我正在制作触摸屏键盘。我希望字母键在按Shift键时从小写更改为大写。这是我当前实现的一个片段:
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是带有qwertyText String字段的JButton的简单扩展。
这里的问题是按钮以混乱的方式更新。我了解为什么会这样;当我调用setText()时,它正在为单个组件调用repaint(),并且每个按钮都在发生这种情况。我的问题是,是否可以在不损害Swing的设计的情况下“批量重画”这些按钮(我宁愿不要覆盖AbstractButton的setText()方法)。谢谢。
更新
原来这是FormLayout的问题。以下是说明问题的简单代码(请注意,您将需要JGoodies Form 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无法以某种方式保留重新绘制的合并性质。
无论如何,即使保留了控件,缓慢的控件也与混乱更新控件一样糟糕。猜猜我将不得不尝试优化我们的绘画代码。感谢您的支持。
最佳答案
Swing中的绘画由RepaintManager
控制,它决定何时更新内容。 RepaintManager
已进行优化,以减少其计划的绘画事件数量,以保持性能。
这意味着当它收到一堆重画请求时,它将把它们合并为尽可能少的画图事件。这意味着,当您从一堆按钮的循环中调用setText
时,RepaintManager
可能会将其减小到尽可能接近的程度(具体取决于您要更新的内容,但最有可能小于循环的迭代次数)...
例如,它似乎对我有用...
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;
}
}
}