简体   繁体   English

从Java中的另一个线程更新JTextField

[英]Update JTextField from another thread in Java

I'm making a game client/server and I'm having a new thread update some info on the client GUI (which is using Swing). 我正在制作一个游戏客户端/服务器,我正在新的线程更新客户端GUI上的一些信息(使用Swing)。 I'm trying to use SwingUtilities but it's not working. 我正在尝试使用SwingUtilities但它不起作用。 Also, I heard SwingUtilities creates a new thread everytime you use it so I'm looking for a new way as well (I have 10 or so JTextFields to be updated). 另外,我听说SwingUtilities每次使用它都会创建一个新线程,所以我也在寻找一种新方法(我有10个左右的JTextFields要更新)。 Is there a way to do it without using SwingUtilities? 有没有办法在不使用SwingUtilities的情况下完成? Here is what I have right now. 这就是我现在所拥有的。

SwingUtilities.invokeLater(    
        new Runnable() {    
           public void run()    
           {    
              Client.status.setText("status = "+status); 
           }    
        });

Interestingly, just recently I encountered a similar issue, so In order to get over this I used SwingUtilities.invokeAndWait(Runnable runnable) , that's what made the SSCCE I was creating to work as expected, though if I change all calls to invokeAndWait() with invokeLater() , one can clearly see the difference between the two things. 有趣的是,就在最近我遇到了类似的问题,所以为了克服这个问题,我使用了SwingUtilities.invokeAndWait(Runnable runnable) ,这就是我创建的SSCCE按预期工作的原因,但是如果我将所有调用都改为invokeAndWait()使用invokeLater() ,可以清楚地看到这两件事之间的区别。

A quote from Java Doc says : Java Doc的一句话说:

Causes doRun.run() to be executed synchronously on the AWT event dispatching thread. 
This call blocks until all pending AWT events have been processed and 
(then) doRun.run() returns. This method should be used when an application thread 
needs to update the GUI.

This is a small program I had made as an SSCCE to represent a Bubble Sort Animation : 这是我作为SSCCE表示冒泡排序动画的一个小程序:

import javax.swing.*;

public class BubbleSortFrame extends JFrame
{
    private BubbleSortView contentPane;

    private void displayGUI()
    {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        contentPane = new BubbleSortView();
        setContentPane(contentPane);
        pack();
        setLocationByPlatform(true);
        setVisible(true);
    }

    public static void main(String... args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                new BubbleSortFrame().displayGUI();
            }
        });
    }
}

import java.awt.*;
import java.awt.event.*;
import java.lang.reflect.InvocationTargetException;
import javax.swing.*;

public class BubbleSortView extends JPanel
{
    private JLabel sizeLabel;
    private JTextField sizeField;
    private JTextField[] vField;
    private JLabel[] vLabel;
    private JButton startButton, createButton;
    private int size;
    private JPanel createPanel, animationPanel;

    private BubbleSort bubbleSort;

    public BubbleSortView()
    {
        size = 5;
        displayAndCreateGUI();
    }

