第十七节、轻松学Java_GUI编程

容器类与布局管理器

容器类

Container 又分为两种类型, 分别是 Window 和 Panel。
Window 类是不依赖其他容器而独立存在的容器, 它有两个子类, 分别是 Frame 类和 Dialog 类。
Frame类用于创建一个具有标题栏的框架窗口, 作为程序的主界面。
Dialog 类用于创建一个对话框,实现与用户的信息交互。
Panel 也是一个容器, 但是它不能单独存在, 只能存在于其他容器( Window 或其子类) 中, 一个 Panel对象代表了一个长方形的区域, 在这个区域中可以容纳其他组件。

布局管理器

在 java.awt 包中提供了 5 种布局管理器, 分别是 FlowLayout( 流式布局管理器)、 BorderLayout( 边界布局管理器)、 GridLayout( 网格布局管理器)、 GridBagLayout( 网格包布局管理器) 和 CardLayout( 卡片布局管理器)。

流式布局管理器

在这种布局下, 容器会将组件按照添加顺序从左向右放置。 当到达容器的边界时, 会自动将组件放到下一行的开始位置。 这些组件可以左对齐、 居中对齐( 默认方式) 或右对齐的方式排列。

package com.test;
import java.awt.Frame ;
import java.awt.FlowLayout;
import java.awt.Button;
public class Test {
	public static void main(String[] args) {
		final Frame f = new Frame("Flowlayout");// 创建一个名为Flowlayout的窗体
		// 设置窗体中的布局管理器为FlowLayout,所有组件左对齐,水平间距为20,垂直间距为30
		f.setLayout(new FlowLayout(FlowLayout.LEFT, 20, 30));
		f.setSize(220, 300); // 设置窗体大小
		f.setLocation(300, 200); // 设置窗体显示的位置
		f.add(new Button("第1个按钮")); // 把"第1个按钮"添加到f窗口
		f.add(new Button("第2个按钮"));
		f.add(new Button("第3个按钮"));
		f.add(new Button("第4个按钮"));
		f.add(new Button("第5个按钮"));
		f.add(new Button("第6个按钮"));
		f.setVisible(true); // 设置窗体可见
	}
}

输出:
在这里插入图片描述

边界布局管理器

BorderLayout( 边界布局管理器) 是一种较为复杂的布局方式, 它将容器划分为 5 个区域, 分别是东(EAST)、 南(SOUTH)、 西(WEST)、 北(NORTH)、 中(CENTER)。

package com.test;
import java.awt.Frame ;
import java.awt.BorderLayout;
import java.awt.Button;
public class Test {
	public static void main(String[] args) {
		final Frame f = new Frame("BorderLayout");// 创建一个名为BorderLayout的窗体
		f.setLayout(new BorderLayout()); // 设置窗体中的布局管理器为BorderLayout
		f.setSize(300, 300); // 设置窗体大小
		f.setLocation(300, 200);// 设置窗体显示的位置
		f.setVisible(true); // 设置窗体可见
		// 下面的代码是创建5个按钮,分别用于填充BorderLayout的5个区域
		Button but1 = new Button("东部"); // 创建新按钮
		Button but2 = new Button("西部");
		Button but3 = new Button("南部");
		Button but4 = new Button("北部");
		Button but5 = new Button("中部");
		// 下面的代码是将创建好的按钮添加到窗体中,并设置按钮所在的区域
		f.add(but1, BorderLayout.EAST); // 设置按钮所在区域
		f.add(but2, BorderLayout.WEST);
		f.add(but3, BorderLayout.SOUTH);
		f.add(but4, BorderLayout.NORTH);
		f.add(but5, BorderLayout.CENTER);
	}
}

输出:
在这里插入图片描述

网格布局管理器

与 FlowLayout 不同的是, 放置在 GridLayout 布局管理器中的组件将自动占据网格的整个区域。

package com.test;
import java.awt.Frame ;
import java.awt.GridLayout;
import java.awt.Button;
public class Test {
	public static void main(String[] args) {
		Frame f = new Frame("GridLayout");// 创建一个名为GridLayout的窗体
		f.setLayout(new GridLayout(3, 3));// 设置该窗体为3*3的网格
		f.setSize(300, 300); // 设置窗体大小
		f.setLocation(400, 300);
		// 下面的代码是循环添加9个按钮到GridLayout中
		for (int i = 1; i <= 9; i++) {
			Button btn = new Button("btn" + i);
			f.add(btn); // 向窗体中添加按钮
		}
		f.setVisible(true);
	}
}

