Re: [問題] 繪圖的兩個問題

看板java作者 (wz)時間13年前 (2012/07/07 13:07), 編輯推噓0(000)
留言0則, 0人參與, 最新討論串3/4 (看更多)
(原文恕刪) 首先, 你應該繼承 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)
文章代碼(AID): #1FzyGIuo (java)
文章代碼(AID): #1FzyGIuo (java)