    private void displayAndCreateGUI()
    {
        setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        setOpaque(true);
        setBackground(Color.WHITE);
        JPanel basePanel = new JPanel();
        basePanel.setLayout(new GridLayout(2, 1, 5, 5));
        basePanel.setOpaque(true);
        basePanel.setBackground(Color.WHITE);

        JPanel topPanel = new JPanel();
        topPanel.setOpaque(true);
        topPanel.setBackground(Color.WHITE);
        topPanel.setBorder(
            BorderFactory.createTitledBorder("Input : "));
        topPanel.setLayout(new GridLayout(2, 1, 5, 5)); 
        /*
         * This will act as the area
         * for taking the input for
         * number of elements in an Array.
         */
        JPanel sizePanel = new JPanel();
        sizePanel.setOpaque(true);
        sizePanel.setBackground(Color.WHITE);
        sizeLabel = new JLabel("Enter Number of Elements : ");
        sizeField = new JTextField(10);
        createButton = new JButton("CREATE");

        /*
         * This will act as the area
         * where we will specify the values
         * for each index in an Array.
         */
        createPanel = new JPanel();
        createPanel.setOpaque(true);
        createPanel.setBackground(Color.WHITE);
        createPanel.setBorder(
            BorderFactory.createTitledBorder("Please Enter values for an Array : "));
        createPanel.setVisible(false);      

        animationPanel = new JPanel();
        animationPanel.setOpaque(true);
        animationPanel.setBackground(Color.WHITE);
        animationPanel.setBorder(
            BorderFactory.createTitledBorder("Animation : "));
        animationPanel.setVisible(false);   

        createButton.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent ae)
            {
                if (sizeField.getDocument().getLength() > 0)
                {
                    size = Integer.parseInt(sizeField.getText());
                    vField = new JTextField[size];
                    createPanel.setVisible(true);
                    for (int i = 0; i < size; i++)
                    {
                        vField[i] = new JTextField(5);
                        /*
                         * Adding the Listener to the
                         * last JTextField on the Right 
                         * Side.
                         */
                        if (i == (size - 1)) 
                        {
                            vField[i].addActionListener(new ActionListener()
                            {
                                @Override
                                public void actionPerformed(ActionEvent ae)
                                {
                                    animationPanel.setLayout(
                                            new GridLayout(1, size, 2, 2));
                                    animationPanel.setVisible(true);
                                    vLabel = new JLabel[size];
                                    for (int i = 0; i < size; i++)
                                    {
                                        vLabel[i] = new JLabel(
                                            vField[i].getText(), JLabel.CENTER);
                                        vLabel[i].setOpaque(true);
                                        vLabel[i].setBackground(Color.YELLOW);
                                        vLabel[i].setForeground(Color.RED);
                                        animationPanel.add(vLabel[i]);
                                    }
                                    animationPanel.revalidate();
                                    animationPanel.repaint();
                                    bubbleSort = new BubbleSort(vLabel, size);
                                    Thread t = new Thread(bubbleSort);
                                    t.start();
                                }
                            });
                        }
                        createPanel.add(vField[i]);
                    }
                    createPanel.revalidate();
                    createPanel.repaint();
                    createButton.setEnabled(false);
                }
                else
                    size = 5;
            }
        });
        sizePanel.add(sizeLabel);
        sizePanel.add(sizeField);
        sizePanel.add(createButton);

        /*
         * Initializing JTextField Array
         * so that it can be first presented
         * to the USER to take input for
         * 5 values.
         */
        //for (int i = 0; i < size; i++)
        //  vField[i] = new JTextField(5);
        topPanel.add(sizePanel);
        topPanel.add(createPanel);
        basePanel.add(topPanel);
        basePanel.add(animationPanel);
        add(basePanel);
    }

    private class BubbleSort implements Runnable
    {
        private int[] arr;
        private JLabel[] vLabel;
        private int size;
        private int pass;

        public BubbleSort(JLabel[] label, int size)
        {
            vLabel = label;
            this.size = size;
            pass = 1;
            for (int i = 0; i < size; i++)
                System.out.print("" + vLabel[i].getText() + "\t");
            System.out.println("");
        }

        @Override
        public void run()
        {
            try
            {
                bubbleSorting();
            }
            catch (InvocationTargetException ite)
            {
                ite.printStackTrace();
            }
            catch(InterruptedException ie)
            {
                ie.printStackTrace();
            }
        }

        private void bubbleSorting() 
            throws InterruptedException, InvocationTargetException
        {
            while (pass < size)
            {
                for (int i = 0; i < (size - pass); i++)
                {
                    final int j = i;
                    SwingUtilities.invokeAndWait(new Runnable()
                    {
                        @Override
                        public void run()
                        {
                            vLabel[j].setBackground(Color.RED);
                            vLabel[j].setForeground(Color.WHITE);
                            vLabel[j + 1].setBackground(Color.RED);
                            vLabel[j + 1].setForeground(Color.WHITE);
                        }
                    });
                    try
                    {
                        Thread.sleep(1500);
                    }
                    catch(InterruptedException ie)
                    {
                        ie.printStackTrace();
                    }
                    int left = Integer.parseInt(vLabel[i].getText());
                    int right = Integer.parseInt(vLabel[i + 1].getText());
                    if (left > right)
                    {
                        String temp = vLabel[i].getText();
                        vLabel[i].setText(vLabel[i + 1].getText());
                        vLabel[i + 1].setText(temp);
                    }
                    SwingUtilities.invokeAndWait(new Runnable()
                    {
                        @Override
                        public void run()
                        {
                            vLabel[j].setBackground(Color.YELLOW);
                            vLabel[j].setForeground(Color.RED);
                            vLabel[j + 1].setBackground(Color.YELLOW);
                            vLabel[j + 1].setForeground(Color.RED);
                        }
                    });
                }
                System.out.println("Pass : " + pass + "\tSize : " + size);  
                SwingUtilities.invokeAndWait(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        vLabel[size - pass].setBackground(Color.GREEN);
                        vLabel[size - pass].setForeground(Color.BLUE);
                    }
                });
                pass++;
            }
            SwingUtilities.invokeAndWait(new Runnable()
            {
                @Override
                public void run()
                {
                    vLabel[0].setBackground(Color.GREEN);
                    vLabel[0].setForeground(Color.BLUE);
                }
            });
        }
    }
}

I don't know where you heard about " SwingUtilities creates a new thread " from, but I think you've either misunderstood or being informed incorrectly. 我不知道你从哪里听说过“ SwingUtilities创建一个新主题 ”,但我认为你已经误解或被错误地告知了。 SwingUtilities.invokeLater places the Runnable onto the end of the Event Dispatcher's queue. SwingUtilities.invokeLaterRunnable放在Event Dispatcher队列的末尾。 The queue then processes this event within the it's own thread context (in time), calling Run , there is no "new" thread created for this process. 然后队列在它自己的线程上下文(及时)内处理此事件,调用Run ,没有为此进程创建“新”线程。

As to your question. 至于你的问题。

You may need to call validate() (and possibly repaint() ) on the fields parent container to encourage it update ;) 您可能需要在字段父容器上调用validate() (可能还有repaint() )以鼓励它更新;)

And no, there isn't any other way to sync the UI across threads, that's the reason for SwingUtilities 不,没有任何其他方法可以跨线程同步UI,这就是SwingUtilities的原因

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM