2014-12-04 26 views
1

我正在製作觸摸屏鍵盤。當我按下shift鍵時(從小寫字母到大寫字母),我希望字母鍵改變文字。這是我目前執行的一個片段:批量重繪使用FormLayout的擺動組件

public void updatedButtons() 
{ 
    switch(m_state) 
    { 
     case QWERTY: 
      for(KeyboardButton button : m_keyboardButtons) 
      { 
       button.setText(button.getQwertyText().toLowerCase()); 
      } 
      break; 
     case QWERTY_SHIFT: 
      for(KeyboardButton button : m_keyboardButtons) 
      { 
       button.setText(button.getQwertyText().toUpperCase()); 
      } 
      break; 
    } 
} 

哪裏KeyboardButton是一個JButton的簡單延伸與qwertyText字符串字段。

這裏的問題是按鈕以混沌的方式更新。我明白爲什麼會這樣;當我調用setText()時,它將調用repaint()以獲取單個組件,並且每個按鈕都會發生這種情況。我的問題是,我能夠「批量重繪」這些按鈕,而不會破壞Swing的設計(我不希望覆蓋AbstractButton的setText()方法)。謝謝。

UPDATE

原來這是一個的FormLayout問題。下面是說明問題的簡單代碼(請注意,您需要JGoodies表單Jar,並且可能需要修改斷點值)。

import java.awt.Color; 
import java.awt.Graphics; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.util.ArrayList; 
import java.util.List; 

import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 

import com.jgoodies.forms.layout.CellConstraints; 
import com.jgoodies.forms.layout.FormLayout; 

public class JButtonTest 
{ 
    public static List<JButton> buttons = new ArrayList<JButton>(); 
    public static boolean isCaps = false; 
    public static JFrame frame; 


    public static void main(String[] args) 
    { 
     frame = new JFrame(); 
     frame.setSize(1000, 100); 

     JPanel panel = new JPanel(); 
     // Form with 11 83x83 pixel squares, with 5x83 pixel spaces. 
     panel.setLayout(new FormLayout("83px, 5px, 83px, 5px, 83px, 5px, 83px, 5px, " 
       + "83px, 5px, 83px, 5px, 83px, 5px, 83px, 5px, 83px, 5px, 83px, 5px, 83px, 5px, 86px", 
             "83px")); 

     int i = 1; 
     for (char c = 'a'; c < 'l'; ++c) 
     { 
      JButton button = new ComplexButton(Character.toString(c)); 

      button.addActionListener(new ActionListener() 
      { 
       @Override 
       public void actionPerformed(ActionEvent e) 
       { 
        updateButtons(); 
       } 
      }); 

      panel.add(button, new CellConstraints().xywh((i*2)-1, 1, 1, 1, CellConstraints.FILL, CellConstraints.FILL)); 
      buttons.add(button); 
      ++i; 
     } 

     frame.setContentPane(panel); 
     frame.setVisible(true); 
    } 

    // Enable the commented-out lines in this method to allow concurrent updating. 
    public static void updateButtons() 
    { 
     for (JButton button : buttons) 
     { 
      if (!isCaps) 
       button.setText(button.getText().toUpperCase()); 
      else 
       button.setText(button.getText().toLowerCase()); 
      //RepaintManager.currentManager(button).markCompletelyClean(button); 
     } 
     //frame.repaint(); 
     isCaps = !isCaps; 
    } 
    protected static class ComplexButton extends JButton 
    { 
     public ComplexButton(String string) 
     { 
      super(string); 
     } 

     @Override 
     public void paint(Graphics g) 
     { 
      int breakpoint = 3000000; 
      super.paint(g); 
      // Simulate some complex operations. 
      for (int i = 0; i < breakpoint; ++i) 
      { 
       g.setColor(new Color(i%255, (2*i)%255, (3*i)%255)); 
      } 
     } 
    } 
} 