输出:
在这里插入图片描述

网格包布局管理器

它与 GridLayout 布局管理器类似, 不同的是, 它允许网格中的组件大小各不相同, 而且允许一个组件跨越一个或者多个网格。

使用GridLayout 布局管理器的步骤如下:
1、创建GridLayout 布局管理器,并使容器采用该布局管理器。
2、创建GridBagConstraints对象(布局约束条件),并设置该对象的相关属性。
3、调用GridLayout对象的setConstraints()方法建立GridBagConstraints对象和受控组件之间的关联。
4、向容器中添加组件
GridBagConstraints对象可以重复使用,只需要改变它的属性即可。如果要向容器中添加多个组件,则重复2、3、4。

package com.test;
import java.awt.Frame ;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Button;
class Layout extends Frame {
	public Layout(String title) {
		GridBagLayout layout = new GridBagLayout();
		GridBagConstraints c = new GridBagConstraints();
		this.setLayout(layout);
		c.fill = GridBagConstraints.BOTH; // 设置组件横向纵向可以拉伸
		c.weightx = 1; // 设置横向权重为1
		c.weighty = 1; // 设置纵向权重为1
		this.addComponent("btn1", layout, c);
		this.addComponent("btn2", layout, c);
		this.addComponent("btn3", layout, c);
		c.gridwidth = GridBagConstraints.REMAINDER; // 添加的组件是本行最后一个组件
		this.addComponent("btn4", layout, c);
		c.weightx = 0; // 设置横向权重为0
		c.weighty = 0; // 设置纵向权重为0
		addComponent("btn5", layout, c);
		c.gridwidth = 1; // 设置组件跨一个网格(默认值)
		this.addComponent("btn6", layout, c);
		c.gridwidth = GridBagConstraints.REMAINDER; // 添加的组件是本行最后一个组件
		this.addComponent("btn7", layout, c);
		c.gridheight = 2; // 设置组件纵向跨两个网格
		c.gridwidth = 1; // 设置组件横向跨一个网格
		c.weightx = 2; // 设置横向权重为2
		c.weighty = 2; // 设置纵向权重为2
		this.addComponent("btn8", layout, c);
		c.gridwidth = GridBagConstraints.REMAINDER;
		c.gridheight = 1;
		this.addComponent("btn9", layout, c);
		this.addComponent("btn10", layout, c);
		this.setTitle(title);
		this.pack();
		this.setVisible(true);
	}
	// 增加组件的方法
	private void addComponent(String name, GridBagLayout layout,
			GridBagConstraints c) {
		Button bt = new Button(name); // 创建一个名为name的按钮
		layout.setConstraints(bt, c); // 设置GridBagConstraints对象和按钮的关联
		this.add(bt); // 增加按钮
	}
}
public class Test {
	public static void main(String[] args) {
		new Layout("GridBagLayout");
	}
}

输出:
在这里插入图片描述

卡片布局管理器

卡片布局管理器将界面看作一系列卡片, 在任何时候只有其中一张卡片是可见的, 这张卡片占据容器的整个区域。

package com.test;
import java.awt.Frame ;
import java.awt.Button;
import java.awt.Label;
import java.awt.Panel;
import java.awt.CardLayout;
import java.awt.BorderLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
class Cardlayout extends Frame implements ActionListener {
	Panel cardPanel = new Panel(); // 定义Panel面板放置卡片
	Panel controlpaPanel = new Panel(); // 定义Panel面板放置按钮
	Button nextbutton, preButton;       //声明两个按钮
	CardLayout cardLayout = new CardLayout();// 定义卡片布局对象
	// 定义构造方法,设置卡片布局管理器的属性
	public Cardlayout() { 
		setSize(300, 200);
		setVisible(true);
		// 为窗口添加关闭事件监听器
		this.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				Cardlayout.this.dispose();
			}
		});
		cardPanel.setLayout(cardLayout); // 设置cardPanel面板对象为卡片布局
		// 在cardPanel面板对象中添加3个文本标签
		cardPanel.add(new Label("第一个界面", Label.CENTER));
		cardPanel.add(new Label("第二个界面", Label.CENTER));
		cardPanel.add(new Label("第三个界面", Label.CENTER));
		// 创建两个按钮对象
		nextbutton = new Button("下一张卡片");
		preButton = new Button("上一张卡片");
		// 为按钮对象注册监听器
		nextbutton.addActionListener(this);
		preButton.addActionListener(this);
		// 将按钮添加到controlpaPanel中
		controlpaPanel.add(preButton);
		controlpaPanel.add(nextbutton);
		// 将cardPanel面板放置在窗口边界布局的中间,窗口默认为边界布局
		this.add(cardPanel, BorderLayout.CENTER);
		// 将controlpaPanel面板放置在窗口边界布局的南区,
		this.add(controlpaPanel, BorderLayout.SOUTH);
	}
	// 下面的代码实现了按钮的监听触发,并对触发事件做出相应的处理
	public void actionPerformed(ActionEvent e) {
		// 如果用户单击nextbutton,执行的语句
		if (e.getSource() == nextbutton) {
			// 切换cardPanel面板中当前组件之后的一个组件,若当前组件为最后一个组件,则显示第一个组件。
			cardLayout.next(cardPanel);
		}
		if (e.getSource() == preButton) {
			// 切换cardPanel面板中当前组件之前的一个组件,若当前组件为第一个组件,则显示最后一个组件。
			cardLayout.previous(cardPanel);
		}
	}
}
public class Test {
	public static void main(String[] args) {
		Cardlayout cardlayout = new Cardlayout();
	}
}

