JAVA学习日志5 图形用户接口 (Head First Java 190630)

本文详细介绍如何使用Java Swing库创建基本的图形用户界面(GUI),包括创建第一个GUI、制作自定义绘图面板、处理按钮事件以及使用内部类实现动画效果。通过实例讲解了JFrame、JButton等组件的使用,以及如何通过覆盖paintComponent方法绘制图形。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第十二章 图形用户接口

1. 第一个GUI

我们用JFrame来作图像用户接口。一旦创建出JFrame后,你就可以把组件(widget)加到上面。有很多的Swing组件可以使用,它们在javax.swing这个包中。最常使用的组件包括: JButton、JRadioButton、JCheckBox、JLabel、JList、JScrollPane、JSlider、JTextArea、JTextField和JTable等。大部分很容易使用。

import javax.swing.*;    // 别忘记引进swing包

public class SimpleGui1 {
	JFrame frame = new JFrame();   // 创建出frame
	JButton button = new JButton("click me");  // 创建出button
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  // 这一行程会在Windows关闭时把程序结束掉
	frame.setContentPane().add(button);  // 把button加到frame的pane上
	frame.setSize(300, 300);  // 设定frame的大小
	frame.setVisible(true);  // 最后把frame显示出来

运行代码会生成如下的窗口:
在这里插入图片描述
窗口中"click me"按钮占据了所有窗口面积,而且点击后并没有实现任何功能。如果想要知道按钮的事件,就会监听事件的接口。监听接口是介于监听(你)和事件源(按钮)间的桥梁。

事件源(按钮)会在用户做出相关动作时(按下按钮)产生事件的对象。你的程序在大多数情况下是事件的接受方而不是创建方。也就是说,你会花较多的时间当监听者而不是时间来源。

实现监听接口让按钮有一个回头调用程序的方式。interface正是声明调用(call-back)方法的地方。

取得按钮的ActionEvent

  1. 实现ActionListener这个接口
  2. 向按钮注册(告诉它你要监听事件)
  3. 定义事件处理的方法(实现接口上的方法)
import javax.swing.*;
import java.awt.event.*;  // ActionListener和ActionEvent所在的包

public class SimpleGUI implements ActionListener {   //实现接口,表示其是个ActionListener
	JButton button;
	
	public static void main(String[] args) {
		SimpleGUI gui = new SimpleGUI();
		gui.go();
	}	
	public void go() {
		JFrame frame = new JFrame();
		button = new JButton("click me!");
		button.addActionListener(this);  // 向按钮注册
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.getContentPane().add(button);
		frame.setSize(300, 300);
		frame.setVisible(true);
	}
	public void actionPerformed(ActionEvent event) {  // 实现interface上的方法
		button.setText("I have been clicked!");  // 按钮会以ActionEvent对象作为参数来调用此方法
	}
}

2. 制作板绘图

我们有时候会想要设定自己想要的图案,这时我们可以创建JPanel的子类并覆盖掉paintComponent()这个方法,并在其中写出自己想要实现的图形或者样式。注意的是这里调用该方法的参数是个和实际屏幕有关的Graphics对象,你无法取得它,只能由系统交给你。
在主程序中创建出JPanel子类的对象,将其加入框架会自动调用paintComponent()方法,不需要用"对象名.paintComponent()"的形式。

2.1 画出图形

import java.awt.*;
import javax.swing.*;
	
class MyDrawPanel extends JPanel {  // 创建JPanel的子类
	public void paintComponent(Graphics g) {  // 覆盖paintComponent方法,注意一定要加上Graphics对象
		
		g.setColor(Color.blue);  // 设定颜色
		g.fillRect(20, 50, 100, 100);  // Rect表示方形,起始位置(20,50),大小(100,100)
	}
}

2.2 显示JPEG

class MyDrawPanel extends JPanel {  
	public void paintComponent(Graphics g) {  
		Image image = new ImageIcon("PeppaPig.jpg").getImage();  // 引号内为文件名小猪佩奇
		g.drawImage(image, 3, 4, this);  // 3,4表示图片离左方边缘3个像素,顶端边缘4个像素
	}
}

2.3 在黑色背景板显示随机彩色圆圈

class MyDrawPanel extends JPanel {  
	public void paintComponent(Graphics g) {  
		g.fillRect(0, 0, this.getWidth(), this.getHeight());  // 用和窗口一样大的黑色方块盖住全部窗口,当做黑色背景
		int red = (int) (Math.random()*255);  // 设定随机的三基色RGB
		int green = (int) (Math.random()*255);
		int blue = (int) (Math.random()*255);
		Color randomColor = new Color(red, green, blue);  // 混合形成随机新颜色 
		g.setColor(randomColor);
		g.fillOval(70, 70, 100, 100);  // Oval表示建立椭圆
	}
}

Graphics
每个Graphics引用的后面的有个Graphics2D对象,你可以将其转换成2D形式,Graphics2D类有更多的方法。如果你要调用Graphics2D类的方法,就不能直接用g参数。但你可以将其转换为Graphics2D变量,操作方法只需在paintComponent()方法中加入:

Graphics2D g2d = (Graphics2D) g;

可以对Graphics引用调用的方法(部分):

