520不敢说出口?教你硬核表白

临近5月20的时候,想起之前做过一个用程序做出一个爱心的图案,便突发奇想给它升级一下

爱心1.0

爱心2.0
在这里插入图片描述

原理

爱心1.0的原理 是根据公式 (x ^ 2 + y ^ 2 - 1) ^ 3 - x ^ 2 * y ^ 3 = 0画出来的。使用双重循环就可以实现,然后判断最后的结果和0的关系。如果结果等于0则该坐标就在爱心上,如果大于0则在爱心外,小于0则在爱心内。那么就可以画出不同样子的爱心

  • 画边框、爱心留白
    在这里插入图片描述
  • 只画爱心内部
    在这里插入图片描述

如果只是这样的话,那和爱心1.0没有多大区别,所以我打算让它动起来,画出不同的颜色

实现要点

  • 怎么画出图形: 使用java的图形化界面,通过画笔画很多连续的矩形。使用到的是重写的public void paintComponent(Graphics g)方法。 要使该方法能够使用,就要在一个JPanel类中重写,并且把这个类添加到一个JFrame类中,之后在里面使用g.fillRect()方法画矩形就好了
  • 怎么修改画出矩形的颜色: 在使用g.fillRect()方法画图之前可以先通过g.setColor()方法设置颜色,在此方法中要放入一个Color对象作为参数,那么就可以通过RGB三原色设置要画的颜色,之后不断改变RBG数值就可以达到不断改变颜色的效果
  • 怎么画爱心: 根据上面说的公式来判断当前坐标的值是否在爱心外或爱心内来判断该点是否要画,如果要画的话就调用repaint()方法,会直接执行paintComponent(Graphics g)方法
  • 怎么实现动画效果: 最开始使用的是时间事件,每隔一定时间就画一行。看似很理想但是会有一个问题,如果画一行的操作是连续的,那么在这一行中是需要循环判断每一个点是否要画,如果要画就使用repaint(),否则就继续循环。结果画出来的只会有一个点。原因是Java有一个GUI (AWT) Thread来负责GUI事件的分发,这个线程一般是和主程序的线程是绑定的,如果当前线程休眠那么画图的这个事件也会丢失。如果循环调用repaint()的话就会合并为最后一个repaint(),所以永远只会画出一个点。那么就需要使用到多线程,为面板创建一个新的线程,每次调用repaint()时就让面板线程休眠一段时间,那么就会轮到GUI (AWT) Thread,就可以执行repaint(),从而就不会丢失事件。既然使用了线程休眠,那么就不需要再额外增加一个时间事件了,只需要通过线程休眠达到时间间隔的效果就可以了

完整代码

爱心1.0

#include<stdio.h>
#include<iostream>
using namespace std ;
int main() {
     for(float y = 1.5f; y >= -1.5f; y -= 0.1f){
        for(float x = -1.5f; x <= 1.5f; x += 0.05f){
            float a = x*x + y*y - 1;
            if(a*a*a - x*x*y*y*y <= 0.0f)
                printf("*");
            else
                printf(" ");
        }
        printf("\n");
    }
    return 0 ;
}

爱心2.0

public class Main {
    public static void main(String[] args) {
	    Window window = new Window() ;
    }
}


public class Window extends JFrame {
    Panel panel;

    public Window() {
        panel = new Panel() ;
        add(panel) ;    //只有将画板添加到窗口才能画图
        panel.setBounds(0, 0, 860, 750);
        Thread t = new Thread(panel) ;      //要使用线程才能实现动画效果
        t.start();
        setLayout(null);        //画板要能调节大小,则窗口不能使用默认排版方式
        setBounds(400, 50, 860, 750);
        setVisible(true);
        validate();
        setDefaultCloseOperation(Window.EXIT_ON_CLOSE);
    }
}


