2014-10-20 74 views
0

我正在學習java swing,並且在以下程序中遇到問題。它在頂部創建一個帶有退出按鈕的小框架。目的是在鼠標點擊的任何位置顯示座標。當我點擊鼠標2件不必要的事情正在發生:Java:重繪在Swing不工作

  1. 的退出按鈕被鼠標點擊無效,它不再響應(而不是對事件作出反應,並戒菸,它顯示的退出按鈕的頂部座標) 。
  2. 當我點擊一個新位置時,舊位置的座標依然存在。

我用removeAll()revalidate()做基於this discussionrepaint()之前,但是這並沒有幫助。此代碼取自here以及說明研究在線文檔爲何發生這種情況的代碼。

任何指針?

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 

import java.awt.Color; 
import java.awt.event.ActionListener; 
import java.awt.event.ActionEvent; 
import java.awt.BorderLayout; 
import java.awt.Graphics; 
import javax.swing.JFrame; 
import javax.swing.JButton; 
import javax.swing.JLabel; 

public class QuitCoordinateTest { 
    public static void main(String[] args){ 
    GUI gui = new GUI(); 
    } 
} 

class MyFrame extends JFrame implements ActionListener{ 
    int clickX; 
    int clickY; 

    public void paint(Graphics g){ 
    g.drawString("" + clickX + ", " + clickY, clickX, clickY); 
    } 

    public void actionPerformed(ActionEvent e){ 
    System.exit(0); 
    } 
} 
//=======================================================// 

class GUI extends MyFrame { 
    JButton quitButton = new JButton("Quit"); 

    public GUI(){ 

    MyFrame displayWindow = new MyFrame(); 
    displayWindow.setTitle("Title"); 

    /* 
    JPanel buttonPanel = new JPanel(); 
    buttonPanel.add(quitButton); 
    displayWindow.getContentPane().add(buttonPanel,BorderLayout.NORTH); 
    JPanel textPanel = new JPanel(); 
    */ 

    displayWindow.getContentPane().add(quitButton,BorderLayout.NORTH); 
    quitButton.addActionListener(displayWindow); 
    displayWindow.setSize(201,201); 
    displayWindow.setVisible(true); 
// displayWindow.pack(); 

    displayWindow.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); 

    displayWindow.addMouseListener(new MouseProc(displayWindow)); 

    }//end constructor 

}//end class GUI definition 
//=======================================================// 

//This listener class monitors for mouse presses and 
// displays the coordinates of the mouse pointer when the 
// mouse is pressed on the source object. 

class MouseProc extends MouseAdapter{ 
    MyFrame refToWin; 

    MouseProc(MyFrame inWin){ 
    refToWin = inWin; 
    } 

    //Override the mousePressed method to determine and 
    // display the coordinates when the mouse is pressed. 
    public void mousePressed(MouseEvent e){ 

    refToWin.removeAll(); 
    refToWin.clickX = e.getX(); 
    refToWin.clickY = e.getY(); 

    //Force the JFrame object to be repainted in order to 
    // display the coordinate information. 

    refToWin.removeAll(); 
    refToWin.validate(); 
    refToWin.repaint(); 

    } 
} 
+0

謝謝!我更新了代碼以顯示添加quitButton。對不起,新的擺動。我假設你的意思是爲(a)按鈕和(b)座標區域創建JPanel並在那裏使用繪畫。我試圖創建JPanel,以避免在退出按鈕上重疊座標。它改變了外觀和窗口大小。我必須提供一個201x201窗口,頂部有一個跨越窗口寬度的退出按鈕。我將致力於修復JPanel的大小。我使用removeAll來擺脫基於鏈接討論的舊座標。看來超級會解決這個問題。 – user3600280 2014-10-20 01:12:28

回答