  • drawImage( )
  • drawLine( )
  • drawPolygon( )
  • drawRect( )
  • drawOval( )
  • fillRect( )
  • fillRoundRect( )
  • setColor

可以对Graphics2D引用调用的方法(部分):

  • fill3DRect( )
  • draw3DRect( )
  • rotate( )
  • scale( )
  • shear( )
  • transform( )
  • setRenderingHints( )

下面是个使用Graphics2D类方法制作随机渐变色圆的例子:

public class MyDrawPanel extends JPanel {
	public void paintComponent(Graphics g) {
		Graphics2D g2d = (Graphics2D) g;  // 转变类型为Graphics2D
		int red = (int) (Math.random()*255);  
		int green = (int) (Math.random()*255);
		int blue = (int) (Math.random()*255);
		Color startColor = new Color(red, green, blue); 
		red = (int) (Math.random()*255);  
		green = (int) (Math.random()*255);
		blue = (int) (Math.random()*255);
		Color endColor = new Color(red, green, blue);
		GradientPaint gradient = new GradientPaint(70, 70, startColor, 150, 150, endColor);  // (70,70)为起点,(150,150)为颜色终点
		g2d.setPaint(gradient);  // 将“笔刷”设定为渐层
		g2d.fillOval(70, 70, 100, 100);  // 用目前笔刷填满图形
	}
}

在这里插入图片描述
GUI的布局
这里先简单说一下GUI的layout,frame默认有5个区域可以安置widget。每个区域可以安置一项。可以通过这样实现:

frame.getContentPane().add(BorderLayout.SOUTH, button);

这段代码可以把button放在界面的最南端,同样你还可以输入EAST, WEST, NORTH, CENTER, 就能将button分别放在东、西、北、 中。
在这里插入图片描述

3. 内部类

当我们有两个及以上的按钮时,我们不能同时写两个actionPerformed()方法,这个时候就需要内部类了。内部类就是在其它类中的类,实现的话只需要其在大类的最外部括号中就行。
内部类可以使用外部类所有的方法和变量,即使是私有变量

class Myouter {
	private int x;  // 外部类的私有的x实例变量
	MyInner inner = new MyInner();  // 创建内部的实例
	public void doStuff() {
		inner.go();  // 调用内部的方法
	}
	class MyInner {
		void go() {  // 内部也可以使用外部的x变量
			x = 42;
		}
	}  // 关闭内部类
}  // 关闭外部类

运用内部类我们可以实现多个按钮的功能

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;

public class TwoButton {
	JFrame frame;
	JButton botton;
	public void go() {
		frame = new JFrame();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		MyDrawPanel panel = new MyDrawPanel();
		botton = new JButton("I'm a label");
		JButton changeLabel = new JButton("Change Label!");
		JButton changeColor = new JButton("change color!");
		changeLabel.addActionListener(new ChangeLabel());
		changeColor.addActionListener(new ChangeColor());
		frame.getContentPane().add(BorderLayout.WEST, botton);
		frame.getContentPane().add(BorderLayout.EAST, changeLabel);
		frame.getContentPane().add(BorderLayout.SOUTH, changeColor);
		frame.getContentPane().add(BorderLayout.CENTER, panel);
		frame.setSize(500, 500);
		frame.setVisible(true);
	}
	class ChangeLabel implements ActionListener {  // 运用内部类实现“changeLable”按钮的功能 
		public void actionPerformed(ActionEvent event) {
			botton.setText("Ouch!");
		}
	}
	class ChangeColor implements ActionListener {  //实现“changeColor”按钮的功能
		public void actionPerformed(ActionEvent event) {
			frame.repaint();
		}
	}
	public static void main(String[] args) {
		TwoButton gui = new TwoButton();
		gui.go();
	}
}

以内部类执行动画效果
运用内部类还可以实现简单的动画,我们只需要把JPanel的子类当做内部类,就可以实现这个功能。

import java.awt.*;
import javax.swing.*;

public class MoveTest {
	int x = 50;
	int y = 50;
	public void go() {
		JFrame frame = new JFrame();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		DrawPanel panel = new DrawPanel();
		frame.getContentPane().add(panel);
		frame.setSize(300,300);
		frame.setVisible(true);
		
		for(int i = 0; i < 130; i++) {
			x++;
			y++;
			panel.repaint();
			try {
				Thread.sleep(50);  //延迟可以放慢
			} catch(Exception ex) {
				ex.printStackTrace();
			}
		}	
	}
	class DrawPanel extends JPanel {  // drawPanel充当内部类,可共享想x,y坐标,实现位置变换
		public void paintComponent(Graphics g) {
			g.setColor(Color.blue);
			g.fillOval(x, y, 50, 50);
		}
	}
	public static void main(String[] args) {
		MoveTest test = new MoveTest();
		test.go();
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值