这主要是以下内容:
我认为我有一个案例,可以告诉用户操作和程序化操作之间的区别。我正在尝试编写一个通用案例线程安全的JComboBox类。尝试从非AWT线程更新控件时隐藏所有invokeLater的想法。
public class JComboBoxThreadSafe
extends JComboBox {
private int m_iSelected = -1;
private Object m_oSelected = null;
private boolean m_bVisible = true;
public JComboBoxThreadSafe(){
super();
}
public JComboBoxThreadSafe(ComboBoxModel arg0){
super(arg0);
}
public JComboBoxThreadSafe(Object[] items){
super(items);
}
public JComboBoxThreadSafe(Vector<?> items){
super(items);
}
@Override
public void setSelectedIndex(final int iIndex){
m_iSelected = iIndex;
m_oSelected = getItemAt(iIndex);
if (SwingUtilities.isEventDispatchThread()){
super.setSelectedIndex(iIndex);
}else{
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run() {
JComboBoxThreadSafe.super.setSelectedIndex(iIndex);
}
});
}
}
@Override
public void setSelectedItem(final Object oSelect){
m_oSelected = oSelect;
m_iSelected = FindItemIndex(oSelect);
if (SwingUtilities.isEventDispatchThread()){
super.setSelectedItem(oSelect);
}else{
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run() {
JComboBoxThreadSafe.super.setSelectedItem(oSelect);
}
});
}
}
@Override
public void setVisible(final boolean bVisible){
m_bVisible = bVisible;
if (SwingUtilities.isEventDispatchThread()){
super.setVisible(bVisible);
}else{
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run() {
JComboBoxThreadSafe.super.setVisible(bVisible);
}
});
}
}
@Override
public Object getSelectedItem(){
return m_oSelected;
}
@Override
public int getSelectedIndex(){
return m_iSelected;
}
@Override
public boolean isVisible(){
return m_bVisible;
}
private int FindItemIndex(Object oItem){
int iReturn = -1;
int iCount = getItemCount();
for (int iIndex = 0; (iReturn == -1) && (iIndex < iCount); iIndex++){
if (getItemAt(iIndex).equals(oItem)) iReturn = iIndex;
}
return iReturn;
}
}
我有一个通过网络与服务器通信的线程。当GUI启动时,它会向服务器查询一些设置。当它收到响应时,需要更新GUI上的控件。当用户更改该值时,它会将新设置发送到服务器。通常我会有一个布尔标志来保护程序集不会导致“新”设置被发送到服务器。对控件的更改发生在以后使标志无效。
public class DisplayOperatorAdvanced
implements ListDataListener {
private JComboBox m_cbRate = null;
private boolean m_bAllowUpdates = true;
public JPanel init(){
// ... Lots of init stuff removed
m_cbRate = new JComboBoxThreadSafe(...);
m_cbRate.getModel().addListDataListener(this);
// ... Lots of init stuff removed
}
private void setRate(){
// Read control values and send them to server
}
public void handleSettingValue(String sSetting){
// Comes in on a non-AWT thread
m_bAllowUpdates = false;
// The underlying control doesn't get changed until later!
m_cbRate.setSelectedItem(sSetting);
m_bAllowUpdates = true;
}
@Override
public void contentsChanged(ListDataEvent ldeEvent){
if (m_bAllowUpdates) setRate();
}
}
我可以想到一些黑客的解决方案:
过滤掉所有程序化更改真的很棒。可以吗?
谢谢!
修改
这是一个测试类,显示只修改模型不起作用。当我在最新的JDK 1.7u51上运行它时,单击选择随机按钮,梳理器无法正确呈现。如果将鼠标悬停在它上面,它将再次开始工作,直到您通过下拉列表进行新选择,然后再次单击选择随机按钮。所以,我编写了JCmoboBoxThreadSafe,希望每次我想更新组合框时都不必编写invokeLater代码。
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class CBTest
implements ActionListener,
Runnable {
private static JComboBox<String> ms_cbTest = null;
public void actionPerformed(ActionEvent aeEvent){
Thread tThread = new Thread(this);
tThread.start();
}
public void run(){
ms_cbTest.getModel().setSelectedItem((int)(ms_cbTest.getItemCount() * Math.random()));
}
public static void main(String[] asArgs){
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e){
}
JFrame fFrame = new JFrame();
JPanel pPanel = new JPanel();
fFrame.getContentPane().add(pPanel);
ms_cbTest = new JComboBox<String>();
for (int iNum = 0; iNum < 100; iNum++){
ms_cbTest.addItem("" + iNum);
}
pPanel.add(ms_cbTest);
JButton bSelect = new JButton("Select Random");
bSelect.addActionListener(new CBTest());
pPanel.add(bSelect);
fFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
fFrame.pack();
fFrame.setLocationRelativeTo(null);
fFrame.setResizable(false);
fFrame.setVisible(true);
}
}