JFrame
JFrame是个代表屏幕上window的对象。可以把button、checkbox、text字段等接口放在window上面。标准的menu也可以加到上面。
import javax.swing.*;
public class SimpleGui1 {
public static void main(String[] args) {
JFrame frame = new JFrame(); //创建frame
JButton button = new JButton("click me"); //创建button
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //这一行程序会在window关闭时结束程序
frame.getContentPane().add(button);
frame.setSize(300, 300); //设定frame大小
frame.setVisible(true); //显示frame
}
}
实现按钮功能
实现按钮功能:
- 按钮要知道它的作用。
- 按钮要在按键事件发生时调用执行功能的方法。
取得用户的事件
在Java中,取得处理用户操作事件的过程称为even-handling。Java中有许多不同的事件类型,大多数都与GUI上用户的操作有关。如果用户按下了按钮,就会产生事件。
监听
如果想要知道按钮的事件,就要监听事件的接口。
监听接口是介于监听和事件源间的桥梁。
Swing的GUI组件是事件的来源。以Java的术语说,事件来源是个可以将用户操作(点击鼠标、关闭窗口等)转换成事件的对象。对Java而言,事件几乎都是以对象来表示(事件类对象)。
事件源(例如按钮)会在用户做出相关动作时(按下按钮)产生事件对象。你的程序在大多数情况下是事件的接受方而不是创建方。也就是说,你会花较多的时间当监听者而不是事件来源。
每个事件类型都有相对应的监听者接口,想要接收MuoseEvent的话就实现Mouse Listener这个接口。记得接口的规则:要实现接口就得声明这件事,这代表你必须把接口中所有方法都实现出来。
监听和事件源的沟通
监听
如果类想要知道按钮的ActionEvent,就要实现ActionListener这个接口。按钮需要知道你关注的部分,因此要通过调用addActionListener(this)并传入ActionListener的引用(下面的例子里就是你自己的这个程序,所以用this)来向按钮注册。按钮会在该事件发生时调用该接口上的方法。作为一个ActionListener,编译器会确保你实现此接口的actionPerformed()。
事件源
按钮是ActionEvent的来源,因此它必须要知道有哪些对象是需要事件通知的。此按钮有个addActionListener()方法可以提供对事件有兴趣的对象(listener)一种表达此兴趣的方法。
当按钮的addActionListener()方法被调用是(因为某个listener的调用),它的参数会被按钮存到清单中。当用户按下按钮时,按钮会通过调用清单上的每个监听的actionPerformed()来启动事件。
取得按钮的ActionEvent
- 实现ActionListener这个接口。
- 向按钮注册(告诉它你要监听事件)。
- 定义事件处理方法(实现接口的方法)。
import javax.swing.*;
import java.awt.event.*;
public class SimpleGui1B implements ActionListener {
JButton button;
public static void main(String[] args) {
SimpleGui1B gui = new SimpleGui1B();
gui.go();
}
public void go() {
JFrame frame = new JFrame();
button = new JButton("Click me");
button.addActionListener(this); //向按钮注册
frame.getContentPane().add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 300);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent event) { //实现接口中的方法,真正处理事件的方法
button.setText("I've been clicked");
}
}
图形
在GUI上加东西的3种方法:
- 在frame上放置widget:
加上按钮、窗体、radio button 等。 - 在widget上绘制2D图形:
使用graphics对象来绘制图形。 - 在widget上放置JPEG图
创建绘图组件
如果要在屏幕上放上自己的图形,最好的方式是自己创建出有绘图功能的widget。把它放在frame上,就像按钮或其他widget一样,不同之处是它会按照你所要的方式绘制。
创建Jpanel的子类并覆盖掉paintComponent()这个方法
所有绘图程序代码都在paintComponent()里面。当你的panel所处的frame显示的时候,paintComponent()就会被调用。用户不能自己调用这个方法!它的参数是个跟实际屏幕有关的Graphics对象,用户无法取得这个对象,必须交由系统来交给你。然而,还是可以调用repaint()类要求系统重新绘制显示装置,然后产生paintComponent()调用。
import java.awt.*;
import javax.swing.*;
public class MyDrawPanel extends JPanel {//创建JPanel的子类
public void paintComponent(Graphics g) {//只能由系统调用
g.setColor(Color.blue);
g.fillRect(20, 50, 100, 100);
}
public static void main (String[] args) {
JFrame frame = new JFrame(); //创建frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyDrawPanel s = new MyDrawPanel();
frame.getContentPane().add(s);
frame.setSize(300, 300);
frame.setVisible(true);
}
}
其他在paintComponent()中可以做的事情
显示JPEG
import java.awt.*;
import javax.swing.*;
public class MyDrawPanel extends JPanel {//创建JPanel的子类
public void paintComponent(Graphics g) {//只能由系统调用
Image image = new ImageIcon("224888289124380709.jpg").getImage();//注意这里的根路径是project目录
g.drawImage(image, 3, 4, this);
}
public static void main (String[] args) {
JFrame frame = new JFrame(); //创建frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyDrawPanel s = new MyDrawPanel();
frame.getContentPane().add(s);
frame.setSize(300, 300);
frame.setVisible(true);
}
}
在黑色背景上画随机色彩的圆圈
import java.awt.*;
import javax.swing.*;
public class MyDrawPanel extends JPanel {//创建JPanel的子类
public void paintComponent(Graphics g) {//只能由系统调用
g.fillRect(0, 0, this.getWidth(), this.getHeight());
int red = (int) (Math.random() * 255);
int green = (int) (Math.random() * 255);
int blue = (int) (Math.random() * 255);
Color randomColor = new Color(red, green ,blue); //随机颜色
g.setColor(randomColor); //设定画的颜色
g.fillOval(400, 400, 200, 200);
}
public static void main (String[] args) {
JFrame frame = new JFrame(); //创建frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyDrawPanel s = new MyDrawPanel();
frame.getContentPane().add(s);
frame.setSize(300, 300);
frame.setVisible(true);
}
}
使用Graphics2D对象
paintComponent()的参数被声明为Graphics类型:
public void paintComponent(Graphics g)
因此参数g是个Graphics对象,由于多态,g也有可能是Graphics的子类。事实上,由g参数所引用的对象实际上是个Graphics2D的实例。
如果要调用Graphics2D类的方法,就不能直接使用g参数。要将其转换成Graphics2D变量:
Graphics2D g2d = (Graphics2D) g;
Graphics2D的方法更多:
import java.awt.*;
import javax.swing.*;
public class MyDrawPanel extends JPanel {//创建JPanel的子类
public void paintComponent(Graphics g) {//只能由系统调用
Graphics2D g2d = (Graphics2D) g;
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(400,400, startColor,600,600, endColor);//两点之间坐标渐变
g2d.setPaint(gradient);
g2d.fillOval(400, 400, 200, 200);
}
public static void main (String[] args) {
JFrame frame = new JFrame(); //创建frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyDrawPanel s = new MyDrawPanel();
frame.getContentPane().add(s);
frame.setSize(800, 800);
frame.setVisible(true);
}
}
在获得事件时绘制图形
GUI布局:
frame默认有5个区域可以安置widget:
按下按钮圆圈就会改变颜色
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class MySimpleGui3C implements ActionListener {
JFrame frame;
public static void main(String[] args) {
MySimpleGui3C gui = new MySimpleGui3C();
gui.go();
}
public void go() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton button = new JButton("change colors");
button.addActionListener(this);
MyDrawPanel s = new MyDrawPanel();
frame.getContentPane().add(BorderLayout.SOUTH, button);//两个参数的add方法可以指定位置
frame.getContentPane().add(BorderLayout.CENTER,s);
frame.setSize(800, 800);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent event) {
frame.repaint();
}
}
内部类
一个类可以嵌套在另一个类的内部。内部类可以使用外部所有的方法与变量,就算是private的也一样。
利用内部类实现两个按钮的程序
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class TwoButton {
JFrame frame;
JLabel label; //必须放在方法以外,否则是局部变量不能用
public static void main(String[] args) {
TwoButton gui = new TwoButton();
gui.go();
}
public void go() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton labelButton = new JButton("change label");
labelButton.addActionListener(new LabelListener());
JButton colorButton = new JButton("change color");
colorButton.addActionListener(new ColorListener());
label = new JLabel("I'm a label");
MyDrawPanel drawPanel = new MyDrawPanel();
frame.getContentPane().add(BorderLayout.SOUTH, colorButton);
frame.getContentPane().add(BorderLayout.EAST, labelButton);
frame.getContentPane().add(BorderLayout.CENTER, drawPanel);
frame.getContentPane().add(BorderLayout.WEST, label);
frame.setSize(800, 800);
frame.setVisible(true);
}
class LabelListener implements ActionListener {//内部类,可以调用label
public void actionPerformed(ActionEvent event) {
label.setText("Ouch!");
}
}
class ColorListener implements ActionListener {//内部类,可以调用frame
public void actionPerformed(ActionEvent event) {
frame.repaint();
}
}
}
以内部类执行动画效果
import javax.swing.*;
import java.awt.*;
public class SimpleAnimation {
int x = 70;
int y = 70;
public static void main(String[] args) {
SimpleAnimation gui = new SimpleAnimation();
gui.go();
}
public void go() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyDrawPanel drawPanel = new MyDrawPanel();
frame.getContentPane().add(drawPanel);
frame.setSize(800, 800);
frame.setVisible(true);
for (int i = 0; i < 130; i++) {
x++;//递增坐标值
y++;//递增坐标值
drawPanel.repaint();//重新绘制
try {
Thread.sleep(50);//加上延迟放缓过程
} catch(Exception ex) { }
}
}
class MyDrawPanel extends JPanel {
public void paintComponent(Graphics g) {
//去除痕迹
g.setColor(Color.WHITE);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.green);
g.fillOval(x, y, 40, 40);//x,y是椭圆左上角坐标,40,40是高度和宽度
}
}
}
这样使用内部类可以让外部类实现无法继承的子类的方法。