输出:
在这里插入图片描述

自定义布局

如果不希望通过布局管理器对容器进行布局, 也可以调用容器的 setLayout(null)方法, 将布局管理器取消。 在这种情况下, 程序必须调用容器中每个组件的setSize()和 setLocation()方法或者 setBounds()方法( 这个方法接收 4 个参数, 分别是左上角的 x、 y 坐标和组件的长、 宽), 为这些组件在容器中定位。

AWT事件处理与AWT绘图

事件处理机制
package com.test;
import java.awt.Frame ;
import java.awt.event.WindowListener;
import java.awt.Window; 
import java.awt.event.WindowEvent;
public class Test {
	public static void main(String[] args) {
		// 建立新窗体
		Frame f = new Frame("我的窗体!");
		// 设置窗体的宽和高
		f.setSize(400, 300);
		// 设置窗体的出现的位置
		f.setLocation(300, 200);
		// 设置窗体可见
		f.setVisible(true);
		// 为窗口组件注册监听器
		MyWindowListener mw = new MyWindowListener();
		f.addWindowListener(mw);
	}
}
// 创建MyWindowListener类实现WindowListener接口
class MyWindowListener implements WindowListener {
	// 监听器监听事件对象作出处理
	public void windowClosing(WindowEvent e) {
		Window window = e.getWindow();
		window.setVisible(false);
		// 释放窗口
		window.dispose();
	}
	public void windowActivated(WindowEvent e) {
	}
	public void windowClosed(WindowEvent e) {
	}
	public void windowDeactivated(WindowEvent e) {
	}
	public void windowDeiconified(WindowEvent e) {
	}
	public void windowIconified(WindowEvent e) {
	}
	public void windowOpened(WindowEvent e) {
	}
}

输出:
在这里插入图片描述

事件适配器

然而在程序中需要用到的只有 windowClosing()一个方法, 其他 6 个方法都是空实现, 没有发挥任何作用, 这样的代码编写明显是一种多余但又无法省略的工作。 针对这样的问题, JDK 提供了一些适配器类, 它们是监听器接口的默认实现类, 这些实现类中实现了接口的所有方法, 但方法中没有任何代码, 程序可以通过继承适配器类来达到实现监听器接口的目的。

package com.test;
import java.awt.Frame ;
import java.awt.Window; 
import java.awt.event.WindowAdapter; 
import java.awt.event.WindowEvent;
public class Test {
	public static void main(String[] args) {
		// 建立新窗体
		Frame f = new Frame("我的窗体!");
		// 设置窗体的宽和高
		f.setSize(400, 300);
		// 设置窗体的出现的位置
		f.setLocation(300, 200);
		// 设置窗体可见
		f.setVisible(true);
		// 为窗口组件注册监听器
		f.addWindowListener(new MyWindowListener());
	}
}

//继承WindowAdapter类,重写windowClosing()方法
class MyWindowListener extends WindowAdapter {
	public void windowClosing(WindowEvent e) {
		Window window = (Window) e.getComponent();
		window.dispose();
	}
}

输出:
在这里插入图片描述

常用事件
窗体事件

在应用程序中, 当对窗体事件进行处理时, 首先需要定义一个实现了 WindowListener 接口的类作为窗体监听器, 然后通过 addWindowListener()方法将窗体对象与窗体监听器绑定。

