有没有办法区分用户导致的事件和应用程序导致的事件?

时间:2014-03-13 04:14:37

标签: java multithreading swing events combobox

这主要是以下内容:

Swing: Is there a way to differentiate between a user-caused ItemEvent and an application-caused one?

我认为我有一个案例,可以告诉用户操作和程序化操作之间的区别。我正在尝试编写一个通用案例线程安全的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();

    }

}

我可以想到一些黑客的解决方案:

  1. 侦听鼠标事件而不是模型更改
  2. 尝试在程序化更改后过滤掉下一个事件
  3. 过滤掉所有程序化更改真的很棒。可以吗?

    谢谢!

    修改

    这是一个测试类,显示只修改模型不起作用。当我在最新的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);
    
        }
    
    }
    

0 个答案:

没有答案