Re: [問題] 繪圖的兩個問題
(原文恕刪)
首先, 你應該繼承 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)
討論串 (同標題文章)