package com.test;
import java.awt.Frame ;
import java.awt.Window; 
import java.awt.event.WindowListener; 
import java.awt.event.WindowEvent;
public class Test {
	public static void main(String[] args) {
		final Frame f = new Frame("WindowEvent");
		f.setSize(400, 300);
		f.setLocation(300, 200);
		f.setVisible(true);
		// 使用内部类创建WindowListener实例对象,监听窗体事件
		f.addWindowListener(new WindowListener() {
			public void windowOpened(WindowEvent e) {
				System.out.println("windowOpened---窗体打开事件");
			}
			public void windowIconified(WindowEvent e) {
				System.out.println("windowIconified---窗体图标化事件");
			}
			public void windowDeiconified(WindowEvent e) {
				System.out.println("windowDeiconified---窗体取消图标化事件");
			}
			public void windowDeactivated(WindowEvent e) {
				System.out.println("windowDeactivated---窗体停用事件");
			}
			public void windowClosing(WindowEvent e) {
				System.out.println("windowClosing---窗体正在关闭事件");
				((Window) e.getComponent()).dispose();
			}
			public void windowClosed(WindowEvent e) {
				System.out.println("windowClosed---窗体关闭事件");
			}
			public void windowActivated(WindowEvent e) {
				System.out.println("windowActivated---窗体激活事件");
			}
		});
	}
}

输出:
windowClosing—窗体正在关闭事件
windowDeactivated—窗体停用事件
windowClosed—窗体关闭事件

鼠标事件

处理鼠标事件时, 首先需要实现 MouseListener 接口定义监听器( 也可以通过继承适配器 MouseAdapter类来实现), 然后调用 addMouseListener()方法将监听器绑定到事件源对象。

public class Test {
	public static void main(String[] args) {
		final Frame f = new Frame("WindowEvent");
		// 为窗口设置布局
		f.setLayout(new FlowLayout());
		f.setSize(300, 200);
		f.setLocation(300, 200);
		f.setVisible(true);
		Button but = new Button("Button"); // 创建按钮对象
		f.add(but); // 在窗口添加按钮组件
		// 为按钮添加鼠标事件监听器
		but.addMouseListener(new MouseListener() {
			public void mouseReleased(MouseEvent e) {
				System.out.println("mouseReleased-鼠标放开事件");
			}

			public void mousePressed(MouseEvent e) {
				System.out.println("mousePressed-鼠标按下事件");
			}

			public void mouseExited(MouseEvent e) {
				System.out.println("mouseExited—鼠标移出按钮区域事件");
			}

			public void mouseEntered(MouseEvent e) {
				System.out.println("mouseEntered—鼠标进入按钮区域事件");
			}

			public void mouseClicked(MouseEvent e) {
				System.out.println("mouseClicked-鼠标完成单击事件");
			}
		});
	}
}
键盘事件

JDK 中提供了一个 KeyEvent 类表示键盘事件, 处理 KeyEvent 事件的监听器对象需要实现 KeyListener 接口或者继承KeyAdapter 类。

import java.awt.event.KeyEvent;
public class Test {
	public static void main(String[] args) {
		Frame f = new Frame("KeyEvent");
		f.setLayout(new FlowLayout());
		f.setSize(400, 300);
		f.setLocation(300, 200);
		TextField tf = new TextField(30); // 创建文本框对象
		f.add(tf); // 在窗口中添加文本框组件
		f.setVisible(true);
		// 为文本框添加键盘事件监听器
		tf.addKeyListener(new KeyAdapter() {
			public void keyPressed(KeyEvent e) {
				int KeyCode = e.getKeyCode(); // 返回所按键对应的整数值
				String s = KeyEvent.getKeyText(KeyCode); // 返回按键的字符串描述
				System.out.print("输入的内容为:" + s + ",");
				System.out.println("对应的KeyCode为:" + KeyCode);
			}
		});
	}
}

动作事件

在 Java 中, 动作事件用 ActionEvent 类表示, 处理 ActionEvent 事件的监听器对象需要实现 ActionListener接口。 监听器对象在监听动作时, 不会像鼠标事件一样处理鼠标的移动和单击的细节, 而是处理类似于“按钮按下” 这样“有意义” 的事件。