public class Panel extends JPanel implements Runnable {
    int R ;     //三原色red
    int G ;		//三原色green
    int B ;		//三原色blue
    int tx;     //画图坐标
    int ty ;	//画图坐标
    float y ;   //循环画图行数
    boolean flag ;      //画边框爱心还是实体爱心
    boolean increaseOrDecrease = false ;		//G、B增大或减小
    boolean backRed = false ;					//从黑色变回红色
    File file = new File("my lonely soul.wav") ;	//背景音乐
    URL url = null;
    URI uri = null ;
    AudioClip clip = null;	
    public Panel(){
        try {
            uri=file.toURI();
            url = uri.toURL() ;
        }
        catch (MalformedURLException e1) {}
        clip= Applet.newAudioClip(url);
        clip.loop();	//播放背景音乐
        R = 255 ;       //初始三原色为红色
        G = 0 ;
        B = 0 ;
        y = 1.5f ;      //初始循环位置
        tx = 30 ;       //每一行画图的位置
        ty = 10 ;       //初始画图的列的位置
        flag = false ;  //最开始画边框爱心
        setVisible(true);
    }
    public void paintComponent(Graphics g) {
        if(!flag) {     //画边框
            Color color = new Color(R,G,B) ;    //根据当前的RGB画相应颜色的图形
            g.setColor(color);
            g.fillRect(tx, ty, 13, 13);
            g.fillRect(tx, ty+11, 13, 10);  //多往下画一点减小每行的间隔
        }
        else {          //画实体爱心
            super.paintComponent(g);		//将之前所有的边框先清空
            Color color = new Color(206, 40, 34) ;	//最终的颜色
            g.setColor(color);
            for(float i = 1.5f; i >= -1.5f; i -= 0.1f){
                for(float x = -1.5f; x <= 1.5f; x += 0.05f){
                    float a = x*x + i*i - 1;
                    if(a*a*a - x*x*i*i*i <= 0.0f) {
                        g.fillRect(tx, ty, 13, 13);
                        g.fillRect(tx, ty+11, 13, 16);
                    }
                    tx += 13 ;
                }
                tx = 30 ;
                ty += 25 ;
            }
        }
    }
    public void run() {
        while (true) {
            try {
                Thread.sleep(70);
            }
            catch(Exception e) {}
            if(y>=-1.2f && !flag) {     //画边框爱心
                //根据公式(x^2+y^2-1)^3-x^2y^3=0画
                for(float x = -1.5f; x <= 1.5f; x += 0.05f) {
                    float a = x*x + y*y - 1;
                    if(a*a*a-x*x*y*y*y>0.0f && y!=1.5f) {   //大于0是爱心外侧,小于0是内侧
                        this.repaint();
                        try {            //要把线程休眠一会才会轮到repaint()的线程
                            Thread.sleep(4);  //可自定义事件,事件越小画的速度越快但太小的话可能会漏画
                        }
                        catch(InterruptedException e){}
                    }
                        tx += 13 ;  //每行往右走一点
                }
                tx = 30 ;   //画完一行后要回到最左边
                ty += 25 ;  //画下一行
                y -= 0.1f ; //循环次数减少
            }
            else {         //画完一个边框后判断继续画下一个边框或画实体
            	if(!increaseOrDecrease) {	//G、B数值增加
                    G += 4 ;
                    B += 4 ;
            	}
            	else {						//G、B数值减小
                    G -= 4 ;
                    B -= 4 ;
            	}
        		if(G >= 70) 				//G、B数值在0~70范围内
            		increaseOrDecrease = true ;
            	if(!backRed) 				//红变黑
            		R -= 10 ;   
            	else 						//黑变红
            		R += 10 ;
                if(R <= 0) {				//到黑色了准备变回红色
                	R = 1 ;					//重新初始化R
                	backRed = true ;
                }
                if(G<=0 && B<=0) {
                	G = 1 ;
                	B = 1 ;
                	backRed = true ;
                }
                if(R < 255)     //R没有再次变回255说明还在画边框
                    y = 1.5f ;
                else {          //画实体爱心
                    flag = true ;
                    try {
                        Thread.sleep(500);
                    }
                    catch(Exception e) {}
                    this.repaint();
                }
                tx = 30 ;   //每画完一次都要重新初始化画图坐标
                ty = 10 ;
            }
        }
    }
}

总结

  • 这是继圣诞树之后第二个突发奇想做的东西,还是挺有意思的,也能学到一些新的东西,比如多线程实现循环repaint()。以后还会有更多突发奇想的东西做出来吧
  • 做出来的只是一个模板,如果对你有用,完全可以在这个基础上实现更多有趣浪漫的操作。不准觉得这个表白程序太直男!把“硬核”打在公屏上!

如果无聊的话可以点这里听着歌看着爱心颜色慢慢变化,发呆就好了

展开阅读全文

Python数据分析与挖掘

01-08
92讲视频课+16大项目实战+源码+¥800元课程礼包+讲师社群1V1答疑+社群闭门分享会=99元   为什么学习数据分析?       人工智能、大数据时代有什么技能是可以运用在各种行业的?数据分析就是。       从海量数据中获得别人看不见的信息,创业者可以通过数据分析来优化产品,营销人员可以通过数据分析改进营销策略,产品经理可以通过数据分析洞察用户习惯,金融从业者可以通过数据分析规避投资风险,程序员可以通过数据分析进一步挖掘出数据价值,它和编程一样,本质上也是一个工具,通过数据来对现实事物进行分析和识别的能力。不管你从事什么行业,掌握了数据分析能力,往往在其岗位上更有竞争力。    本课程共包含五大模块: 一、先导篇: 通过分析数据分析师的一天,让学员了解全面了解成为一个数据分析师的所有必修功法,对数据分析师不在迷惑。   二、基础篇: 围绕Python基础语法介绍、数据预处理、数据可视化以及数据分析与挖掘......这些核心技能模块展开,帮助你快速而全面的掌握和了解成为一个数据分析师的所有必修功法。   三、数据采集篇: 通过网络爬虫实战解决数据分析的必经之路:数据从何来的问题,讲解常见的爬虫套路并利用三大实战帮助学员扎实数据采集能力,避免没有数据可分析的尴尬。   四、分析工具篇: 讲解数据分析避不开的科学计算库Numpy、数据分析工具Pandas及常见可视化工具Matplotlib。   五、算法篇: 算法是数据分析的精华,课程精选10大算法,包括分类、聚类、预测3大类型,每个算法都从原理和案例两个角度学习,让你不仅能用起来,了解原理,还能知道为什么这么做。
©️2020 CSDN 皮肤主题: 黑客帝国 设计师: 上身试试 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值