自己绘制图形的方法,思路就是自己创建出有绘图功能的widget
,并把widget
放在frame
上,将frame
设置大小并显示出来即可。
操作上,继承JPanel
类,创建子类,并覆盖掉paintComponent()
这个方法即可。
你想绘制出什么样的图,只需要在paintComponent()
方法里写出对应方法就可以实现。并且paintComponent()
方法不需要自己调用,当你的panel所处的frame显示的时候,paintComponent()
方法就会被系统调用。
import javax.swing.*;
import java.awt.*;
public class MyDrawPanel extends JPanel {
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
GradientPaint gradientPaint = new GradientPaint(70, 70, Color.RED, 150, 150, Color.PINK);
g2d.setPaint(gradientPaint);
g2d.fillOval(70, 70, 100, 100);
}
public static void main(String[] args) {
MyDrawPanel myDrawPanel = new MyDrawPanel();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(myDrawPanel); //将自己的绘图组件加到frame上去
frame.setSize(200, 200);
frame.setVisible(true);
}
}
paintComponent()
方法声明的参数g
是Graphics
类型的,但注意,这并不代表g
就一定是Graphics
类型的,它也有可能是Graphics
的子类。这是因为多态的缘故。而事实上,的确是这样的。
public void paintComponent()(Graphics g){}
由g参数所引用的对象实际上是类Graphics2D的实例。·
这就限制了Graphics2D
可以做的事情,因为那些在Graphics2D
引用上能用的方法,在Graphics
引用上却不能做了,这就是多态带来的问题。编辑器是会根据引用的类型而不是实际对象来决定你能够调用哪些方法。
也就是说,如果你要使用Graphics2D
特有的方法,就不能直接使用参数g
了,而要做强制转换:
Graphics2D g2d = (Graphics2D) g;
下面的程序是将按钮和绘图组件这两个widget
放在一个frame
上,通过BorderLayout
布局管理,随机组合图形的RGB,点击按钮时会更改图形颜色。可以当做参考。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ChangeColor implements ActionListener {
JFrame jFrame;
public static void main(String[] args) {
ChangeColor changeColor = new ChangeColor();
changeColor.changeIt();
}
private void changeIt() {
jFrame = new JFrame();
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton jButton = new JButton("click me to change color");
jButton.addActionListener(this); //向按钮注册事件
MyDrawPanel myDrawPanel = new MyDrawPanel(); //创建我的绘图组件
//将按钮放置在界面的下部(南部)
jFrame.getContentPane().add(BorderLayout.SOUTH, jButton);
//将绘图组件放在界面中心
jFrame.getContentPane().add(BorderLayout.CENTER, myDrawPanel);
jFrame.setSize(600, 600);
jFrame.setVisible(true); //设置frame可见
}
@Override
public void actionPerformed(ActionEvent e) {
jFrame.repaint(); //重绘图形
}
}
class MyDrawPanel extends JPanel {
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
int red = (int) (Math.random() * 255); //三原色RGB
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 gradientPaint = new GradientPaint(70, 70, startColor, 150, 150, endColor);
g2d.setPaint(gradientPaint);
g2d.fillOval(70, 70, 100, 100);
}
}
上面提到的是只要一个按钮的情况,那两个按钮怎么实现监听呢?多个按钮呢?
这种情况要用到内部类。简言之,内部类就是一个类嵌套在了另一个类的内部。如下,MyInnerClass
就是一个内部类。
class MyOuterClass{
class MyInnerClass{
void go(){
}
}
}
内部类对外部类好像有一张通行证一样,能够自由存取外部类的内容,即便是private
的。内部类除了和外部类没有差别以外,还多了特殊的存取权。
而有特权就得遵守一定的条件。比如内部类并不是可以存取任意一个外部类的实例的内容。因为内部类的实例一定会绑在外部类的实例上,所以内部类只能存取它所属的那一个外部类。
下面就是实现两个按钮监听的程序
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ChangeColor {
JFrame jFrame;
JLabel jLabel;
private void changeIt() {
jFrame = new JFrame();
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton colorButton = new JButton("click me to change color");
JButton labelButton = new JButton("click me to change label");
jLabel = new JLabel("I'm a label"); //初始化一个label
//向改变颜色的按钮注册事件
colorButton.addActionListener(new ColorChange());
//向改变label文字内容的按钮注册事件
labelButton.addActionListener(new LableChange());
MyDrawPanel myDrawPanel = new MyDrawPanel(); //创建我的绘图组件
//将改变颜色的按钮放置在界面的下部(南部)
jFrame.getContentPane().add(BorderLayout.SOUTH, colorButton);
//将改变label内容的按钮放置在界面的右边(东部)
jFrame.getContentPane().add(BorderLayout.EAST, labelButton);
//将绘图组件放在界面中心
jFrame.getContentPane().add(BorderLayout.CENTER, myDrawPanel);
//将label放在界面的左边(西部)
jFrame.getContentPane().add(BorderLayout.WEST, jLabel);
jFrame.setSize(600, 600);
jFrame.setVisible(true); //设置frame可见
}
//两个内部类
class ColorChange implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
jFrame.repaint();
}
}
class LableChange implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
jLabel.setText("changed!");
}
}
public static void main(String[] args) {
ChangeColor changeColor = new ChangeColor();
changeColor.changeIt();
}
}
class MyDrawPanel extends JPanel {
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
int red = (int) (Math.random() * 255); //三原色RGB
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 gradientPaint = new GradientPaint(70, 70, startColor, 150, 150, endColor);
g2d.setPaint(gradientPaint);
g2d.fillOval(70, 70, 100, 100);
}
}