作者the2046 (wz)
看板java
标题Re: [问题] 绘图的两个问题
时间Sat Jul 7 13:07:27 2012
(原文恕删)
首先, 你应该继承 JComponent或其子类, 然後覆写(Override)
paintComponent(Graphics g), 而非 paint(Graphics g).
因为, 从 swing类别开始 JComponent或其子类才有内建双缓冲(double buffering)
机制,
而它们的 paint会转呼叫 paintComponent, 所以若无特殊原因
都应该覆写 paintComponent才对.
重画(repaint)是一件很耗时的工作, 所以它执行的优先权(priority)是最低的.
它必需让其他指令先执行, 它才能执行. 例如:
import javax.swing.*;
import javax.swing.event.MouseInputListener;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
class TeachPanel extends JPanel implements MouseInputListener{
public TeachPanel() {
this.addMouseListener(this);
this.addMouseMotionListener(this);
}
@Override
public void paintComponent(Graphics g) {
System.out.println("paint done");
System.out.println("----------------");
}
public void t() {
System.out.println("t done1");
System.out.println("t done2");
}
//--------[ implements MouseInputListener
@Override
public void mouseDragged(MouseEvent e) {
System.out.println("drag done1");
repaint();
System.out.println("drag done2");
System.out.println("drag done3");
System.out.println("drag done4");
t();
}
@Override public void mouseClicked(MouseEvent e) {}
@Override public void mouseEntered(MouseEvent e) {}
@Override public void mouseExited(MouseEvent e) {}
@Override public void mouseMoved(MouseEvent e) {}
@Override public void mousePressed(MouseEvent e) {}
@Override public void mouseReleased(MouseEvent e) {}
//--------] implements MouseInputListener
public static void main(String[] args) {
JFrame jf = new JFrame();
jf.setSize(500, 500);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setContentPane(new TeachPanel());
}
}
输出结果:
paint done
----------------
drag done1
drag done2
drag done3
drag done4
t done1
t done2
paint done
----------------
萤幕初始化时, 系统会自动调用 paintComponent一次,
但随後 repaint()都最後才执行.
所以这意味着: 画图时, 参数更新要写在 paintComponent中,
若不这样做, 会造成参数更新後才画图这种错误.
然後不想有间隙, 就得用drawLine()的方式.
按第一下取得起始位置, 拖曳取得第二个位置, 画线.
第二个位置当作起始位置, 再拖曳取得第二个位置, 画线.
如此连绵不断就不会有间隙产生.
当视窗最小化(deminimized)或调整尺寸(resized)後, 重现刚才画的图案
这必须宣告一个 ArrayList物件,记住拖曳过的每个 Point.
当视窗经过上述变化, 作业系统会自动触发 paintComponent,
所以用个回圈把 ArrayList的 Point取出画回, 即大功告成.
以下是范例:
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.event.MouseInputListener;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
class DrawPanel extends JPanel implements MouseInputListener{
ArrayList point; //:纪录每个点
public DrawPanel() {
this.addMouseListener(this);;
this.addMouseMotionListener(this);
point = new ArrayList();
}
@Override
public void paintComponent(Graphics g) {
paintLine(g);
}
private void paintLine(Graphics g) {
final Point A_BREAK = new Point(-1,-1);
for(int i = 0; i < point.size()-1; i++) { //:重画出每个点
Point p1 = (Point)point.get(i);
Point p2 = (Point)point.get(i+1);
if(p1.equals(A_BREAK) || p2.equals(A_BREAK)) { //:碰到中断点跳开不画
continue;
} else {
g.drawLine(p1.x, p1.y, p2.x, p2.y);
}
}
}
//--------[ implements MouseInputListener
@Override
public void mousePressed(MouseEvent e) {
point.add( new Point(e.getX(), e.getY()) );
}
@Override
public void mouseDragged(MouseEvent e) {
point.add( new Point(e.getX(), e.getY()) );
repaint();
}
@Override
public void mouseReleased(MouseEvent e) {
point.add( new Point(-1, -1) ); //: 表示作画中断
}
@Override public void mouseClicked(MouseEvent e) {}
@Override public void mouseEntered(MouseEvent e) {}
@Override public void mouseExited(MouseEvent e) {}
@Override public void mouseMoved(MouseEvent e) {}
//--------] implements MouseInputListener
public static void main(String[] args) {
JFrame jf = new JFrame();
jf.setSize(500, 500);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setContentPane(new DrawPanel());
}
}
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 220.135.64.74
※ 编辑: the2046 来自: 220.135.64.74 (07/07 13:09)