蹭个热度用Java画个圣诞树,整体思路就是先画树和灯,画完以后加顶端的星星,之后再加飘雪特效和音乐,最后另做一个窗口,用来读取用户自定义的参数。

首先是画树和灯(Tree.java),这里主要是用 fillRect 和 fillOval来画,最后效果如下:

 

这里用两张图是想说明,灯串其实做了闪烁效果,也就是repaint的时候,灯的颜色会由有色变无色,无色变有色,所以为了呈现效果,我把树中间的空隙也用fillRect画上了背景色。

接下来是画顶端的星星和飘雪特效(Snow.java),这里为了图方便,飘雪特效用的是自己画的GIF图,星星则是一个button,点击可打开/关闭飘雪特效。同时BGM也放在了这个类里。

最后就是自定义部分。颜色部分(RGB.java)用到了ColorChooser类来选择颜色,还有一个JRadioButton来选择是否使用默认颜色。而树高部分(Xmas.java)则是用的JComboBox来选择对应高度(高度会影响之后画有圣诞树的窗口的大小)。为了美观(乐趣?),我还做了一个开始页面,效果如下:

开始页面:

自定义页面:

 

 

完整代码如下:

public class Xmas extends JFrame implements ActionListener{
	
	private int Width, Height;
	private boolean submit = false;
	JLayeredPane lp = new JLayeredPane();
	JLabel ct;
	JButton button;
	JComboBox<Integer> layerSelected = new JComboBox<>(new MyComboBox());
	RGB p1, p2, p3, p4;
	ArrayList<Integer> colours = new ArrayList<Integer>();
	
	public Xmas() {
		this.setTitle("狐狸子的圣诞树售卖店");
		URL iconUrl = this.getClass().getResource("/sources/tree.png");
		Image tree = Toolkit.getDefaultToolkit().getImage(iconUrl);
		this.setIconImage(tree);
		this.setLayout(null);
		this.setResizable(false);
		this.setSize(800, 650);
		this.setLocationRelativeTo(null); //Put the window to the centre of the screen
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		/*Set the background picture*/
		URL imgUrl = this.getClass().getResource("/sources/Background.jpg");
		ImageIcon background = new ImageIcon(imgUrl);
		JLabel bg = new JLabel(background);
		bg.setBounds(0, 0, background.getIconWidth(), background.getIconHeight());
		
		/*Set the content*/
		URL contentUrl = this.getClass().getResource("/sources/Content.png");
		ImageIcon content = new ImageIcon(contentUrl);
		ct = new JLabel(content);
		ct.setBounds(30, 50, content.getIconWidth(), content.getIconHeight());
		
		/*Create the start button*/
		button = new JButton("");
		URL url = this.getClass().getResource("/sources/Start.png");
		ImageIcon start = new ImageIcon(url);
		button.setIcon(start);
		button.setBorder(null);
		button.setContentAreaFilled(false);
		button.setBounds(150, 430, 200, 55);
		button.addActionListener(this);

		lp.add(bg, new Integer(100));
		lp.add(ct, new Integer(150));
		lp.add(button, new Integer(200));
		this.setContentPane(lp);
	}
	
	public Xmas(int layer, ArrayList<Integer>c) {
		this.setTitle("点击星星有惊喜呦╰(*°▽°*)╯");
		this.setLayout(null);
		this.setBackground(new Color(c.get(0), c.get(1), c.get(2)));
		Width = (layer*4+3) * 17 + 150;
		Height = (layer*4+2) *17 + 150;
		this.setSize(Width, Height);
		this.setResizable(false); 
		this.setLocationRelativeTo(null);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		Tree tree = new Tree(layer, c);
		this.setContentPane(tree);
		Snow snow = new Snow(layer);
		this.setGlassPane(snow);
		snow.setOpaque(false);
		this.getGlassPane().setVisible(true);
		this.validate();
	}
	