請注意,如果您從FormLayout更改爲FlowLayout,它將很好地工作(儘管本質上是緩慢的)。如果您刪除註釋代碼上的評論(感謝MadProgrammer),它也可以正常工作。另請注意,如果將printlns放在updateButtons()方法的開始和結尾處,該方法將在按鈕停止更新之前結束很久,並且按鈕不會一致更新。這意味着重繪的凝聚特性不會以FormLayout保存。無論如何,即使它被保留下來,呆滯的控件也同混沌更新控件一樣糟糕。猜猜我必須嘗試優化我們的繪圖代碼。感謝您的支持。

+0

我要說的是,你正在做的事情錯了,但由於你忽略了提供一個[可運行示例](https://stackoverflow.com/help/mcve),它可以向你展示r問題,我們會建議的任何東西都會是瘋狂的猜測...... – MadProgrammer 2014-12-04 20:54:52

+0

我不是要求你修復我的代碼。我在說,不管實現的細節如何,這就是Swing正在做的事情(在每個setText()調用中調用repaint()),並且我想阻止它執行它。我的問題是,是否有一個乾淨的方式來防止擺動對這些重新打電話行事。如果你堅持要看演示,我會盡快把一些東西放在一起。 – Ironcache 2014-12-04 21:03:48

+1

@Ironcache實際上,repaint()是一個「延遲/合併」的方法,所以這意味着實際的繪畫只會在循環完成後發生,並且由循環觸發的所有重繪調用將合併爲一個重繪。所以這個問題很難被你的解釋所引起。請提供[mcve](https://stackoverflow.com/help/mcve) – 2014-12-04 21:08:37

回答

3

Swing中的繪畫由RepaintManager控制,它決定什麼時候應該更新。 RepaintManager經過優化,可以減少爲了保持性能而預定的繪畫事件數量。

這意味着,當它收到一堆重繪請求時,它會將它們合併成儘可能少的繪畫事件。這意味着當你從一堆按鈕的循環中調用setText時,很可能RepaintManager已經將其降低到儘可能接近1(取決於你正在更新的內容可能會更多,但很可能小於循環)的迭代次數...

例如,它似乎爲我工作...

Keys

import java.awt.EventQueue; 
import java.awt.GridLayout; 
import java.awt.Insets; 
import java.awt.event.KeyAdapter; 
import java.awt.event.KeyEvent; 
import java.util.ArrayList; 
import java.util.List; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class TestKeyboard { 

    public static void main(String[] args) { 
     new TestKeyboard(); 
    } 

    public TestKeyboard() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
        ex.printStackTrace(); 
       } 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.add(new TestPane()); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class TestPane extends JPanel { 

     private List<JButton> buttons; 

     public TestPane() { 
      setFocusable(true); 
      setLayout(new GridLayout(0, 4)); 
      buttons = new ArrayList<>(26); 
      for (int index = 0; index < 26; index++) { 
       JButton btn = createButton(index); 
       buttons.add(btn); 
       add(btn); 
      } 

      addKeyListener(new KeyAdapter() { 

       @Override 
       public void keyPressed(KeyEvent e) { 
        if (e.getKeyCode() == KeyEvent.VK_SHIFT) { 
         for (JButton btn : buttons) { 
          String text = btn.getText().toUpperCase(); 
          btn.setText(text); 
         } 
         revalidate(); 
         repaint(); 
        } 
       } 

       @Override 
       public void keyReleased(KeyEvent e) { 
        if (e.getKeyCode() == KeyEvent.VK_SHIFT) { 
         for (JButton btn : buttons) { 
          String text = btn.getText().toLowerCase(); 
          btn.setText(text); 
         } 
         revalidate(); 
         repaint(); 
        } 
       }    
      }); 
     } 

     protected JButton createButton(int index) { 
      JButton btn = new JButton(Character.toString((char) ('a' + index))); 
      btn.setMargin(new Insets(4, 4, 4, 4)); 
      btn.setFocusable(false); 
      btn.setFocusPainted(false); 
      return btn; 
     } 

    } 

} 
+0

謝謝,您的回答幫助我解決了我的問題。我不知道重繪經理。標記這個最好的答案,我自己的答案會隨之而來。 – Ironcache 2014-12-05 16:20:33

+0

用我的結果代碼的例子更新問題。 – Ironcache 2014-12-05 16:33:12