class ComponentWithActionEvent extends JFrame implements ActionListener// 实现动作监视器接口
{// 创建一个窗口界面
	JButton button_up, button_down, button_first, button_last;// 声明所需的按钮组件
	JLabel label1, label2, label3;// 声明所需的JLabel组件
	JPanel panel;// 声明一个JPanel容器,用于图片的载入和显示
	CardLayout card;// 声明一个CardLayout布局管理器,用于组件的叠加存放

	public ComponentWithActionEvent() {
		button_up = new JButton("上一张");
		button_down = new JButton("下一张");
		button_first = new JButton("第一张");
		button_last = new JButton("最后一张");

		label1 = new JLabel();// 创建JLabel,用于装入图片
		label2 = new JLabel();
		label3 = new JLabel();
		label1.setIcon(new ImageIcon("1.png"));// 将图片加入label,实现图片的显示
		label2.setIcon(new ImageIcon("2.png"));
		label3.setIcon(new ImageIcon("3.png"));

		panel = new JPanel();// 创建一个JPanel容器,用于载入各个JLabel组件
		card = new CardLayout();// 将JPanel容器的布局管理器设为CardLayout,
		panel.setLayout(card);// 实现图片的逐一显示

		panel.add(label1);// 将各个JLabel组件加入到JPanel容器
		panel.add(label2);
		panel.add(label3);

		card.first(panel);
		add(panel, BorderLayout.CENTER);// 将JPanel容器加入到窗口的中间位置
		add(button_up, BorderLayout.WEST);// 将各个按钮组件加入到窗口的指定位置
		add(button_down, BorderLayout.EAST);
		add(button_first, BorderLayout.NORTH);
		add(button_last, BorderLayout.SOUTH);

		button_up.addActionListener(this);// 注册监视器。用当前对象this作监视器,
		button_down.addActionListener(this);// 因为当前对象所在的类实现了ActionEvent
		button_first.addActionListener(this);// 接口,所以它可以作监视器
		button_last.addActionListener(this);

		setTitle("动作事件示例");
		setSize(260, 260);
		setVisible(true);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}

	// actionPerformed是ActionEvent接口中的方法,必须定义
	// 当事件发生后,该方法就会被调用,并将事件对象传递给参数e
	public void actionPerformed(ActionEvent e) {// 一个监视器同时监视4个按钮,所以要判断是哪一个事件源产生的事件
		if (e.getSource() == button_up)// 监听up按钮,显示上一张图片
			card.previous(panel);
		else if (e.getSource() == button_down)// 监听down按钮,显示上一张图片
			card.next(panel);
		else if (e.getSource() == button_first)// 监听first按钮,显示第一张图片
			card.first(panel);
		if (e.getSource() == button_last)// 监听last按钮,显示最后一张图片
			card.last(panel);
	}
}

public class Test {
	public static void main(String[] args) {
		new ComponentWithActionEvent();
	}
}

选项事件

选项事件( ItemEvent) 类用于表示选项事件。产生 ItemEvent 事件的事件源有复选框( JCheckBox)、 下拉列表框( JComboBox)、 菜单项( JMenuItem)等。 例如, 当用户对复选框 JCheckBox 进行操作时, 当 JChenkBox 从未选中状态变成选中状态时就会触发改事件。

class FrameWithItemEvent extends JFrame implements ItemListener {// 定义一个窗口,继承并实现ItemListener接口
	JTextField text;
	JButton button;
	JCheckBox checkBox1, checkBox2, checkBox3;
	JRadioButton radio1, radio2;
	ButtonGroup group;
	JComboBox comBox;
	JTextArea area;

	public void display() {
		setLayout(new FlowLayout());

		add(new JLabel("文本框:"));
		text = new JTextField(10);
		add(text);
		add(new JLabel("按钮:"));
		button = new JButton("确定");
		add(button);

		add(new JLabel("选择框:"));
		checkBox1 = new JCheckBox("喜欢音乐");
		checkBox2 = new JCheckBox("喜欢旅游");
		checkBox3 = new JCheckBox("喜欢篮球");
		checkBox1.addItemListener(this);// 注册监听器,监听JcheckBox组件
		checkBox2.addItemListener(this);
		checkBox3.addItemListener(this);
		add(checkBox1);
		add(checkBox2);
		add(checkBox3);

		add(new JLabel("单选按钮:"));
		group = new ButtonGroup();
		radio1 = new JRadioButton("男");
		radio2 = new JRadioButton("女");
		group.add(radio1);
		group.add(radio2);
		add(radio1);
		add(radio2);

		add(new JLabel("下拉列表:"));
		comBox = new JComboBox();
		comBox.addItem("请选择");
		comBox.addItem("音乐天地");
		comBox.addItem("武术天地");
		comBox.addItem("象棋乐园");
		comBox.addItemListener(this);// 注册监听器,监听JComboBox组件
		add(comBox);

		add(new JLabel("文本区:"));
		area = new JTextArea(6, 12);
		add(new JScrollPane(area));

		setSize(300, 300);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}