	@Override
	public void actionPerformed(ActionEvent arg0) {
		if (!submit) {
			/*Remove the landing page's component*/
			ct.setVisible(false);
			
			/*Change the content*/
			URL imgUrl = this.getClass().getResource("/sources/Data.png");
			ImageIcon customize = new ImageIcon(imgUrl);
			JLabel cm = new JLabel(customize);
			cm.setBounds(30, 50, customize.getIconWidth(), customize.getIconHeight());
			
			/*Change the button*/
			URL url = this.getClass().getResource("/sources/Submit.png");
			ImageIcon submit = new ImageIcon(url);
			button.setIcon(submit);
			button.setBorder(null);
			button.setContentAreaFilled(false);
			button.setBounds(75, 430, submit.getIconWidth(), submit.getIconHeight());
			button.addActionListener(this);
			
			/*Make a combo box*/
			layerSelected.setBounds(215, 65, 75, 35);
			
			/*custom color*/
			p1 = new RGB(166, 27, 41); //Background colour
			p1.setBounds(270, 260, 300, 40);
			p1.setOpaque(false);
			p2 = new RGB(67, 178, 68); //Leafs colour
			p2.setBounds(310, 290, 220, 40);
			p2.setOpaque(false);
			p3 = new RGB(92, 55, 25); //Root colour
			p3.setBounds(310, 320, 220, 40);
			p3.setOpaque(false);
			p4 = new RGB(248, 223, 112); //Light colour
			p4.setBounds(310, 350, 220, 40);
			p4.setOpaque(false);
			
			lp.add(p1, new Integer(260));
			lp.add(p2, new Integer(262));
			lp.add(p3, new Integer(264));
			lp.add(p4, new Integer(268));
			lp.add(cm, new Integer(270));
			lp.add(layerSelected, new Integer(300));
		} else {
			colours.add(p1.getRedValue());
			colours.add(p1.getGreenValue());
			colours.add(p1.getBlueValue());
			colours.add(p2.getRedValue());
			colours.add(p2.getGreenValue());
			colours.add(p2.getBlueValue());
			colours.add(p3.getRedValue());
			colours.add(p3.getGreenValue());
			colours.add(p3.getBlueValue());
			colours.add(p4.getRedValue());
			colours.add(p4.getGreenValue());
			colours.add(p4.getBlueValue());
			
			this.dispose();
			int height = (int)layerSelected.getSelectedItem();
			Xmas c = new Xmas(height, colours);
			c.setVisible(true);
		}
		submit = !submit;
	}
}
public class RGB extends JPanel implements ActionListener{
	final int[] defaultColor = new int[3];
	int[] rgb = new int[3];
	final JLabel label = new JLabel("        ");
	JButton cc = new JButton("选择颜色");
	JRadioButton customize = new JRadioButton("默认色", false);
	
	public RGB(int r, int g, int b) {
		FlowLayout f = (FlowLayout)this.getLayout();
		f.setHgap(15);
		
		/*Save the RGB value of the default colour*/
		defaultColor[0] = r;
		defaultColor[1] = g;
		defaultColor[2] = b;
		
		/*Set the colour as default colour*/
		rgb[0] = defaultColor[0];
		rgb[1] = defaultColor[1];
		rgb[2] = defaultColor[2];
		
		/*Make the colour chooser's button*/
		cc.addActionListener(this);
		cc.setSize(70, 35);
		
		/*Make the colour block*/
        label.setOpaque(true);        
		label.setSize(35, 35);
		label.setBackground(new Color(r, g, b));

		/*Make the JRadioButton for the default color*/
		customize.setSize(30, 35);
		customize.setOpaque(true);
		customize.setBorder(null);
		customize.setContentAreaFilled(false);
		customize.addActionListener(this);
		
		this.add(label);
		this.add(cc);
		this.add(customize);
		
	}
	
	@Override
    public void actionPerformed(ActionEvent e) {
		if (e.getSource() == customize) {
			cc.setEnabled(!customize.isSelected());
			rgb[0] = defaultColor[0];
			rgb[1] = defaultColor[1];
			rgb[2] = defaultColor[2];
			label.setBackground(new Color(rgb[0], rgb[1], rgb[2]));
		}
		
		if (e.getSource() == cc && (!customize.isSelected())) {
	        Color color = JColorChooser.showDialog(this, "选取颜色", null);

	        if (color == null) {
	            return;
	        }
	        label.setBackground(color);

	        rgb[0] = color.getRed();
	        rgb[1] = color.getGreen();
	        rgb[2] = color.getBlue();
		}
    }
		
	public int getRedValue() {
		return rgb[0];
	}
	
	public int getGreenValue() {
		return rgb[1];
	}
	
	public int getBlueValue() {
		return rgb[2];
	}
}
public class MyComboBox extends AbstractListModel<Integer> implements ComboBoxModel<Integer>{
	private final int[] layers = {5, 6, 7, 8, 9, 10, 11};
	int selectedItem;
	
	public MyComboBox() {
		this.setSelectedItem(this.getElementAt(0));
	}
	
	@Override
	public Integer getElementAt(int index) {
		return layers[index];
	}

	@Override
	public int getSize() {
		return layers.length;
	}

	@Override
	public Object getSelectedItem() {
		return selectedItem;
	}

	@Override
	public void setSelectedItem(Object item) {
		selectedItem = (int) item;
		
	}

}
public class Tree extends JPanel implements ActionListener{
	
	private int x;
	private int y;
	private int[] range;
	private int endY;
	private final int layer;
	private boolean change = false;
	Timer time;
	private ArrayList<Integer> colours = new ArrayList<Integer>();
	
