2013-05-09 109 views
-1

我正在編寫一個支持網絡的類似戰艦的遊戲gui(是的,我也是)。 如果我右鍵單擊來設置一個航點,所有的mapLabel消失,我不明白它,因爲所有的右鍵點擊應該做的是發送一些字符串到服務器,而不是以任何方式影響顯示本身。 如果我打電話給panel.repaint(); pane.validate();設定航點後,所有事情都會再次顯示,但表現即將接近不可能的緩慢。我知道,這是很多代碼,但我無法想象在FieldListener中出現問題,儘管它必須是。所以我不知道要發佈什麼。如果你想看到別的東西,你可以要求它...先前顯示的圖像在鼠標點擊後消失

這裏是我們的代碼部分,即最有可能是負責的問題:

/** 
* The listener for a field. 
* @author Andris 
* 
*/ 
private class FieldListener implements MouseListener { 

    private int[] xy; 
    private int[] pressedPos = new int[] {-1,-1}; 


    @Override 
    public void mousePressed(MouseEvent evt) { 
     Field field = map.getField(xy[0],xy[1]); 
     pressedPos = xy.clone(); 
     switch(evt.getButton()){ 
     case MouseEvent.BUTTON1://-------well, BUTTON1...... 
      break; 
     case MouseEvent.BUTTON3: 
      switch(selBtn){ 
      case 2://---------------this is the case 
       client.Out("some string");// this sends to the server, nothing else... 
       break; 
      } 
      break; 
     } 
    } 

這是執行服務器應答後(從不同的包完全不同的類,並且所有的消失領域是私人的,雖然):

public class Server { 
    client.Out(cfg.chat_server+"you have set a waypoint at ("+x+","+y+")."); 

public class ChatFrame extends JPanel { 
    public void Out(String nextString){ 
     text.append(" "+nextString); 
     text.append("\n"); 
     JScrollBar scroll = display.getVerticalScrollBar(); 
     if(!scroll.getValueIsAdjusting())scroll.setValue(Integer.MAX_VALUE); 
    } 

這裏的定製油漆方法(也許這是ImageObserver的是錯誤的):

private class MapLabel extends JLabel{ //------------- in MapFrame 

    private Field field; 
    private int[] xy; 

    public void paint(Graphics g){ 
     Image image = getImageNsetToolTip(); 
     Graphics2D g2D=(Graphics2D)g; 
     g2D.drawImage(image, 0, 0, actImgSize, actImgSize, this); 
     g2D.setClip(0, 0, actImgSize, actImgSize); 
     super.paint(g2D); 
    } 

    /** 
    * gets the proper image and sets the tool-tip 
    * @return 
    */ 
    private Image getImageNsetToolTip(){ 
     Image result; 
     String toolTip = "("+xy[0]+","+xy[1]+")"; 
     TileType type = field.getType(); 
     switch(type){ 
     case harbor: 
      result=harborImg[0]; 
      break; 
     case land: 
//------------------------------etc... 


     this.setToolTipText(toolTip); 
     return result; 
    } 

這裏的一些,其餘的:

...lots of imports... 

/** 
* This is the frame in which the GameMap is displayed. 
* @author Andris 
* 
*/ 
@SuppressWarnings("serial") 
public class MapFrame extends JPanel { 

...lots of variables... 

    /** 
    * Creates the frame, but doesn't make it visible yet. 
    * @param window the GameWindow in which this frame will be embedded. 
    * @param client the client who runs this. 
    */ 
    public MapFrame(GameWindow window, Client client){ 

...lots of variables initialized... 

     panel = new JPanel(); 
     pane = new JScrollPane(panel, 
       JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, 
       JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); 


     buttons = new JButton[nButtons]; 
     buttonListener = new ButtonListener(); 
     for(int i=0; i<nButtons; i++){ 
      buttons[i] = new JButton(buttonTexts[i]); 
      buttons[i].setName(buttonTexts[i].replace(' ', '_')); 
      buttons[i].addActionListener(buttonListener); 
      buttonPanel.add(buttons[i]); 
     } 
+1

嗨!歡迎來到SO。不幸的是,不太可能有人回答這個問題,因爲它包含了太多的代碼,而且是不完整的;所以很難幫助你。展示一些努力併發布[SSCCE](http://sscce.org),這將很快爲您提供有價值的幫助。 – 2013-05-09 20:50:41

+0

因爲我不知道問題出在哪裏,而且我們的代碼有3000多行,所以我不認爲它包含太多的代碼,並且我無法在較小的程序中重新創建問題... – 2013-05-12 20:27:00

+0

_因爲我沒有想法問題在哪裏,我們的代碼是3000多行。因此,[SSCCE](http://sscce.org)的想法。如果按照鏈接中描述的方法進行操作,將極大地提高發現問題的可能性並獲得可再現此問題的較小程序。 – 2013-05-13 07:42:59

回答

0

我終於弄明白了:
有很多線程在運行,因爲服務器,客戶端,每個連接和什麼都不在自己的線程中運行。
可以導致擺動事件隊列的行爲,結果,事情不會執行時,他們應該。
這通常只會發生,如果有其他線程的許多(因此不可能做一個SSCCE)。
爲了防止像validate()或repaint()這樣的每個方法都應該作爲invokeLater被調用(並且因此被事件隊列正確處理),特別是如果它們是從不同的線程調用的。
所以這是我寫的無處不在:

SwingUtilities.invokeLater(new Runnable(){ 
     @override 
     public void run(){ 
      panel.validate(); 
      panel.repaint(); 
      pane.validate(); 
     } 
    }); 

或:

SwingUtilities.invokeLater(new Runnable(){ 
     @override 
     public void run(){ 
      mapLabels[x][y].repaint(); 
     } 
    }); 
2

有一個問題,你的繪製代碼

public void paint(Graphics g){ 
    Image image = getImageNsetToolTip(); 
    Graphics2D g2D=(Graphics2D)g; 
    g2D.drawImage(image, 0, 0, actImgSize, actImgSize, this); 
    g2D.setClip(0, 0, actImgSize, actImgSize); 
    super.paint(g2D); 
} 

繪畫之前super.paint可以消滅你以前有畫的潛力。這是因爲paint調用paintComponent,paintBorderpaintComponents

一個paintComponent的工作是準備用於繪製的圖形上下文(清潔起來)

你應該,也避免與剪輯搞亂。由於繪畫在Swing中的工作方式,您可能會冒着讓組件繪製超出其物理邊界的風險。剪輯是由重繪管理器設置爲等於組件的大小之前paint被稱爲

相反,你應該使用paintComponent進行自定義的繪畫

看看Perofming custom painting更多細節

現在,我想到的問題是,爲什麼在JLabel上繪製自定義圖像時,JLabel的其中一個功能是顯示圖標?

+0

我正在努力提高性能。有人告訴我寧願重寫paint或paintCompnent方法,而不是使用ImageIcons(據說更有效的重縮放),儘管我沒有發現它(明顯)更高效。 – 2013-05-12 19:55:13

+0

我嘗試了你的建議,但他們沒有解決主要問題(儘管setClip似乎沒有負面影響,因此肯定是一種改進)。現在你提到它了,我意識到,我可能應該堅持使用ImageIcons的自己和舊的計劃,並放棄提高性能。謝謝 – 2013-05-12 20:15:48

+0

因此最後的聲明;) – MadProgrammer 2013-05-12 21:45:19

相關問題