java画图板之平面山水画(一):https://blog.csdn.net/qq_43348021/article/details/104346805
上次的博客中已经将山脉的轮廓画出来了,这次我们对它进行修饰。

填充

刚开始,我以为将区域填充需要将其中每个点都画到,其实不然。我们知道画出的山脉轮廓其实是有若干个点连线组成的,我们只需要从这些点开始,垂直向下划线即可,当点的数量足够多的时候,显示的就是全部被填充的情况。

    public void showmt(double startx, double starty, double endx, double endy, Color mtcolor, double range, double timescounter) {double midx, midy;//计算中点坐标midx = (startx + endx) / 2;midy = (starty + endy) / 2 + (Math.random() * 2 - 1) * range;if (timescounter++ == times) {//画山脉轮廓g.drawLine((int) startx, (int) starty, (int) midx, (int) midy);g.drawLine((int) midx, (int) midy, (int) endx, (int) endy);//填充山脉g.setColor(mtcolor);g.drawLine((int) midx, (int) midy, (int) midx, (int) 600/*画布底部*/);} else {//随着相邻两个点的横坐标距离减少,纵坐标随机起伏范围也要减小range *= rate;//递归showmt(startx, starty, midx, midy, mtcolor, range, timescounter);showmt(midx, midy, endx, endy, mtcolor, range, timescounter);}}
  • 这是递归次数(times)为10时画出的效果:

  • 这是递归次数(times)为11时画出的效果:

群山

只有一座山肯定是不够的,我们用循环来画多做山脉,同时对远近山脉的高低、颜色进行调整,这部分放在监听器中。

   for (int i = 0; i < 4; i++) {int distance = 100;// 每座山脉间距离mountain mountain = new mountain();mountain.setGraphics(bufferg);// 先在缓存中绘制Color mtcolor = new Color(i * 50, i * 50, i * 50);// 设置每座山脉颜色mountain.showmt(0, 50 + i * distance, 800, 50 + i * distance, mtcolor, 100, 1);// showmt(double startx, double starty, double endx, double endy, Color mtcolor, double range, double timescounter)}

提速

实际运行过上面的代码就会知道,递归11次会使得画出图像需要1秒左右的过程,有没有什么办法能使图像在运行的瞬间就显示出来呢?这就需要用到计算机的缓存了,我们可以事先在缓存中画出图形并保存,然后将缓存中的图像显示出来(CPU与缓存间传输信息的速度要大于CPU与输入输出设备的)。
    这样做还有一个好处,由于我们的图像绘制时使用了随机函数,导致我们每次调用函数都会改变图像,当其他构件发生变化时,山脉的图像也在跟着变化。运用缓存后,当其他构件发生变化影响到山脉的图像时,我们只需要将缓存中保存的图片重新显示出来就行了,而不需要重新绘制。
    java提供了BufferedImage类供我们使用。

    //绘制山脉// 设置缓存BufferedImage buffer = new BufferedImage(800, 400, BufferedImage.TYPE_INT_RGB);// 设置缓存画布Graphics bufferg = buffer.getGraphics();// 设置画布背景颜色Color bufferbgcolor = new Color(255,255,255);bufferg.setColor(bufferbgcolor);bufferg.fillRect(0, 0, 800, 400);// 在缓存中绘制山脉for (int i = 0; i < 4; i++) {int distance = 100;// 每座山脉间距离mountain mountain = new mountain();mountain.setGraphics(bufferg);// 先在缓存中绘制Color mtcolor = new Color(i * 50, i * 50, i * 50);// 设置每座山脉颜色mountain.showmt(0, 50 + i * distance, 800, 50 + i * distance, mtcolor, 100, 1);// showmt(double startx, double starty, double endx, double endy, Color mtcolor, double range, double timescounter)}

太阳

有了山脉,我总觉得还少了点什么,为了让图片更加有意境,我加入了太阳这个元素。但是仅仅是画一个太阳很死板,我想让它动起来。

  • 首先,先确定太阳的画法,使用fillOval()函数,需要注意的是里面的参数是圆外接矩形左上角的点的坐标。在画下一个太阳前,需要将前一个太阳擦除,准确的说是覆盖:用与背景相同的颜色,在前一个太阳处画圆。
  • 然后,就是太阳的轨迹:

    我们将轨迹设置为以O为圆心,OA为半径的圆弧,A点的位置可以修改。接着我们设定太阳移动的移动速度sunspeed = 0.5 弧度/次,运动开始相对时间starttime = 35(因为从0开始可能会被挡住,每次运行完+1),我们可以通过三角函数,算出在t时刻P点的坐标(OB - OA* Math.cos(Math.asin(AB/OA) + starttime * sunspeed * PI / 180),600 - 500 * Math.sin(Math.asin(AB/OA) + starttime * sunspeed * PI / 180))
public void showsun() {// 绘制太阳// 清除上一个太阳Color bgcolor = new Color(255, 128, 0);g.setColor(bgcolor);g.fillOval((int) (sunx - sunr), (int) (suny - sunr), (int) sunr, (int) sunr);// 计数starttime++;// 计算新太阳的位置sunx = 400 - 500 * Math.cos(Math.asin(0.6) + starttime * sunspeed * PI / 180);suny = 600 - 500 * Math.sin(Math.asin(0.6) + starttime * sunspeed * PI / 180);// 画出太阳Color suncolor = new Color(255, 0, 0);g.setColor(suncolor);g.fillOval((int) (sunx - sunr), (int) (suny - sunr), (int) sunr, (int) sunr);// 在主画布上画出缓存画布g.drawImage(buffer, 0, 200, null);}
  • 最后,我们加入线程休眠,让这段程序每100ms运行一次
    while (sun.sunx <= 700) {// 设置截止条件// 计时try {Thread.sleep(100); // 设置精度} catch (InterruptedException ex) {Logger.getLogger(sun.class.getName()).log(Level.SEVERE, null, ex);}// 画出太阳和山脉sun.showsun();}

但是,这里面还有一个问题,就是太阳没有运行完,程序就不能执行其他的任务,这需要用到多线程和高并发的相关知识了,我会将这一部分放到聊天室搭建的博客中。

运行结果

结果是一个动图,但是我不知道怎么做gif。虽然可能没有想象中的美观但是关键是技术与思想的掌握和今后的运用。

附录(源代码)

background类

package plain;import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import javax.swing.JButton;
import javax.swing.JFrame;public class background {public void showbg() {JFrame bg = new JFrame();// 设置窗体基本属性bg.setTitle("地球平原");bg.setSize(800, 600);bg.setLocationRelativeTo(null);// 窗体关闭时结束程序bg.setDefaultCloseOperation(bg.EXIT_ON_CLOSE);// 设置背景颜色,直接设置没有用,需要用Panel组件Color bgcolor = new Color(255, 128, 0);//Color bgcolor = new Color(255, 255, 255);bg.getContentPane().setBackground(bgcolor);// 设置布局,放在可见前才显示FlowLayout flow = new FlowLayout();bg.setLayout(flow);// 设置可见,并获取画布对象bg.setVisible(true);Graphics g = bg.getGraphics();// 设置鼠标监听器MouseListener mouselistener = new MouseListener();bg.addMouseListener(mouselistener);mouselistener.setGraphics(g);}public static void main(String args[]) {background bg = new background();bg.showbg();}
}

MouseListener类

package plain;import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.logging.Level;
import java.util.logging.Logger;import javax.swing.JFrame;import three_dimention.Pad;public class MouseListener implements java.awt.event.MouseListener, ActionListener {Graphics g;public void setGraphics(Graphics g) {this.g = g;}public void mouseClicked(MouseEvent e) {//绘制山脉// 设置缓存BufferedImage buffer = new BufferedImage(800, 400, BufferedImage.TYPE_INT_RGB);// 设置缓存画布Graphics bufferg = buffer.getGraphics();// 设置画布背景颜色Color bufferbgcolor = new Color(255, 128, 0);bufferg.setColor(bufferbgcolor);bufferg.fillRect(0, 0, 800, 400);// 在缓存中绘制山脉for (int i = 0; i < 4; i++) {int distance = 100;// 每座山脉间距离mountain mountain = new mountain();mountain.setGraphics(bufferg);// 先在缓存中绘制Color mtcolor = new Color(i * 50, i * 50, i * 50);// 设置每座山脉颜色mountain.showmt(0, 50 + i * distance, 800, 50 + i * distance, mtcolor, 100, 1);// showmt(double startx, double starty, double endx, double endy, Color mtcolor, double range, double timescounter)}//绘制太阳sun sun = new sun();sun.setGraphics(g);sun.setBuffer(buffer);while (sun.sunx <= 700) {// 设置截止条件// 计时try {Thread.sleep(100); // 设置精度} catch (InterruptedException ex) {Logger.getLogger(sun.class.getName()).log(Level.SEVERE, null, ex);}// 画出太阳和山脉sun.showsun();}}public void mousePressed(MouseEvent e) {}public void mouseReleased(MouseEvent e) {}public void mouseEntered(MouseEvent e) {}public void mouseExited(MouseEvent e) {}public void actionPerformed(ActionEvent e) {}}

mountain类

package plain;import java.awt.Color;
import java.awt.Graphics;public class mountain {double rate = 0.5, times = 11;//times>10Boolean whe_left = true;Graphics g;public void setGraphics(Graphics bufferg) {this.g = bufferg;}public void showmt(double startx, double starty, double endx, double endy, Color mtcolor, double range, double timescounter) {double midx, midy;//计算中点坐标midx = (startx + endx) / 2;midy = (starty + endy) / 2 + (Math.random() * 2 - 1) * range;if (timescounter++ == times) {//画山脉轮廓g.drawLine((int) startx, (int) starty, (int) midx, (int) midy);g.drawLine((int) midx, (int) midy, (int) endx, (int) endy);//填充山脉g.setColor(mtcolor);g.drawLine((int) midx, (int) midy, (int) midx, (int) 600/*画布底部*/);} else {//随着相邻两个点的横坐标距离减少,纵坐标随机起伏范围也要减小range *= rate;//递归showmt(startx, starty, midx, midy, mtcolor, range, timescounter);showmt(midx, midy, endx, endy, mtcolor, range, timescounter);}}
}

sun类

package plain;import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.logging.Level;
import java.util.logging.Logger;import javax.swing.JFrame;public class sun {Graphics g;// 主画布double sunspeed = 0.5;// 太阳移动速度double PI = 3.14;// πdouble sunx = 0, suny = 300, sunr = 80;// 起始位置、太阳直径double starttime = 35;// 运动开始的时间BufferedImage buffer;public void setGraphics(Graphics g) {this.g = g;}public void setBuffer(BufferedImage buffer) {this.buffer = buffer;}public void showsun() {// 绘制太阳// 清除上一个太阳Color bgcolor = new Color(255, 128, 0);g.setColor(bgcolor);g.fillOval((int) (sunx - sunr), (int) (suny - sunr), (int) sunr, (int) sunr);// 计数starttime++;// 计算新太阳的位置sunx = 400 - 500 * Math.cos(Math.asin(0.6) + starttime * sunspeed * PI / 180);suny = 600 - 500 * Math.sin(Math.asin(0.6) + starttime * sunspeed * PI / 180);// 画出太阳Color suncolor = new Color(255, 0, 0);g.setColor(suncolor);g.fillOval((int) (sunx - sunr), (int) (suny - sunr), (int) sunr, (int) sunr);// 在主画布上画出缓存画布g.drawImage(buffer, 0, 200, null);}
}

java画图板之平面山水画(二)相关推荐

  1. java画图板之平面山水画(一)

    前期准备 在上次的博客中,我们已经用java了解并制作了画图板,可以在上面添加绘制椭圆.曲线.填充.改变颜色等功能,在之后的版本中会进行修改.     今天要做的是通过递归的方式绘制山脉. 具体步骤 ...

  2. JAVA画图板01 —— 窗体的实现

    画图板 界面开发: 创建窗体对象 完善界面 个人将自制的JAVA画图板分为了三个模块,分别是界面.监听器以及画笔,这一章来介绍界面的相关代码. 界面开发: 创建窗体对象 首先需要创建一个窗体对象.JF ...

  3. 一个Java画图板程序的设计

    本文讲述一个画图板应用程序的设计,屏幕抓图如下.这篇文章带有三个附件,其中两个jar文件都是j2sdk1.4.2_08编译打包,包含源代码,可执行,如下表: 附件名称及链接 详情 jDraw_basi ...

  4. java画图板代码_java学习小总结——画图板制做(附代码)

    学习java这门编程语言也有一个多月了.~若是能用本身学的编程语言去开发一些小程序软件能够说是本身一直求之不得吧!.模仿XP的画图板的开发则是学java来最先作的一个小软件.也是把以前学到的不少知识得 ...

  5. Java 画图板用随机数搞“混沌游戏”

    今晚做了这样的一个任务:用随机数在画图板里面生成四个点,然后选出其中的三个点组成一个三角形,把三角形的三个顶点标为1.2.3,另一个点标为4,把4点随机与1.2.3三个点中一个点进行连接,取连线的中点 ...

  6. Java画图板界面上的添加

    步骤 1.创建类来实现接口(动作监听器和鼠标监听器) 2.在按钮上添加动作监听器,通过e.getActioncommand(),来得到按钮上的字,通过button =(JButton)e.getAct ...

  7. Java画图板的简单实现。(重绘,多边形,曲线画笔,画图片)

    思路: ①画图板的界面 ②创建监听器类 ③给按钮加上鼠标监听 ③画图版的重绘 第一部分:界面类 ①画图板的界面 ③给按钮加上鼠标监听 public class SampleDraw extends J ...

  8. java 画图板源代码_非常值得学习的java 绘图板源代码

    package minidrawpad; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; impor ...

  9. java 画图板 锯齿_java绘画中的锯齿问题

    java给图中的锯齿问题也称作呈现兼容性问题 JDK(tm)1.1呈现模型是基于像素给的模型,该模型的坐标无限细分,且位于像素之间.使用一个一像素宽的画笔执行绘制操作,填充路径锚点向下和向右的像素.J ...

最新文章

  1. 【Qt】QtCreator中的单例编程(以ActionManager为例)
  2. [笔记].关于Nios II的数据类型的一点想法
  3. 高通CVPR神研究:视频处理计算量降低78%,教卷积层自己“挑像素”,卡成PPT的视频纵享丝滑...
  4. c语言小游戏贪吃神,[原创]自己编的一个贪吃蛇小游戏
  5. React学习:ref调用、组件封装调用-学习笔记
  6. 字符串替换(C++)
  7. 【FFMPEG系列】之查看FFMPEG版本号
  8. Openstack api security testing tools
  9. 服务器延迟和时间偏移怎么设置,针对大量时间偏移配置 W32Time - Windows Server | Microsoft Docs...
  10. Appfuse实践(一)——配置安装 转自http://www.donews.net/skyhero/archive/2004/12/17/205662.aspx...
  11. java继承动物类_Java之继承
  12. 保利威视后台录屏类视频清晰度优化说明
  13. Android面试知识点复习,那些不为人知的秘密
  14. 宝存科技推出全球首款大量商用级别的高性能Open-Channel SSD
  15. 【问链财经-区块链基础知识系列】 第四十五课 一文读懂保理业务的操作流程
  16. Unity3D iPhone开发入门 (转)iPhoneSettings.
  17. JVM 内存分哪几个区,每个区的作用是什么
  18. FPGA第一天的学习-LED流水灯
  19. long与int转换线上问题解决(必看)
  20. 「技术分享」工业触摸屏之触摸屏分类(连载)

热门文章

  1. java 多线程分段等待执行完成状况,循环屏障CyclicBarrier | Java工具类
  2. sql server获取库名,表名
  3. dashboard 镜像源_使用 tekton 做 CI/CD
  4. YOLO系列之yolo v1
  5. C++中BitBlt的使用方法详解
  6. sklearn.datasets数据集和下载网站
  7. VirtualBox安装Centos图解教程
  8. POI读取word里面的表格并处理数据
  9. 关于HTTP请求 415错误
  10. error C2872: 'ULONG_PTR' : ambiguous symbol