JAVA -生日礼物

Java程序 — 生日礼物(适合初学者)

#最后会生成一个exe文件(毕竟Java需要jre 。。。为了让电脑上没Java环境的人能直接运行程序,毕竟弄个Java环境不是那么简单~)

先看一下效果吧!

具体效果就是程序一开始会有小蛋糕从上面一直往下降,可以说是蛋糕雨吧,然后鼠标在上面点击一次,在点击的地方会随机生成一中玫瑰,总共有五种玫瑰,例如图片右下方排列的那五种
看到中间那个红色线条类的东西了吗,一开始是没有的,在每次点击的时候会随机增加5个线条,当点击的次数多了,线条也会越来越密集,最后呈现的图形就是图片上的啦~这里我用的是那个笛卡尔的爱心曲线,这个是我所能找到的最简单的函数了,虽然看起来不想桃心那样优美,但是 emmm,还是可以看的~
左上角是类似gif的动图,就是会有闪光的,后面会说的~,那个图片左上方是有个显示的名字我遮住了,接下来就是详细的制作过程了,
制作过程过程肯定非常长,不过也没用什么框架,就初学者的水平,希望耐心看完,不懂得可以在下面问哦,一起学习交流~

在这里插入图片描述# 第一步 在网上搜集素材
为了好看美观,我们使用的图片都是png格式的,不过在网上找的图片大部分都是jpg格式,之所以使用png格式的图片主要是png格式的图片背景可以是透明的,不是那种白的。看上面的图片,如果背景是白的就比较尬了,所以自己现在网上找图片,然后用ps(具体教程我先就不说了,网上有很多,可能以后有时间我会补充,emm )
在网上找好图片后,可以先做个背景图,当然可以不做,直接用程序控制图片的大小,位置,但是毕竟背景是不动的(背景其实也可以动起来,可能后面会说关于让背景简单动起来的方法,这里先不说的)
例如我的背景图片如下:
这些都是在ps直接做好的,其他的就在程序中控制位置大小,这样有很多图片就不用再程序中操心了,所以还是直接把背景图做好比较好(我感觉如果用程序控制那几只填写一闪一闪应该会更好看,但我水平不行。。这里就让他们固定在那吧)
在这里插入图片描述
新建一个maven项目,普通项目也行,只不过我们后面要播放音乐需要外部jar包,maven方便一点


/**
 * 我这里就先一部分一部分的介绍,后面都会全部完整的展示的,
 * 如果一下子全部粘贴过来的,看着会很多,很乱,所以先一点一点的介绍,
 * 要用心学哦
 */
@Override
public void paint(Graphics g) {
    super.paint(g);
   
    g.drawImage(img_path,img_size_X,img_size_X,location_x,location_Y,null);//用这个方法在窗口上显示图片
}

/*在主类中建一个内部线程类
*这个内部内 没隔20ms会调用一次repain()方法,这个方法使JFrame自带的方法
*调用这个方法,就相当于调用那个paint()方法,这个repaint()方法是无参的
*如果直接调用那个paint()方法重画,就必须给它一个Graphics对象,所以我们调用repaint()方法,这样就可以规避那个Graphics了,repaint()方法的作用应该就是为了规避那个Graphics吧,(个人见解~)
*
*/
class paintThread extends Thread{
    @Override
    public void run() {
        while (true) {
            repaint();
            try {
                this.sleep(20);
            } catch (InterruptedException e) {
            }
        }
    }
}

显示图片应该都会吧,
这里需要注意那个super.paint(g);这个自动生成的方法是为了在原有的基础上画,如果不删的话,就会出现一串像水流似的蛋糕(就是一个蛋糕显示完后,就一直在那,然后应该可以想象得到),反正我删了,而且后面为了防止屏幕一闪一闪的,我会用到双缓冲,然后好像就不需要那个了,(提醒一下,这里我是用的是继承JFrame而不是Frame,这俩个还是不太一样的)

创建JFrame子类后记得初始化

