今天学习了怎么做一个简单的画图板。
由于尝试的过程没有截图,只有最终的结果,所以中间过程的尝试截图就没有了。
首先把参考代码看懂,才能自己做。
“
Android中的触摸事件可是大头中的大头, 其中onTouch事件是在view中定义的,所以想要实现绘图,自己要定义一个绘图组件,这个组件一定要继承view类,同时覆盖重写view中的onDraw方法。 Android画图最基本的三个对象(Color,Paint,Canvas) 三个类都存放在 android.graphics包下 1) Color :颜色对象,相当于现实生活中的 ‘调料’ 2) Paint : 画笔对象,相当于现实生活中画图用的 ‘笔’————主要的还是对‘画笔’进行设置 3) Canvas : 画布对象,相当于现实生活中画图用的 ‘纸 或 布’
”
根据指导,新建一个java类,写上代码
public class paintview extends View{ private List<Point> pointall=new ArrayList<Point>(); public paintview(Context context, AttributeSet attrs) { super(context, attrs); super.setBackgroundColor(Color.WHITE); super.setOnTouchListener(new Touch()); } private class Touch implements OnTouchListener{ @Override public boolean onTouch(View v, MotionEvent e) { // TODO Auto-generated method stub Point p=new Point((int)e.getX(),(int)e.getY()); if(e.getAction()==e.ACTION_DOWN){ //当按下 pointall=new ArrayList<Point>(); pointall.add(p); } else if(e.getAction()==e.ACTION_UP){//当抬起 pointall.add(p); paintview.this.postInvalidate(); //重绘 } else if(e.getAction()==e.ACTION_MOVE){ pointall.add(p); //移动时候 paintview.this.postInvalidate(); //重绘 } return true; } } protected void onDraw(Canvas canvas){ Paint p=new Paint(); //定义画笔 p.setColor(Color.RED); //定义颜色 if(pointall.size()>1){ Iterator<Point> iter=pointall.iterator();// 现在有坐标点保存的时候可以开始进行绘图 Point first=null; Point last=null; while(iter.hasNext()){ if(first==null){ first=(Point)iter.next(); } else{ if(last!=null){ first=last; //将下一个坐标点赋给上面的 } last=(Point)iter.next(); //不停下指 canvas.drawLine(first.x, first.y, last.x, last.y,p); } } } } }
之后配置好activity_main.xml
加上这段:
<com.example.paint.paintview
android:id="@+id/paintview"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
现在,参考代码已经全部导入我们的工程了,运行一下看看效果。
试试结果,能画出一条一个像素宽度的线条,并且只有红色,而且再次点击绘制的时候原来线条消失了。
所以尝试对其进行改进,试想加入画笔颜色,画笔粗细。最重要的,可以画多条线。
首先分析代码,线条的绘制方式。其使用迭代器,循环遍历集合并根据相邻点的位置进行连线,达到绘图的效果。
但是发现在按下事件中:
if(e.getAction()==e.ACTION_DOWN){ //当按下
pointall=new ArrayList<Point>();
pointall.add(p);
}
每一次迭代器都被重置了,导致前面的信息丢失。为了解决这个问题,可以设置参数进行判断,当只有在第一次画的时候,重置迭代器,之后的绘制,不会重置迭代器:
if(e.getAction()==e.ACTION_DOWN){ //当按下
if(f==false){
f=true;
pointall=new ArrayList<Point>();
p=new Point(0,-2001);
}
尝试一下。好的,现在我们可以一直绘制了。但是也有问题。
绘制的线条并不是分开的,新线条的起点和旧线条的终点连接在了一起?
问题就在与渲染方式,其遍历集合,把前一个点和后一个点进行连接,而新线条的起点就是和旧线条的终点相邻。怎么办呢?
其实只要进行判断,当遇到终点或起点的时候,不要把他们连接就可以了。
但是如何在集合里面保存起点终点信息?集合里面只有 点 ,要保存起点终点信息,也只能通过点进行保存。
那么可以把起点终点的坐标设置为一个特殊值,当遇到的时候,就知道他们是起点和终点了。
if(e.getAction()==e.ACTION_DOWN){ //当按下
if(f==false){
f=true;
pointall=new ArrayList<Point>();
}
p=new Point(0,0);
pointall.add(p);
起点坐标被强制设置为0。同样的,对终点进行标记。
然后在渲染的方法的前面加上:
if(first.x==0||last.x==0)continue;
canvas.drawLine(first.x, first.y, last.x, last.y,p);
这样,如果遇到起点终点,就会跳过,不渲染。
尝试一下!好的,成功把线条断开了!
颜色怎么办?首先在面板设置组件,点击的时候获取信息,判断选择了什么颜色。
这个组件随便什么都可以,我使用的是Spinner。怎么获取信息并且传入我们之前新建的java类里面,这里就不多说了。
好,现在我们可以从面板中获取颜色信息了,但是怎么改变线条颜色呢?
由于我们只有一个迭代器,需要保存不同线条的信息,同理,我们也只能使用点坐标进行信息保存。仔细看上面的代码,发现我只用了起点终点的x坐标来判断是否渲染,现在,我们把它的y坐标利用上,用它来保存颜色信息!
if(e.getAction()==e.ACTION_DOWN){ //当按下 if(f==false){ f=true; pointall=new ArrayList<Point>(); } p=new Point(0,color1); pointall.add(p); }
参数color1是一个整数,我用来保存颜色信息,需要自己建立面板传入的参数和颜色代表的整数之间的对应!
并且在绘制之前,进行判断当前线条的颜色。
if(first.y==1000)p.setColor(Color.BLACK);//黑 else if(first.y==-1001)p.setColor(Color.RED);//红 else if(first.y==-1002)p.setColor(Color.rgb(255, 150, 0));//橙 else if(first.y==-1003)p.setColor(Color.YELLOW);//黄 else if(first.y==-1004)p.setColor(Color.GREEN);//绿 else if(first.y==-1005)p.setColor(Color.CYAN);//青 else if(first.y==-1006)p.setColor(Color.BLUE);//蓝 else if(first.y==-1007)p.setColor(Color.MAGENTA);//紫 else if(first.y==-1008)p.setColor(Color.GRAY);//灰 //断线跳过 if(first.x==0||last.x==0)continue; canvas.drawLine(first.x, first.y, last.x, last.y,p);
尝试一下!成功了,我们可以切换不同颜色了!而且不同的线条也显示出不同的颜色了!
接下来是更换线条粗细。使用同样的思想,用点来保存信息,但是,起点终点的x和y坐标都被我们利用完了,怎么办?很简单!它们只是记录信息的点,不要要参加绘制,所以可以再来一个点进行记录粗细的信息。
if(e.getAction()==e.ACTION_DOWN){ //当按下 if(f==false){ f=true; pointall=new ArrayList<Point>(); p=new Point(0,-2001); pointall.add(p); } p=new Point(0,linewight); pointall.add(p); p=new Point(0,color1); pointall.add(p); }
linewight这个参数被我用来存放粗细的信息,同样的要自己建立面板传入的参数和信息的整数对应关系。
由于是携带信息的点,所以干脆就和起点放在一起,“两个起点”。
但是!这里要注意一下,我们要给整个集合的第一个点设置一个粗细的参数,不然的话,后面改变线条粗细的时候,会因为第一条线没有起点携带了粗细信息而会跟着被改变
(其实读者可以自己试一试,如果把我上面代码的p=new Point(0,-2001);pointall.add(p);给删掉,会是什么效果)。
接下来,渲染的地方就最终变成这个样子了:
last=(Point)iter.next(); //不停下指 //判断线条颜色 if(first.y==1000)p.setColor(Color.BLACK);//黑 else if(first.y==-1001)p.setColor(Color.RED);//红 else if(first.y==-1002)p.setColor(Color.rgb(255, 150, 0));//橙 else if(first.y==-1003)p.setColor(Color.YELLOW);//黄 else if(first.y==-1004)p.setColor(Color.GREEN);//绿 else if(first.y==-1005)p.setColor(Color.CYAN);//青 else if(first.y==-1006)p.setColor(Color.BLUE);//蓝 else if(first.y==-1007)p.setColor(Color.MAGENTA);//紫 else if(first.y==-1008)p.setColor(Color.GRAY);//灰 //判断线条粗细 if(first.y==-2001)p.setStrokeWidth(1); else if(first.y==-2002)p.setStrokeWidth(2); else if(first.y==-2003)p.setStrokeWidth(3); else if(first.y==-2004)p.setStrokeWidth(4); else if(first.y==-2006)p.setStrokeWidth(6); else if(first.y==-2008)p.setStrokeWidth(8); //断线跳过 if(first.x==0||last.x==0)continue; canvas.drawLine(first.x, first.y, last.x, last.y,p);
我选用的选择线条粗细的组件是图片按钮。
好的,现在我今天的最终版也就做出来了,我们来试试效果。
记住,目标:绘制多条线,不同颜色的线,不同粗细的线!
最后的最后,给上代码:
Main.Activity.java: public class MainActivity extends Activity { private ImageButton px01; private ImageButton px02; private ImageButton px03; private ImageButton px04; private ImageButton px06; private ImageButton px08; private Spinner color; private String color1; private Spinner lwight; private String lwight1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); px01=(ImageButton)findViewById(R.id.imageButton1); px01.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { paintview.linewight=-2001; } }); px02=(ImageButton)findViewById(R.id.imageButton2); px02.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { paintview.linewight=-2002; } }); px03=(ImageButton)findViewById(R.id.imageButton3); px03.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { paintview.linewight=-2003; } }); px04=(ImageButton)findViewById(R.id.imageButton4); px04.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { paintview.linewight=-2004; } }); px06=(ImageButton)findViewById(R.id.imageButton5); px06.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { paintview.linewight=-2006; } }); px08=(ImageButton)findViewById(R.id.imageButton6); px08.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { paintview.linewight=-2008; } }); color=(Spinner)findViewById(R.id.colortext); color.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { // TODO Auto-generated method stub color1= (String) color.getSelectedItem(); if(color1.equals("红色")) paintview.color1=-1001; else if(color1.equals("橙色")) paintview.color1=-1002; else if(color1.equals("黄色")) paintview.color1=-1003; else if(color1.equals("绿色")) paintview.color1=-1004; else if(color1.equals("青色")) paintview.color1=-1005; else if(color1.equals("蓝色")) paintview.color1=-1006; else if(color1.equals("紫色")) paintview.color1=-1007; else if(color1.equals("灰色")) paintview.color1=-1008; else paintview.color1=1000; } @Override public void onNothingSelected(AdapterView<?> parent) {} }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }
paintview.java: public class paintview extends View{ static int color1; static int linewight; static int linewight2; private List<Point> pointall=new ArrayList<Point>(); private boolean f=false; public paintview(Context context, AttributeSet attrs) { super(context, attrs); super.setBackgroundColor(Color.rgb(250, 245, 220)); super.setOnTouchListener(new Touch()); } private class Touch implements OnTouchListener{ @Override public boolean onTouch(View v, MotionEvent e) { // TODO Auto-generated method stub Point p=new Point((int)e.getX(),(int)e.getY()); if(e.getAction()==e.ACTION_DOWN){ //当按下 if(f==false){ f=true; pointall=new ArrayList<Point>(); p=new Point(0,-2001); pointall.add(p); } p=new Point(0,linewight); pointall.add(p); p=new Point(0,color1); pointall.add(p); } else if(e.getAction()==e.ACTION_UP){//当抬起 pointall.add(p); paintview.this.postInvalidate(); //重绘 } else if(e.getAction()==e.ACTION_MOVE){ pointall.add(p); //移动时候 paintview.this.postInvalidate(); //重绘 } return true; } } protected void onDraw(Canvas canvas){ Paint p=new Paint(); //定义画笔 p.setColor(Color.BLACK); //定义颜色 if(pointall.size()>1){ Iterator<Point> iter=pointall.iterator();// 现在有坐标点保存的时候可以开始进行绘图 Point first=null; Point last=null; while(iter.hasNext()){ if(first==null){ first=(Point)iter.next(); } else{ if(last!=null){ first=last; //将下一个坐标点赋给上面的 } last=(Point)iter.next(); //不停下指 //判断线条颜色 if(first.y==1000)p.setColor(Color.BLACK);//黑 else if(first.y==-1001)p.setColor(Color.RED);//红 else if(first.y==-1002)p.setColor(Color.rgb(255, 150, 0));//橙 else if(first.y==-1003)p.setColor(Color.YELLOW);//黄 else if(first.y==-1004)p.setColor(Color.GREEN);//绿 else if(first.y==-1005)p.setColor(Color.CYAN);//青 else if(first.y==-1006)p.setColor(Color.BLUE);//蓝 else if(first.y==-1007)p.setColor(Color.MAGENTA);//紫 else if(first.y==-1008)p.setColor(Color.GRAY);//灰 //判断线条粗细 if(first.y==-2001)p.setStrokeWidth(1); else if(first.y==-2002)p.setStrokeWidth(2); else if(first.y==-2003)p.setStrokeWidth(3); else if(first.y==-2004)p.setStrokeWidth(4); else if(first.y==-2006)p.setStrokeWidth(6); else if(first.y==-2008)p.setStrokeWidth(8); //断线跳过 if(first.x==0||last.x==0)continue; canvas.drawLine(first.x, first.y, last.x, last.y,p); } } } } }
activity_main.xml: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <com.example.day2.paintview android:id="@+id/paintview" android:layout_width="465dp" android:layout_height="216dp" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_alignParentRight="true" android:layout_alignParentTop="true" /> <Spinner android:id="@+id/colortext" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_alignTop="@+id/paintview" android:entries="@array/datacolor" /> <ImageButton android:id="@+id/imageButton1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_below="@+id/colortext" android:src="@drawable/onepx" /> <ImageButton android:id="@+id/imageButton2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignRight="@+id/paintview" android:layout_below="@+id/imageButton1" android:src="@drawable/twopx" /> <ImageButton android:id="@+id/imageButton3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignRight="@+id/paintview" android:layout_below="@+id/imageButton2" android:src="@drawable/threepx" /> <ImageButton android:id="@+id/imageButton4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignRight="@+id/paintview" android:layout_below="@+id/imageButton3" android:src="@drawable/fourpx" /> <ImageButton android:id="@+id/imageButton5" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignRight="@+id/paintview" android:layout_below="@+id/imageButton4" android:src="@drawable/sixpx" /> <ImageButton android:id="@+id/imageButton6" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignRight="@+id/paintview" android:layout_below="@+id/imageButton5" android:src="@drawable/eighpx" /> </RelativeLayout>
选择框配置xml <?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="datacolor"> <item>黑色</item> <item>红色</item> <item>橙色</item> <item>黄色</item> <item>绿色</item> <item>青色</item> <item>蓝色</item> <item>紫色</item> <item>灰色</item> </string-array> </resources>
谢谢欣赏,不足之处还请多多指教
反正我做完就这样了,也不打算改,想怎么说就怎么说吧。
相关推荐
内容概要:本文详细介绍了基于MATLAB GUI界面和卷积神经网络(CNN)的模糊车牌识别系统。该系统旨在解决现实中车牌因模糊不清导致识别困难的问题。文中阐述了整个流程的关键步骤,包括图像的模糊还原、灰度化、阈值化、边缘检测、孔洞填充、形态学操作、滤波操作、车牌定位、字符分割以及最终的字符识别。通过使用维纳滤波或最小二乘法约束滤波进行模糊还原,再利用CNN的强大特征提取能力完成字符分类。此外,还特别强调了MATLAB GUI界面的设计,使得用户能直观便捷地操作整个系统。 适合人群:对图像处理和深度学习感兴趣的科研人员、高校学生及从事相关领域的工程师。 使用场景及目标:适用于交通管理、智能停车场等领域,用于提升车牌识别的准确性和效率,特别是在面对模糊车牌时的表现。 其他说明:文中提供了部分关键代码片段作为参考,并对实验结果进行了详细的分析,展示了系统在不同环境下的表现情况及其潜在的应用前景。
嵌入式八股文面试题库资料知识宝典-计算机专业试题.zip
嵌入式八股文面试题库资料知识宝典-C and C++ normal interview_3.zip
内容概要:本文深入探讨了一款额定功率为4kW的开关磁阻电机,详细介绍了其性能参数如额定功率、转速、效率、输出转矩和脉动率等。同时,文章还展示了利用RMxprt、Maxwell 2D和3D模型对该电机进行仿真的方法和技术,通过外电路分析进一步研究其电气性能和动态响应特性。最后,文章提供了基于RMxprt模型的MATLAB仿真代码示例,帮助读者理解电机的工作原理及其性能特点。 适合人群:从事电机设计、工业自动化领域的工程师和技术人员,尤其是对开关磁阻电机感兴趣的科研工作者。 使用场景及目标:适用于希望深入了解开关磁阻电机特性和建模技术的研究人员,在新产品开发或现有产品改进时作为参考资料。 其他说明:文中提供的代码示例仅用于演示目的,实际操作时需根据所用软件的具体情况进行适当修改。
少儿编程scratch项目源代码文件案例素材-剑客冲刺.zip
少儿编程scratch项目源代码文件案例素材-几何冲刺 转瞬即逝.zip
内容概要:本文详细介绍了基于PID控制器的四象限直流电机速度驱动控制系统仿真模型及其永磁直流电机(PMDC)转速控制模型。首先阐述了PID控制器的工作原理,即通过对系统误差的比例、积分和微分运算来调整电机的驱动信号,从而实现转速的精确控制。接着讨论了如何利用PID控制器使有刷PMDC电机在四个象限中精确跟踪参考速度,并展示了仿真模型在应对快速负载扰动时的有效性和稳定性。最后,提供了Simulink仿真模型和详细的Word模型说明文档,帮助读者理解和调整PID控制器参数,以达到最佳控制效果。 适合人群:从事电力电子与电机控制领域的研究人员和技术人员,尤其是对四象限直流电机速度驱动控制系统感兴趣的读者。 使用场景及目标:适用于需要深入了解和掌握四象限直流电机速度驱动控制系统设计与实现的研究人员和技术人员。目标是在实际项目中能够运用PID控制器实现电机转速的精确控制,并提高系统的稳定性和抗干扰能力。 其他说明:文中引用了多篇相关领域的权威文献,确保了理论依据的可靠性和实用性。此外,提供的Simulink模型和Word文档有助于读者更好地理解和实践所介绍的内容。
嵌入式八股文面试题库资料知识宝典-2013年海康威视校园招聘嵌入式开发笔试题.zip
少儿编程scratch项目源代码文件案例素材-驾驶通关.zip
小区开放对周边道路通行能力影响的研究.pdf
内容概要:本文探讨了冷链物流车辆路径优化问题,特别是如何通过NSGA-2遗传算法和软硬时间窗策略来实现高效、环保和高客户满意度的路径规划。文中介绍了冷链物流的特点及其重要性,提出了软时间窗概念,允许一定的配送时间弹性,同时考虑碳排放成本,以达到绿色物流的目的。此外,还讨论了如何将客户满意度作为路径优化的重要评价标准之一。最后,通过一段简化的Python代码展示了遗传算法的应用。 适合人群:从事物流管理、冷链物流运营的专业人士,以及对遗传算法和路径优化感兴趣的科研人员和技术开发者。 使用场景及目标:适用于冷链物流企业,旨在优化配送路线,降低运营成本,减少碳排放,提升客户满意度。目标是帮助企业实现绿色、高效的物流配送系统。 其他说明:文中提供的代码仅为示意,实际应用需根据具体情况调整参数设置和模型构建。
少儿编程scratch项目源代码文件案例素材-恐怖矿井.zip
内容概要:本文详细介绍了基于STM32F030的无刷电机控制方案,重点在于高压FOC(磁场定向控制)技术和滑膜无感FOC的应用。该方案实现了过载、过欠压、堵转等多种保护机制,并提供了完整的源码、原理图和PCB设计。文中展示了关键代码片段,如滑膜观测器和电流环处理,以及保护机制的具体实现方法。此外,还提到了方案的移植要点和实际测试效果,确保系统的稳定性和高效性。 适合人群:嵌入式系统开发者、电机控制系统工程师、硬件工程师。 使用场景及目标:适用于需要高性能无刷电机控制的应用场景,如工业自动化设备、无人机、电动工具等。目标是提供一种成熟的、经过验证的无刷电机控制方案,帮助开发者快速实现并优化电机控制性能。 其他说明:提供的资料包括详细的原理图、PCB设计文件、源码及测试视频,方便开发者进行学习和应用。
基于有限体积法Godunov格式的管道泄漏检测模型研究.pdf
嵌入式八股文面试题库资料知识宝典-CC++笔试题-深圳有为(2019.2.28)1.zip
少儿编程scratch项目源代码文件案例素材-几何冲刺 V1.5.zip
Android系统开发_Linux内核配置_USB-HID设备模拟_通过root权限将Android设备转换为全功能USB键盘的项目实现_该项目需要内核支持configFS文件系统
C# WPF - LiveCharts Project
少儿编程scratch项目源代码文件案例素材-恐怖叉子 动画.zip
嵌入式八股文面试题库资料知识宝典-嵌⼊式⼯程师⾯试⾼频问题.zip