本博文主要讲解如何使用Graphics类绘制字符串、直线、矩形、椭圆、弧形、多边形和图像,以及如何开发可重用的GUI组件。
要绘图,首先要确定在哪里绘图。每个组件都有自己的坐标系,原点(0,0)在组件的左上角。X坐标向右增加,y坐标向下增加。
注意:Java的坐标系和传统的坐标系不同。
Graphics类中提供了绘制字符串、直线、矩形、椭圆、弧形、多边形和折线段的方法。可以将GUI组件看作一张纸,而将Graphics看做铅笔或画刷。可以应用Graphics类中的方法在GUI组件上进行绘画。
Graphics类是一个提供和设备无关的图形界面抽象类,它可以在不同平台的屏幕上显示图形和图像。任何时候需要显示组件,JVM都会自动在本地平台上为该组件创建一个Graphics对象,然后传递这个对象来调用paintComponet方法来显示图画。
paintComponent方法的签名如下:
protected voidpaintComponent(Graphics g);
这个定义在JComponent类中的方法是在第一次显示组件或重新显示组件的时候调用的。
为了在组件上绘图,需要定义一个扩展JPanel类,并且覆盖它的paintComponent方法来表明绘制什么。
Graphics如下UML类图所示:
JVM调用paintComponet在组件上进行绘画。用户永远都不要直接调用paintComponet。因为这个原因,将paintComponet的可见性设置为protected就足够了。
面板是不可兼得,它们用作一个小型容器,这个容器将组件进行分组获得所需要的布局。JPanel的另一个重要应用是绘画。可以在任何一个Swing GUI组件上绘画,但是通常应该使用JPanel作为画布在其上绘画。
如果用JLabel代替下面图片代码中的JPanel,程序依然可以工作,但不推荐这样做。因为JLabel设计为创建一个标签,而不是为了绘画。为保持一致性,一般通过JPanel的子类来定义画布类。
提示:一些其他的方法是通过JComponent的子类来定义画布,出现的问题是如果要在画布上设置背景色,就必须写绘制背景色的代码。一个简单的setBackground(Color color)方法是不能在JComponent中设置背景颜色的。
范例一:Graphics初步演示
运行效果如图所示:
实现的源代码如下所示:(本片博文的import是一步到位的,即可能没用到的也import了)
package Blog;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Calendar;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class blogTryProject {
public static void main(String[] args){
TestPaintComponent tpc = new TestPaintComponent();
tpc.main(args);
}
}
//Graphics初步演示
class TestPaintComponent extends JFrame{
public TestPaintComponent(){
add(new NewPanel());
}
public static void main(String[]args){
TestPaintComponent frame = new TestPaintComponent();
frame.setTitle("TestPaintComponent");
frame.setSize(400,400);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
class NewPanel extends JPanel{
protected void paintComponent(java.awt.Graphics g){
super.paintComponent(g);
g.drawLine(0, 0, 50, 50);//直线段
g.drawString("Banner", 40, 40);//在指定位置画字符串
g.drawRect(20, 20, 50, 60);//矩形
g.fillRect(80, 90, 50, 60);//填充矩形
g.drawRoundRect(150, 200, 50, 60, 10, 20);//带圆角的矩形
g.fillRoundRect(150, 20, 50, 60, 10, 20);
g.draw3DRect(150, 300, 50, 60, true);//3D矩形凸起
g.draw3DRect(150, 100, 50, 60, false);//3D矩形凹陷
g.drawOval(300, 100, 50, 70);//椭圆
}
}
运行效果如图所示:
实现的源代码如下所示:
package Blog;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Calendar;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class blogTryProject {
public static void main(String[] args){
TestFigurePanel tfp = new TestFigurePanel();
tfp.main(args);
}
}
//测试FigurePanel的程序
class TestFigurePanel extends JFrame{
public TestFigurePanel(){
setLayout(new java.awt.GridLayout(2,3,5,5));
add(new FigurePanel(FigurePanel.LINE));
add(new FigurePanel(FigurePanel.RECTANGLE));
add(new FigurePanel(FigurePanel.ROUND_RECTANGLE));
add(new FigurePanel(FigurePanel.OVAL));
add(new FigurePanel(FigurePanel.RECTANGLE,true));
add(new FigurePanel(FigurePanel.ROUND_RECTANGLE,true));
}
public static void main(String[]args){
TestFigurePanel frame = new TestFigurePanel();
frame.setSize(400,200);
frame.setTitle("TestFigurePanel");
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
//FigurePanel类的实现
class FigurePanel extends JPanel{
public static final int LINE = 1;
public static final int RECTANGLE = 2;
public static final int ROUND_RECTANGLE = 3;
public static final int OVAL = 4;
private int type = 1;
private boolean filled = false;
public FigurePanel(){
}
public FigurePanel(int type){
this.type = type;
}
public FigurePanel(int type,boolean filled){
this.type = type;
this.filled = filled;
}
protected void paintComponent(java.awt.Graphics g){
super.paintComponent(g);
int width = getWidth();
int height = getHeight();
switch(type){
case LINE://画出交叉的两条直线段
g.setColor(java.awt.Color.BLACK);
g.drawLine(10, 10, width - 10, height - 10);
g.drawLine(width - 10, 10, 10, height - 10);
break;
case RECTANGLE://画矩形
g.setColor(java.awt.Color.BLUE);
if(filled)
g.fillRect((int)(0.1*width), (int)(0.1*height),
(int)(0.8*width), (int)(0.8*height));
else
g.drawRect((int)(0.1*width), (int)(0.1*height),
(int)(0.8*width), (int)(0.8*height));
break;
case ROUND_RECTANGLE://画圆角矩形
g.setColor(java.awt.Color.RED);
if(filled)
g.fillRoundRect((int)(0.1*width), (int)(0.1*height),
(int)(0.8*width), (int)(0.8*height), 20, 20);
else
g.drawRoundRect((int)(0.1*width), (int)(0.1*height),
(int)(0.8*width), (int)(0.8*height), 20, 20);
break;
case OVAL://画椭圆
g.setColor(java.awt.Color.GREEN);
if(filled)
g.fillOval((int)(0.1*width), (int)(0.1*height),
(int)(0.8*width), (int)(0.8*height));
else
g.drawOval((int)(0.1*width), (int)(0.1*height),
(int)(0.8*width), (int)(0.8*height));
}
}
public void setType(int type){
this.type = type;
repaint();
}
public int getType(){
return type;
}
public void setFilled(boolean filled){
this.filled = filled;
repaint();
}
public boolean isFilled(){
return filled;
}
public java.awt.Dimension getPreferredSize(){
return new java.awt.Dimension(80,80);
}
}
运行效果如图所示:
package Blog;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Calendar;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class blogTryProject {
public static void main(String[] args){
DrawArcs da = new DrawArcs();
da.main(args);
}
}
//绘制弧形
class DrawArcs extends JFrame{
public DrawArcs(){
setTitle("DrawArcs");
add(new ArcsPanel());
}
public static void main(String[]args){
DrawArcs frame = new DrawArcs();
frame.setSize(250,300);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
class ArcsPanel extends JPanel{
protected void paintComponent(java.awt.Graphics g){
super.paintComponent(g);
int xCenter = getWidth() / 2;
int yCenter = getHeight() / 2;
int radius = (int)(Math.min(getWidth(), getHeight())*0.4);
int x = xCenter - radius;
int y = yCenter - radius;
g.fillArc(x, y, 2*radius, 2*radius, 0, 30);
g.fillArc(x, y, 2*radius, 2*radius, 90, 30);
g.fillArc(x, y, 2*radius, 2*radius, 180, 30);
g.fillArc(x, y, 2*radius, 2*radius, 270, 30);
}
}
范例四:绘制多边形和折线段
运行效果如图所示:
实现的源代码如下所示:
package Blog;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Calendar;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class blogTryProject {
public static void main(String[] args){
DrawPolygon dp = new DrawPolygon();
dp.main(args);
}
}
//绘制多边形和折线段
class DrawPolygon extends JFrame{
public DrawPolygon(){
setTitle("DrawPolygon");
add(new PolygonsPanel());
}
public static void main(String[]args){
DrawPolygon frame = new DrawPolygon();
frame.setSize(200,250);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
class PolygonsPanel extends JPanel{
protected void paintComponent(java.awt.Graphics g){
super.paintComponent(g);
int xCenter = getWidth() / 2;
int yCenter = getHeight() / 2;
int radius = (int)(Math.min(getWidth(), getHeight())*0.4);
java.awt.Polygon polygon = new java.awt.Polygon();
polygon.addPoint(xCenter+radius, yCenter);
polygon.addPoint((int)(xCenter+radius*Math.cos(2*Math.PI/6)),
(int)(yCenter-radius*Math.sin(2*Math.PI/6)));
polygon.addPoint((int)(xCenter+radius*Math.cos(2*2*Math.PI/6)),
(int)(yCenter-radius*Math.sin(2*2*Math.PI/6)));
polygon.addPoint((int)(xCenter+radius*Math.cos(3*2*Math.PI/6)),
(int)(yCenter-radius*Math.sin(3*2*Math.PI/6)));
polygon.addPoint((int)(xCenter+radius*Math.cos(4*2*Math.PI/6)),
(int)(yCenter-radius*Math.sin(4*2*Math.PI/6)));
polygon.addPoint((int)(xCenter+radius*Math.cos(5*2*Math.PI/6)),
(int)(yCenter-radius*Math.sin(5*2*Math.PI/6)));
g.drawPolygon(polygon);
int[] x = {40,70,60,45,20};
int[] y = {20,40,80,45,60};
g.drawPolyline(x, y, x.length);
}
}
范例五:居中显示字符串
运行效果如图所示:
实现的源代码如下所示:
package Blog;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Calendar;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.Font;
public class blogTryProject {
public static void main(String[] args){
TestCenterMessage tcm = new TestCenterMessage();
tcm.main(args);
}
}
//FontMetrics居中显示字符串
class TestCenterMessage extends JFrame{
public TestCenterMessage(){
CenterMessage messagePanel = new CenterMessage();
add(messagePanel);
messagePanel.setBackground(Color.WHITE);
messagePanel.setFont(new Font("Californian FB",Font.BOLD,30));
}
public static void main(String[]args){
TestCenterMessage frame = new TestCenterMessage();
frame.setTitle("居中显示字符串");
frame.setSize(300,150);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
class CenterMessage extends JPanel{
protected void paintComponent(java.awt.Graphics g){
super.paintComponent(g);
java.awt.FontMetrics fm = g.getFontMetrics();
int stringWidth = fm.stringWidth("Welcome to Java");
int stringAscent = fm.getAscent();
int xCoordinate = getWidth()/2 - stringWidth/2;
int yCoordiante = getHeight()/2 + stringAscent/2;
g.drawString("Welcome to Java", xCoordinate, yCoordiante);
}
}
范例六:MessagePanel类的实现
运行的效果如图所示:
实现的源代码如下所示:
package Blog;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Calendar;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.Font;
import java.awt.*;
public class blogTryProject {
public static void main(String[] args){
TestMessagePanel tmp = new TestMessagePanel();
tmp.main(args);
}
}
//MessagePanel类的测试
class TestMessagePanel extends JFrame{
public TestMessagePanel(){
MessagePanel messagePanel1 = new MessagePanel("Welcome to Java");
MessagePanel messagePanel2 = new MessagePanel("Java is fun");
MessagePanel messagePanel3 = new MessagePanel("Java is cool");
MessagePanel messagePanel4 = new MessagePanel("I Love Java");
messagePanel1.setFont(new Font("SansSerif",Font.ITALIC,20));
messagePanel2.setFont(new Font("Courier",Font.BOLD,20));
messagePanel3.setFont(new Font("Times",Font.ITALIC,20));
messagePanel4.setFont(new Font("Californian FB",Font.PLAIN,20));
messagePanel1.setBackground(Color.RED);
messagePanel2.setBackground(Color.CYAN);
messagePanel3.setBackground(Color.GREEN);
messagePanel4.setBackground(Color.WHITE);
messagePanel1.setCentered(true);
setLayout(new GridLayout(2,2));
add(messagePanel1);
add(messagePanel2);
add(messagePanel3);
add(messagePanel4);
}
public static void main(String[]args){
TestMessagePanel frame = new TestMessagePanel();
frame.setSize(400,200);
frame.setTitle("TestMessagePanel");
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
//MessagePanel的实现
class MessagePanel extends JPanel{
private String message = "Welcom to Java";
private int xCoordinate = 20;
private int yCoordinate = 20;
private boolean centered;
private int interval = 10;
public MessagePanel(){
}
public MessagePanel(String message){
this.message = message;
}
public String getMessage(){
return message;
}
public void setMessage(String message){
this.message = message;
repaint();
}
public int getXCoordinate(){
return xCoordinate;
}
public void setXCoordinate(int x){
this.xCoordinate = x;
repaint();
}
public void setYCoordinate(int y){
this.yCoordinate = y;
repaint();
}
public int getYCoordinate(){
return yCoordinate;
}
public boolean isCentered(){
return centered;
}
public void setCentered(boolean centered){
this.centered = centered;
repaint();
}
public int getInterval(){
return interval;
}
public void setInterval(){
this.interval = interval;
repaint();
}
protected void paintComponent(java.awt.Graphics g){
super.paintComponent(g);
if(centered){
FontMetrics fm = g.getFontMetrics();
int stringWidth = fm.stringWidth(message);
int stringAscent = fm.getAscent();
xCoordinate = getWidth()/2 - stringWidth/2;
yCoordinate = getHeight()/2 + stringAscent/2;
}
g.drawString(message, xCoordinate, yCoordinate);
}
public void moveLeft(){
xCoordinate -= interval;
repaint();
}
public void moveRight(){
xCoordinate += interval;
repaint();
}
public void moveUp(){
yCoordinate -= interval;
repaint();
}
public void moveDown(){
yCoordinate += interval;
repaint();
}
public Dimension getPreferredSize(){
return new Dimension(200,30);
}
}
范例七:StillClock类的实现。后续博文改进这个代码,实现实时显示时间,并考虑将界面美化。
运行效果如图所示:
实现的源代码如下所示:
package Blog;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Calendar;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.*;
public class blogTryProject {
public static void main(String[] args){
TestClock tc = new TestClock();
tc.main(args);
}
}
//StillClock类的测试
class TestClock extends JFrame{
public TestClock(){
StillClock clock = new StillClock();
MessagePanel messagePanel = new MessagePanel(clock.getHour()+
":"+clock.getMinute()+":"+clock.getSecond());
messagePanel.setCentered(true);
messagePanel.setForeground(Color.BLUE);
messagePanel.setFont(new Font("Courier",Font.BOLD,16));
add(clock);
add(messagePanel,BorderLayout.SOUTH);
}
public static void main(String[]args){
TestClock frame = new TestClock();
frame.setTitle("TestClock");
frame.setSize(300,350);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
//StillClock类的实现
class StillClock extends JPanel{
private int hour;
private int minute;
private int second;
public StillClock(){
setCurrentTime();
}
public StillClock(int hour,int minute,int second){
this.hour = hour;
this.minute = minute;
this.second = second;
}
public int getHour(){
return hour;
}
public void setHour(int hour){
this.hour = hour;
repaint();
}
public int getMinute(){
return minute;
}
public void setMinute(int minute){
this.minute = minute;
repaint();
}
public int getSecond(){
return second;
}
public void setSecond(int second){
this.second = second;
repaint();
}
protected void paintComponent(Graphics g){
super.paintComponent(g);
int clockRadius = (int)(Math.min(getWidth(), getHeight())*0.8*0.5);
int xCenter = getWidth()/2;
int yCenter = getHeight()/2;
g.setColor(Color.BLACK);
g.drawOval(xCenter - clockRadius, yCenter - clockRadius,
2*clockRadius, 2*clockRadius);
g.drawString("12",xCenter-5,yCenter-clockRadius+12);
g.drawString("9",xCenter-clockRadius+3,yCenter+5);
g.drawString("3",xCenter+clockRadius-10,yCenter+3);
g.drawString("6",xCenter-3,yCenter+clockRadius-3);
int sLength = (int)(clockRadius*0.8);
int xSecond = (int)(xCenter+sLength*Math.sin(second*(2*Math.PI/60)));
int ySecond = (int)(yCenter-sLength*Math.cos(second*(2*Math.PI/60)));
g.setColor(Color.RED);
g.drawLine(xCenter, yCenter, xSecond, ySecond);
int mLength = (int)(clockRadius*0.65);
int xMinute = (int)(xCenter+mLength*Math.sin(minute*(2*Math.PI/60)));
int yMinute = (int)(yCenter-mLength*Math.cos(minute*(2*Math.PI/60)));
g.setColor(Color.BLUE);
g.drawLine(xCenter, yCenter, xMinute, yMinute);
int hLength = (int)(clockRadius*0.5);
int xHour = (int)(xCenter+hLength*Math.sin((hour%12+minute/60.0)*(2*Math.PI/12)));
int yHour = (int)(yCenter-hLength*Math.cos((hour%12+minute/60.0)*(2*Math.PI/12)));
g.setColor(Color.GREEN);
g.drawLine(xCenter, yCenter, xHour, yHour);
}
public void setCurrentTime(){
java.util.Calendar calendar = new java.util.GregorianCalendar();
this.hour = calendar.get(Calendar.HOUR_OF_DAY);
this.minute = calendar.get(Calendar.MINUTE);
this.second = calendar.get(Calendar.SECOND);
}
public Dimension getPreferredSize(){
return new Dimension(200,200);
}
}
//MessagePanel的实现
class MessagePanel extends JPanel{
private String message = "Welcom to Java";
private int xCoordinate = 20;
private int yCoordinate = 20;
private boolean centered;
private int interval = 10;
public MessagePanel(){
}
public MessagePanel(String message){
this.message = message;
}
public String getMessage(){
return message;
}
public void setMessage(String message){
this.message = message;
repaint();
}
public int getXCoordinate(){
return xCoordinate;
}
public void setXCoordinate(int x){
this.xCoordinate = x;
repaint();
}
public void setYCoordinate(int y){
this.yCoordinate = y;
repaint();
}
public int getYCoordinate(){
return yCoordinate;
}
public boolean isCentered(){
return centered;
}
public void setCentered(boolean centered){
this.centered = centered;
repaint();
}
public int getInterval(){
return interval;
}
public void setInterval(){
this.interval = interval;
repaint();
}
protected void paintComponent(java.awt.Graphics g){
super.paintComponent(g);
if(centered){
FontMetrics fm = g.getFontMetrics();
int stringWidth = fm.stringWidth(message);
int stringAscent = fm.getAscent();
xCoordinate = getWidth()/2 - stringWidth/2;
yCoordinate = getHeight()/2 + stringAscent/2;
}
g.drawString(message, xCoordinate, yCoordinate);
}
public void moveLeft(){
xCoordinate -= interval;
repaint();
}
public void moveRight(){
xCoordinate += interval;
repaint();
}
public void moveUp(){
yCoordinate -= interval;
repaint();
}
public void moveDown(){
yCoordinate += interval;
repaint();
}
public Dimension getPreferredSize(){
return new Dimension(200,30);
}
}
范例八:显示图像范例
运行效果如图所示:
实现的原代码如下所示:
package Blog;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Calendar;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.*;
import java.awt.*;
public class blogTryProject {
public static void main(String[] args){
DisplayImage dt = new DisplayImage();
dt.main(args);
}
}
//显示图像范例
class DisplayImage extends JFrame{
public DisplayImage(){
add(new ImagePanel());
}
public static void main(String[]args){
JFrame frame = new DisplayImage();
frame.setTitle("图像显示");
frame.setSize(300, 300);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
class ImagePanel extends JPanel{
private ImageIcon imageIcon = new ImageIcon("C:\\Users\\HarryKate\\Desktop\\博客.PNG");
private Image image = imageIcon.getImage();
protected void paintComponent(Graphics g){
super.paintComponent(g);
if(image != null)
g.drawImage(image, 0, 0, getWidth(),getHeight(),this);
}
}
总结:本博文主要讲解各种方式的图形框架的绘制与编写,为后续更为深层次的GUI设计打下基础。