/**
* 下面这个函数的内容应然是在构造方法中写的,但是为了代码的好看,我直接
* 把他们弄到一个函数中,在构造方法中直接调用就行了
*/
private void init(){
    this.setLocation(300,0);//设置窗口位置,这个可以不管,毕竟窗口可以拖动
    this.setResizable(false);//设置窗口大小不可变,万一她把窗口放大,可就露出白边了 emm
    this.setSize(data.windowSizeX,data.windowSizeY);//设置窗口有大小
    this.setVisible(true);//设置窗口可见,这个必须有!!,不然的话窗口是不可见的,程序运行两秒后直接自己停了
    this.setDefaultCloseOperation(EXIT_ON_CLOSE);//这个是设置点击窗口那个关闭的叉叉程序可以停止,不然你点击那个关闭的叉叉程序没反应   
    new paintThread().start();//开启重画线程;

  }

存数据

程序要用的数据可能会很多例如每个图片的位置,图片的大小,图片的路径等等,这些我们都用一个专门的data类存储,这样不会乱;例如我的data类	
/**
*数据类嘛,全部都是public static 属性的,这样我们就可以直接只用这个类的名字进行调用而不用创建对象了。
*/
package Main.usage;
public class data {
    public static int windowSizeX=1200;
    public static int windowSizeY=800;
    public static int candleSize=30;
    public static double candleSpeed=0.15;
    public static double Love_size=100;
    public static double reseSize=40;
    public static String bgImage= "Main/usage/images/others/birthday.png";
    public static int roseSizeX=200;
    public static int roseSizeY=80;
}

调用图片的方法

package Main.usage;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
public class myImage {
    public static Image getImage(String path)
    {
        BufferedImage image=null;
        URL uri=myImage.class.getClassLoader().getResource(path);
        try {
            image= ImageIO.read(uri);
        } catch (IOException e) {
//            e.printStackTrace();
            System.out.println(path+"图片不存在!");
        }
        return image;
    }
}
上面这个就可以当作工具包类直接复制过去用就行
(最好用我这方法调用图片,因为之后要生成jar再生成exe,会出现路径方面的问题,可能在调试的时候图片显示正常,但是弄成exe就是白板了,因为路径有问题;)

这是我是用的数据类,因为要用到的数据较多,所以还是直接建一个数据类比较好,

/**
*   这个方法是为了随机选择一种蛋糕,的照片,当然随机选择一种玫瑰图片也是一样的。注意看路径 下面有图片,对照着看一下图片路径的设置方法,,
*
*另外,强调一下,图片路径我用的都是/ 这可和\不一样,Java中使用\\必须连着用*两个(转义字符),但是/就一个就行,而且最好用/像下面这样,不要混用,虽然程*序不会报错,而且调试也能正常运行,但是如果像最后生成的exe也能正确显示图片的话,就但用/,我也不知道为什么,我经过不断尝试,最后发现只有这样exe才图片正常显示,emm   为了最后能做出来exe就先按照我这中方法吧 
*emmm...........................................
*/
public static String candleImage()
{
    switch ((int)(Math.random()*8)){
        case 1:return "Main/usage/images/candles/candle1.png";
        case 2:return "Main/usage/images/candles/candle2.png";
        case 3:return "Main/usage/images/candles/candle3.png";
        case 4:return "Main/usage/images/candles/candle4.png";
        case 5:return "Main/usage/images/candles/candle5.png";
        case 6:return "Main/usage/images/candles/candle6.png";
        case 7:return "Main/usage/images/candles/candle7.png";
        default:return "Main/usage/images/candles/candle7.png";
    }
}

在这里插入图片描述
先建一个包,在这个包下面再建一个imgs包,为了存图片,这个包建好后,直接把图片拖进这个包中,(直接拖得话,相当于移动了,原来地方的图片好像就没了,像再留一份图片的话,再拖过去就行了)在这个新建的包内创建我们的获得图片的类,就是上面的那段代码。
(注意这个工具类和图片都在一个包内,类似图片中myImage类和images包都在usage包内)之所以这样,还是因为路径问题,我也不知道为什么,但是只能这样最后生成的exe文件才能无误的显示图片 emm。。
,当然可以大胆尝试一下(坏笑)
#到现在,我们应该有
一个可以显示图片的主类
一个调用图片的工具类(与图片包位置上匹配的)
一个存放图片的包
一个存放数据的data类;