	public Tree(int layer, ArrayList<Integer> cs) {
		this.layer = layer;
		this.colours.addAll(cs);
		this.setLayout(null);
		range = new int[layer *8];
		time = new Timer(300, this);
		time.start();
	}
	
	public void paintComponent(Graphics g) {
		//super.paint(g);
		this.drawLeafs(g);
		this.drawRoot(g);
		if (change) {
			this.drawBalls(g, 0);
		} else {
			this.drawBalls(g, 1);
		}
	}
	
	public void actionPerformed(ActionEvent e) {
		this.repaint();
		change = !change;
	}
	
	private void drawLeafs(Graphics g) {
		x = 50;
		y = 50;
		int maxLeafs = layer*4 + 3;
		int leaf = 1;
		int pos = maxLeafs/2 + 1;
		int index = 0;
		
		for (int i = 0; i < layer; i++) {
			for (int j = 0; j < 4; j++) {
				x = x + 17 * pos; //Find the start position
				range[index] = x; //Record the start position of this line
				index++;

				for (int k = 0; k < leaf; k++) {
					g.setColor(new Color(colours.get(3), colours.get(4), colours.get(5))); //Draw the leafs
					g.fillRect(x, y, 15, 15);
					g.setColor(new Color(colours.get(0), colours.get(1), colours.get(2))); //Fill the space
					g.fillRect(x+15, y, 2, 15);
					g.fillRect(x, y+15, 17, 2);
					x += 17;
				}
				
				range[index] = x; //Record the end position of this line
				index++;
				leaf += 2; //The number of leafs will increase by 2 for each line
				pos --;
				x = 50;
				y += 17;
			}
			leaf -= 4;
			pos += 2;
		}
		endY = y;
	}

	private void drawRoot(Graphics g) {
		x = 50;
		y = endY;
		
		for (int i = 0; i < 3; i++) {
			x = x + 17*(layer + 2);
			g.setColor(new Color(colours.get(6), colours.get(7), colours.get(8)));
			for (int j = 0; j < (2*layer+1); j++) {
				g.fillRect(x, y, 15, 15);
				x += 17;
			}
			
			x = 50;
			y += 17;
		}
	}
	
	private void drawBalls(Graphics g, int init) { //Set the first ball's colour
		Color[] colors = {new Color(0, 0, 0, 0), new Color(colours.get(9), colours.get(10), colours.get(11))};
		int lights = 3;
		int winding = 15;
		for (int i = 0; i < layer-2; i++) {
			/* Calculate the corresponding x range*/
			int line = i*4 + 6;
			int xStart = range[line * 2];
			int xEnd = range[line*2 + 1];
			int range = (xEnd - xStart) / lights;
			int xpos = xStart + 10;
			int ypos = 50 + line * 17;
			
			/*Start to draw the lights*/
			for (int j = 0; j < lights/2 + 1; j++) {
				g.setColor(colors[init % 2]);
				g.fillOval(xpos, ypos, 23, 23);
				init++;
				xpos += range;
				ypos += winding;
			}
			ypos -= 2*winding;
			for (int j = lights/2 + 1; j < lights; j++) {
				g.setColor(colors[init % 2]);
				g.fillOval(xpos, ypos, 23, 23);
				init++;
				xpos += range;
				ypos -= winding;
			}
			lights+=2;
			winding--;
		}
	}
}
public class Snow extends JPanel implements ActionListener{

	JButton star = new JButton(); //Control the snow
	AudioClip clip = null;
	URL url = null;
	JLabel snowy;
	boolean play = true;
	private final int Width;
	
	public Snow(int layer) {
		/* Play the BGM*/
		url = this.getClass().getResource("/sources/music.wav");
		clip = Applet.newAudioClip(url);
		clip.loop();
		
		/* Calculate the relevant parameters and timer*/
		Width = (layer*4+3) * 17 + 150;
		
		/* Create the snow button*/
		URL imgUrl = this.getClass().getResource("/sources/Star.png");
		ImageIcon icon = new ImageIcon(imgUrl);  //Size: 50*50
		star.setIcon(icon);
		star.setBorder(null);
		star.setContentAreaFilled(false);
		star.setBounds(Width/2-40, 15, 50, 50);
		//star.setBounds(0, 0, 50, 50);
		star.addActionListener(this);
		this.add(star);
		this.snowy();
	}
	
	public void actionPerformed(ActionEvent e) {
		if (play) {
			snowy.setVisible(true);
		} else {
			snowy.setVisible(false);
		}
		
		play = !play;
	}
		
	private void snowy() { //Create the snow
		URL imgUrl = this.getClass().getResource("/sources/Snowy.gif");
		ImageIcon snow = new ImageIcon(imgUrl);
		snowy = new JLabel(snow);
		this.add(snowy);
		snowy.setVisible(false);
	}

最后,祝大家平安夜,圣诞还有即将到来的新年快乐呀

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