	public void itemStateChanged(ItemEvent e) {// 重写itemStateChange方法,实现监听的处理
		if (e.getItem() == checkBox1) {// 如果监听到的对象是checkBox1,显示对象内容和选择状态
			String str = checkBox1.getText() + checkBox1.isSelected();
			area.append(str + "\n");
		} else if (e.getItemSelectable() == checkBox2) {// 如果监听到的对象是checkBox2,显示对象内容和选择状态
			String str = checkBox2.getText() + checkBox2.isSelected();
			area.append(str + "\n");
		} else if (e.getSource() == checkBox3) {// 如果监听到的对象是checkBox3,显示对象内容和选择状态
			String str = checkBox3.getText() + checkBox3.isSelected();
			area.append(str + "\n");
		} else if (e.getItemSelectable() == comBox) {// 如果监听到的对象是comBox,显示当前选择的内容
			if (e.getStateChange() == ItemEvent.SELECTED) {
				String str = comBox.getSelectedItem().toString();
				area.append(str + "\n");
			}
		}
	}
}

public class Test {
	public static void main(String[] args) {
		new FrameWithItemEvent().display();
	}
}

焦点事件

焦点事件( FocusEvent) 类用于表示焦点事件。每个 GUI 组件都能够作为 FocusEvent 焦点事件的事件源, 也就是每个组件在获得焦点或者失去焦点的时候都会产生焦点时间。

文档事件

文档事件( DocumentEvent) 接口用于处理文档事件。能够产生 javax.swing.event.DocumentEvent 事件的事件源有文本框( JTextField)、 密码框( JPasswordField)、文本区( JTextArea)。这些组件不能直接触发 DocumentEvent 事件, 而是由组件对象调用 getDocument()方法获取文本区维护文档, 这个维护文档可以触发 DocumentEvent 事件。

AWT绘图

很多 GUI 程序都需要在组件上绘制图形, 例如实现一个五子棋的小游戏, 就需要在组件上绘制棋盘和棋子。 在 java.awt 包中专门提供了 Graphics 类, 它相当于一个抽象的画笔, 其中提供了各种绘制图形的方法, 使用 Graphics 类的方法就可以在组件上绘制图形

package com.test;
import java.awt.Frame ;
import java.awt.Panel;
import java.awt.Graphics;
import java.awt.Font;
import java.awt.Color;
import java.util.Random;
public class Test {
	public static void main(String[] args) {
		final Frame frame = new Frame("验证码"); // 创建Frame对象
		final Panel panel = new MyPanel(); // 创建Panel对象
		frame.add(panel);
		frame.setSize(200, 100);
		// 将Frame窗口居中
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);
	}
}

class MyPanel extends Panel {
	public void paint(Graphics g) {
		int width = 160; // 定义验证码图片的宽度
		int height = 40; // 定义验证码图片的高度
		g.setColor(Color.LIGHT_GRAY); // 设置上下文颜色
		g.fillRect(0, 0, width, height); // 填充验证码背景
		g.setColor(Color.BLACK); // 设置上下文颜色
		g.drawRect(0, 0, width - 1, height - 1); // 绘制边框
		// 绘制干扰点
		Random r = new Random();
		for (int i = 0; i < 100; i++) {
			int x = r.nextInt(width) - 2;
			int y = r.nextInt(height) - 2;
			g.drawOval(x, y, 2, 2);
		}
		g.setFont(new Font("黑体", Font.BOLD, 30)); // 设置验证码字体
		g.setColor(Color.BLUE); // 设置验证码颜色
		// 产生随机验证码
		char[] chars = ("0123456789abcdefghijkmnopqrstuvwxyzABCDEFG"
				+ "HIJKLMNPQRSTUVWXYZ").toCharArray();
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < 4; i++) {
			int pos = r.nextInt(chars.length);
			char c = chars[pos];
			sb.append(c + " ");
		}
		g.drawString(sb.toString(), 20, 30); // 写入验证码
	}
}

输出:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

身影王座

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值