蛋糕雨

上代码

package Main;
import java.awt.*;
import java.util.ArrayList;
/**蛋糕容器
 * 管理所有要画的蛋糕
 *这是个线程类,为了实现蛋糕可以自己下降移动。
 * 
 * 其实也可以不用这个线程,因为主类那里有一个画的线程,
 * 然后让主类中每一次重画调用一次这个类的方法 也能实现蛋糕移动的效果,但是为了使蛋糕移动的更自然,
 * 我这里又用了一个‘重画’线程,
 */
public class drawCandlesThread extends Thread{
    Graphics graphics;
    private int capacity=80;
    boolean canDraw=false;
    boolean isLive=false;
    ArrayList<Candle> candles=new ArrayList<>(capacity);
    public drawCandlesThread(){
        for (int i = 0; i <capacity ; i++) {
            candles.add(new Candle());
            isLive=true;
        }
    }
    /**
     * 得到画纸,Java中的Graphics 就相当于画纸
     * 很多人说是画笔,但是我认为是画纸才恰当,
     * 当两个Graphics对象相同,就是同一张画纸,所以显示出来的图片就在同一个窗口了
     * 下面这个方法就是得到共同的那张纸
     * @param g
     */
    public void getGraphy(Graphics g)
    {
        graphics=g;
        canDraw=true;
    }

    /**
     * 
     */
    @Override
    public void run() {
        while (isLive) {
            if (canDraw) {   //加这个判断主要是看纸是否传过来了,不然下面用纸(Graphics)画蛋糕
                            // 会抛出空对象异常
                drawCandles();
            }
            try {
                Thread.sleep(0);
            } catch (InterruptedException e) {
//                e.printStackTrace();
            }
        }
    }//  在纸上画蛋糕
    //直接把纸传给每一个蛋糕对象,让让他们自己画
    public void drawCandles()
    {
        for (Candle candle : candles) {
            candle.draw(graphics);
        }
    }
}

#然后是蛋糕类

package Main;
import Main.usage.data;
import Main.usage.myImage;
import java.awt.*;
public class Candle {
    private double x,y;
    private int size= data.candleSize; //蛋糕的大小
    private double speed=data.candleSpeed*Math.random()+0.1;  //蛋糕下降的速度, 使用Math.random()为了使每个蛋糕下降的速度都不一样
    private Image image= myImage.getImage(data.candleImage());  // 获得图片
    Candle(){
    this.x=(int)(Math.random()*data.windowSizeX)-30; //获得随机位置,为了像下雨那样,
    this.y=(int)(Math.random()*(-400));//如果是固定的高度,一排一起下来就不好看了,
    }
    private void move() {   //移动
        y +=speed;  //每次往下移动speed个距离
        /**
         * //判断是否下降出边界 如果是 就重新回到上面
         */
        if (y>data.windowSizeY) {
            y = (int) (Math.random() * (-100));    //y轴位置
            x=(int)(Math.random()*data.windowSizeX)-30;//x轴位置
            speed=data.candleSpeed*Math.random()+0.1;//速度
        }
    }
    public void draw(Graphics g){
        move();    //每次画之前都要移动一下,这样就能出现下雨那样的效果了
        g.drawImage(image,(int)x,(int)y,size,size,null);
    }
}

画左上角那个闪光的玫瑰

原理就是把一个动图费解成几张图片,