4
  1. repaint()工作正常。
  2. 避免直接在JFrame上繪圖。
  3. 改爲在protected void paintComponent(Graphics g)中繪製一個JPanel的方法覆蓋,然後顯示在JFrame中。
  4. 請務必在paintComponent重寫中調用超級的paintComponent(g)方法 - 這將清除舊圖像,並且是您的其中一個問題的原因。
  5. 在您的代碼中使用合理的評論。太多評論和太多的文字分散注意力,使得理解你的代碼變得更加困難,並不容易。
  6. 在你的JFrame上調用removeAll()將做到這一點 - 刪除所有組件,包括你的按鈕。你爲什麼打這個電話?你確定要調用這個方法嗎?
  7. 一個小小的挑逗 - 你會希望避免直接設置另一個類的字段,比如你的clickX和clickY字段。相反,將它們設爲私有,只允許外部類通過公共方法修改它們。雖然這個小程序可能並不重要,但當您開始擴展您的編程並創建具有複雜交互的大型程序時,它將會非常重要。成功的關鍵在於限制和控制班級之間的所有交流,以避免難以發現副作用。

例如,像...

@Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     String str = String.format("[%d, %d]", clickX, clickY); 
     g.drawString(str, clickX, clickY); 
    } 

    public int getClickX() { 
     return clickX; 
    } 

    public void setClickX(int clickX) { 
     this.clickX = clickX; 
    } 

    public int getClickY() { 
     return clickY; 
    } 

    public void setClickY(int clickY) { 
     this.clickY = clickY; 
    } 

例如

import java.awt.*; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import javax.swing.*; 

@SuppressWarnings("serial") 
public class DetectClicks extends JPanel { 
    private static final int PREF_W = 800; 
    private static final int PREF_H = 650; 
    private int clickX; 
    private int clickY; 

    public DetectClicks() { 
     MyMouseListener mouseAdapter = new MyMouseListener(this); 
     addMouseListener(mouseAdapter); 
     addMouseMotionListener(mouseAdapter); // to allow dragging! 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     return new Dimension(PREF_W, PREF_H); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     String str = String.format("[%d, %d]", clickX, clickY); 
     g.drawString(str, clickX, clickY); 
    } 

    public int getClickX() { 
     return clickX; 
    } 

    public void setClickX(int clickX) { 
     this.clickX = clickX; 
    } 

    public int getClickY() { 
     return clickY; 
    } 

    public void setClickY(int clickY) { 
     this.clickY = clickY; 
    } 

    private static void createAndShowGui() { 
     DetectClicks mainPanel = new DetectClicks(); 

     JFrame frame = new JFrame("DetectClicks"); 
     frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
     frame.getContentPane().add(mainPanel); 
     frame.pack(); 
     frame.setLocationByPlatform(true); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      createAndShowGui(); 
     } 
     }); 
    } 
} 

class MyMouseListener extends MouseAdapter { 
    private DetectClicks detectClicks; 

    public MyMouseListener(DetectClicks detectClicks) { 
     this.detectClicks = detectClicks; 
    } 

    @Override 
    public void mousePressed(MouseEvent evt) { 
     showPoint(evt); 
    } 

    @Override 
    public void mouseDragged(MouseEvent evt) { 
     showPoint(evt); 
    } 

    private void showPoint(MouseEvent evt) { 
     detectClicks.setClickX(evt.getX()); 
     detectClicks.setClickY(evt.getY()); 
     detectClicks.repaint(); 
    } 

} 
0

您的活動得到由打印座標處理程序消耗,你需要重新分派事件,以便按鈕可以看到它。你能做到這樣,座標顯示事件處理中:

Component c = e.getComponent(); 
c.getParent().dispatchEvent(e); 

另外,我會忍不住使用框架的玻璃嵌板,並把一個JLabel它與座標,而不是搞亂塗料方法。

0

你沒有使用任何重繪的(),無效()等 我強烈建議使用

SwingUtilities.invokeLater(new Runnable() { 

      public void run() { 
      //TODO udpdate UI compontents, layouts etc. 
      } 
}); 

這保證了UI組件的實時更新。因爲我們不知道系統何時更新UI層次結構,所以我們不能強制它。這允許系統通過它自己來確定。