(直接把一个gif文件用ps打开会自动切片,然后每张图片都分别去除背景,然后导出来十几张png用一个线程,依次画就实现了动图
那些图片可以用数组保存

package Main;
import Main.usage.data;
import Main.usage.myImage;
import java.awt.*;
public class drawRosesThread extends  Thread{
    private int x=20,y=40;
    private int sizeX= data.roseSizeX;
    private int sizeY=data.roseSizeY;
    private Graphics graphics;
    private Boolean canDraw=false;
    Image[] images=new Image[12];
    public drawRosesThread()
    {//初始化,把图片都装进数组中
        for (int i = 0; i <12 ; i++) {
            images[i]= myImage.getImage("Main/usage/images/rose_S/rose"+(i+1)+".png");
        }
    }
    /*
    画线程
     */
    @Override
    public void run() {
        while (true){
            if (canDraw)   //画纸传过来后开始画
                draw();
            else {
                /**
                 * 不要问我为什么下面线程睡眠0但是不删,
                 * 尽量不要动这个sleep(0)
                 * 删了程序就出bug,我也不知为什么,
                 * 
                 * 
                 * 我推测,当canDraw=false时,这个线程就没什么东西在跑,
                 * 系统就会把这个线程关闭,当我加一个sleep(0)时,就没bug了,
                 * emmm。。。。。。。。。。。。。。。。。。。。。。。
                 * 还有其他地方都有slee(0) 我也不知道,但是不要删,删了就不出错。。。
                 */
                try {
                    Thread.sleep(0);
                } catch (InterruptedException e) {
                }
            }
        }
    }
    public void getGraphy(Graphics g){    //得到画纸
        graphics=g;
        canDraw=true;   //只有得到画纸后才能画,不然后有空对象异常抛出;
    }
    private void draw()
    {
        for (int i = 0; i <12 ; i++) {
            graphics.drawImage(images[i],x,y,sizeX,sizeY,null);
        }
    }
}

画♥

那个心时由很多线条组成的,这些线条的函数是一样的,所以很多线条就组成了那个心
上代码

package Main;
import Main.usage.data;

import java.awt.*;
/** 使用Java中画直线的方法
 *  需要两个点(x1,y1),(x2,y2)
 *
 *  使用的笛卡尔函数; r=a(1-cosθ)  (极坐标方程高中应该学过)
 *  
 */
public class smallLove {

    private double a=80;   // 线条的长度公式中的a
    private double D=Math.random()*Math.PI*2;   //角度,注意角度生成要随机,
    // 因为每次添加五条线,如果不随机的画这五条线是在一起的,就相当于一条线了
    private double x,y;    //位置坐标
    public smallLove(){
        x= data.windowSizeX/2-100;  //使用窗口大小生成坐标,这样窗口改变的时候,坐标也会自动改变,这样就不会那么乱
        y=data.windowSizeY/2-300;
    }
    public void draw(Graphics g)
    {
        Graphics2D g2=(Graphics2D)g;//使用Gra/phics2D 是为了线条粗点,Graphics类不能改变线条粗细,默认的太细了
        g2.setStroke(new BasicStroke(2));//线条加粗,会用就行
        g2.setColor(Color.red);//设置红色
        D+=0.05; //每次画的时候就是转动角度,这样那个心其实是一直在动的,比照片上好看点
        g2.drawLine((int)x,(int)y,(int)(x+a*(1-Math.sin(D))*Math.cos(D)),(int)(y-a*(1-Math.sin(D))*Math.sin(D)));
       g.setColor(Color.black); //用完之后,把颜色重新弄回去
    }
}

为了实现每次鼠标点击,线条就增加,需要用到鼠标监听器(只能在窗口类中才能用,普通的类用不了所以我们在主类中加键盘监听器
(想在普通类中用的画,就弄个方法接受键鼠标监听器,在主类中把鼠标监听器对象传过去就行);

/*方法1 自己实现鼠标监听器接口
*/
public class mainFrame extends JFrame implements MouseListener{
//
public mainFrame(){
this.addMouseListener(this);//所以这里就是添加自己
}
//实现接口的方法
@Override
public void mouseClicked(MouseEvent mouseEvent) {
//鼠标点击时的操作
}

public void mousePressed(MouseEvent mouseEvent) {
//鼠标点下去的操作

}
@Override
public void mouseReleased(MouseEvent mouseEvent) {
//鼠标松开时的操作
}
@Override
public void mouseEntered(MouseEvent mouseEvent) {
//鼠标进入窗口的操作
}
@Override
public void mouseExited(MouseEvent mouseEvent) {
//鼠标离开窗口的操作
}

}

/**
 * 方法二
 * 创建一个类实现鼠标监听的接口
 * 
 */
public class Main extends JFrame {
    public Main(){
      this.addMouseListener(new key());
    }
    class key implements MouseListener {
        @Override
        public void mouseClicked(MouseEvent mouseEvent) {
            mouseEvent.getX();//获得鼠标的x坐标
             mouseEvent.getY();//,y坐标
            mouseEvent.getButton();//获得鼠标点击左键还是右键
            mouseEvent.getClickCount();//获得鼠标点击次数,      例如“双击”
        }
        @Override
        public void mousePressed(MouseEvent mouseEvent) { }
        @Override
        public void mouseReleased(MouseEvent mouseEvent) { }
        @Override
        public void mouseEntered(MouseEvent mouseEvent) { }
        @Override
        public void mouseExited(MouseEvent mouseEvent) { }
    }
}
/*键盘监听器的也是一样的哈,想使用的可以试试*/

/*
*  那个locations是用来存放要画玫瑰花的地址的容器
*每次点击,根据点击的x,y坐标添加地址对象,paint()方法中根据容器中的地址对象画玫瑰就行!
*/

@Override
public void mouseClicked(MouseEvent mouseEvent) {
    locations.add(new location(mouseEvent.getX(),         mouseEvent.getY()));
   Loves.add(new smallLove());
    Loves.add(new smallLove());
    Loves.add(new smallLove());
    Loves.add(new smallLove());
    Loves.add(new smallLove());
    Loves.add(new smallLove());
    Loves.add(new smallLove());
    Loves.add(new smallLove());
    Loves.add(new smallLove());
    Loves.add(new smallLove());
    Loves.add(new smallLove());
    Loves.add(new smallLove());

}

地址类其实很简单的啦,就存放x,y就行;

package Main.usage;
public class location {
/**
*实际中我这里还有个z;表示第几种玫瑰,一共五种,
所以随机选择的玫瑰就是(int)(Math.random()*5); 
当然也可以把这个z直接换成image对象,
我后面是根据这个z从数组中选择玫瑰的图片,都一样的哈~
*/

    private int x,y,z;
    public int getZ() {//第几种玫瑰
        return z;
    }
    public location(int x, int y)
    {
        this.x=x;
        this.y=y;
        z=(int)(Math.random()*5);
    }
    public int getX() {
        return x;
    }
    public int getY() {
        return y;
    }
}

讲讲双缓冲吧

因为实现我们用图片实现动画是不停的话,程序是一个一个的画图片,要画的图片变多的时候就会从第一个图片画完到最后一个图片画完中间经过的时间就会有点长,这时

人的眼睛就会察觉到了,所以为了避免闪烁,我们先让程序把要画的都在一张纸上全画完,然后就只画这张纸就行了这样就同步了,
具体代码


/**
 * 双缓冲原理
 */
public class Main extends JFrame {
    private Image bufferImg=null;//双缓冲要用的纸
    public Main(){
    }
    @Override
    public void paint(Graphics g) {
        if (bufferImg==null) {//判断是否存在,不存在就创建一张纸,
            // 这样做是只用一张纸就行了,避免你每次都重新创建
            bufferImg = this.createImage(data.sizeX, data.sizeY);//创建纸,
        }
        Graphics g2=bufferImg.getGraphics();//获得这张图片的“纸”;因为要在这张纸上画
        g2.drawImage();//用这张纸画东西
        rose.setGraphices(g2);//把这张纸传给其他对象,让每个对象在同一张纸上画
        g.drawImage(bufferImg,data.sizeX,data,sizeY,0,0,null);//最后把这张纸画出来
    }
}

最后看一下主类是怎么实现的`

package Main.start;
import Main.drawCandlesThread;
import Main.drawRosesThread;
import Main.smallLove;
import Main.usage.T;
import Main.usage.data;
import Main.usage.music;
import Main.usage.location;
import Main.usage.myImage;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.util.HashSet;
public class mainFrame extends JFrame implements MouseListener {
    HashSet<location> locations=new HashSet<>();    //记录每次点击时的位置
    HashSet<smallLove> Loves=new HashSet<>();//每次点击增加的线条都存在这里
    Image[] roseImages=new Image[5];   //还记得那个location对象中的z吗,就是用来从这个数组中取图片的
    Image buffer;//双缓冲要用的图片对象
    Image bg= myImage.getImage(data.bgImage);  //背景图片
    drawRosesThread roses; //这是画那个左上角闪光玫瑰要用的线程类
    drawCandlesThread candles;//这是画蛋糕雨要用的线程类
    public mainFrame()
    {
        this.init();
    }
    private void init(){
        //初始化窗口
        this.setLocation(300,0);
        this.setResizable(false);
        this.setSize(data.windowSizeX,data.windowSizeY);
        this.setVisible(true);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);//初始化窗口

        candles=new drawCandlesThread();
        candles.start();//蛋糕雨线程开启
        roses=new drawRosesThread();
        roses.start();//闪光玫瑰线程开启
        new paintThread().start();//重画线程开启
        this.addMouseListener(this);//添加鼠标监听器
        this.initRosesImages();//玫瑰数组初始化照片
    }
    /**
     * 玫瑰数组初始化照片
     */
    private void initRosesImages()
    {
        for (int i=0;i<5;i++)  //注意我那些玫瑰照片的名字特意命名位rose1,rose2了,所以可以用下面这个,反正能把图片装进数组就行
        {
            roseImages[i]=(myImage.getImage("Main/usage/images/roses/rose"+(i+1)+".png"));
        }
    }
    private void drawRose(Graphics g)//画点击时产生玫瑰
    {
        for (location location : locations){ //根据我们每次点击记录的坐标来画
            g.drawImage(roseImages[location.getZ()],location.getX(),location.getY(),(int)data.reseSize,(int)data.reseSize,null);
        }
            Loves.forEach(drawLove -> { //这个是画那个心的 很多线条组成的心
                drawLove.draw(g);
            }
            );
    }
    @Override
    public void paint(Graphics g) {
        if (buffer==null) buffer=this.createImage(data.windowSizeX,data.windowSizeY);//为了防止每次都创建新对象
        Graphics g2=buffer.getGraphics();  //获取双缓冲用到的图片的’纸‘ 因为要在这张纸上画
        g2.drawImage(bg,0,0,data.windowSizeX,data.windowSizeY,null);//画背景
        if (candles!=null)candles.getGraphy(g2);//给蛋糕传过去这张’纸‘
        if (roses!=null)roses.getGraphy(g2);//给左上角那个闪光玫瑰传过去这张‘纸’。
        this.drawRose(g2);//给我们点击生成的玫瑰传过去‘纸’
        g.drawImage(buffer,0,0,data.windowSizeX,data.windowSizeY,null);//最后画这张’纸图片‘
    }
    @Override
    public void mouseClicked(MouseEvent mouseEvent) {  // 每次点击记录一个坐标
        locations.add(new location(mouseEvent.getX(), mouseEvent.getY()));
        Loves.add(new smallLove()); //每次点击都会增加这么多的线条,
        Loves.add(new smallLove());
        Loves.add(new smallLove());
        Loves.add(new smallLove());
        Loves.add(new smallLove());
        Loves.add(new smallLove());
        Loves.add(new smallLove());
        Loves.add(new smallLove());
        Loves.add(new smallLove());
        Loves.add(new smallLove());
        Loves.add(new smallLove());
        Loves.add(new smallLove());//可以用个循环,emm ,都一样,每次点击增加10几条线,免得点几十次都出不来那个心型的轮廓

    }
    @Override
    public void mousePressed(MouseEvent mouseEvent) {
    }
    @Override
    public void mouseReleased(MouseEvent mouseEvent) {
    }
    @Override
    public void mouseEntered(MouseEvent mouseEvent) {
    }
    @Override
    public void mouseExited(MouseEvent mouseEvent) {
    }
    class paintThread extends Thread{
        @Override
        public void run() {
            while (true) { //注意,是个循环,因为线程开始只会调用一次run()
                repaint();
                try {
                    this.sleep(20);  //每次隔20ms重画,免得程序一直连着画,耗内存,能让肉眼看不见就行
                } catch (InterruptedException e) {
                }
            }
        }
    }
    public static void main(String[] args) {
        new mainFrame();
    }
}

音乐

礼物怎么能没有音乐呢?
我这里用的音乐《是夜空中的寂的静》钢琴版QQ音乐上好像是要付费的,我在网易音乐上找的免费版,
(也可以用天空之城,也是收费的,emmm。。。。)
上代码

package Main.usage;
import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.player.Player;

import java.io.*;

/**
 * 注意,播放音乐必须要用线程,因为我们是要图片和音乐一起播放,就必须是多线程的,否则的话,
 * 如果音乐先开始,就会一直放音乐,等音乐播放完才会开始放图片,先放图片就音乐播放不了。
 * 所以就用到线程,其实也很简单的,直接照着格式用就行了
 */
public class music extends Thread{
     Player player;
    @Override
    public void run() {
            try {
                //这个调用音频文件的和那个图片的方法也是相同的呢
                File file= new File(music.class.getClassLoader().getResource("Main/usage/music/first.mp3").getFile());
                //得到音频文件之后通过下面的方法播放
                player=new Player(new FileInputStream(file));
                player.play();//开启播放
            } catch (JavaLayerException e) {
//                e.printStackTrace();
            } catch (FileNotFoundException e) {
//                e.printStackTrace();
            }
    }

    /**
     * 在我们主类中要播放音乐直接在init()(构造)方法中添加下面两条语句就行了
     * @param args
     */
    public static void main(String[] args) {
       music music= new music();
       music.start();
       //必须是用线程的start()方法,这样才是新建一个线程,
        // 而run()方法是仅仅调用run()方法,而不是我们期望的新建一个线程;
    }
}
另外这个播放音乐需要外部的jar 没办法,我这里用的maven 依赖如下
<dependency>
        <groupId>javazoom</groupId>
        <artifactId>jlayer</artifactId>
        <version>1.0.1</version>
    </dependency>

另外如果不是maven的话,直接网上找个把搜索javazoom jar下载“配置一下,网上都有教程的,
或者可以新建一个maven项目把那个的pom.xml复制过来
(我发现的偷懒方法哦 )
复制到项目的根目录下,和那个src是并排的,直接复制过来是红色的不能用要右键单击选择add as maven (我用的是IDEA,如果是eclipse就不太清楚了)添加依赖后如果项目没有自己下载jar就进入那个pom.xml,然后右键单击点击maven 再点击download Source and Documation 下载jar
至此,我们的程序在IDEA上面应该y是可’以运行 的,接下来就是制作exe文件 了,
首先是先打包成jar文件,网上都有很多教程的,
我就不细说的
这里我先转载一个看着可用的吧
IDEA打包jar

弄好jar文件后用exe4J制作exe文件
我转!→EXE
如果程序调用图片和音乐是按照我上面的,最后生成的exe文件应该是可以显示图片和音乐的。
最后得到的就是一个文件夹包含jre和exe文件那个jar文件可以删了
一共200多MB,jre就占了190MB,emm。。。
网上有关于jre瘦身的
我再转→[jre瘦身]
不过我看着都很麻烦,200多就两百多吧
emmmm。。。。。

源代码

(赚个小积分,嘻嘻嘻嘻)
其实还是自己做比较好,礼物嘛,还是自己敲比较有心意哒~

大致制作过程就参考上面的介绍吧,有问题可以在下面指出了哈,我会及时改的~

posted @ 2019-12-17 11:31  G521  阅读(92)  评论(0编辑  收藏  举报