【问题标题】:Java Swing: GUI is not updating some propertiesJava Swing:GUI 未更新某些属性
【发布时间】:2019-04-16 18:54:18
【问题描述】:

编辑:下面是一个最简单、最简单且可检查的问题

继续

我正在做一个拉丁方格应用程序,它设置一个大小为 s 的方格,并且您需要为它着色,但有一些限制,例如同一行或同一列中的颜色不同。

但我的麻烦不是问题本身,而是 Swing。

我正在尝试使用 Swing 来实现一些图形和更好的外观。

问题是,当我找到解决方案时,我想停下几秒钟观看它,然后继续寻找其他人(我将使用 Thread.sleep() 来完成)。

但我看到正方形没有上色。只有完成方法后,才会改变自己。

主要问题

仅显示它找到的最后一个解决方案,并在完成回溯方法时显示。

当我点击resolve按钮时,有一个实现ActionListener接口的类,它有actionPerformed方法,它调用主框架类的一个方法,解析正方形。所以问题是,如果我在找到解决方案时停止执行,GUI 不会改变, 但在内部,当我检查属性(调试)时,单元格的颜色已更新,但在 GUI 中没有。

我不知道为什么:(

更详细

我的想法是,用两个面板制作一个框架,一个在左边,一个在中间(也许将来,在右边放一些东西)。

为此,我使用 BorderLayout。

所以左边的第一个面板,类似于基本配置菜单,用户可以在其中设置正方形的大小并运行它以获得解决方案。

为此我有两个按钮,一个用于修改大小,另一个用于解决它。

所以我需要按钮的事件。尺寸没有给我带来问题,但可以解决。

所以我检查了一下,如果我给某个正方形上色并暂停执行(Scanner.nextLine() 或 Thread.sleep())并没有在 GUI 中进行更改,但是当我调试时,正方形被着色了属性,所以我不太明白为什么会失败。

我认为问题出在哪里

所以我有一个按钮,点击时会解析正方形。 而且我认为,我真的不知道,但我怀疑这样做会创建一个新线程或其他东西,因此无法更新 GUI;只有完成后,才去做。

还有什么可以改变的吗?

class ResolveListener implements  ActionListener
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                int size = Integer.parseInt(textField.getText());
                latinSquareFrame.resolve(size);
            }
        }

一个简单的问题

我已阅读 cmets 以搜索与此类似的最小且易于检查的问题。

所以我做到了。这段代码和我的问题类似,有一个正方形,我想在点击按钮的时候给它上色。

问题是,如果我暂停它,它不会着色,只有在方法完成时才会着色,我不知道为什么。

我认为这与我之前遇到的问题相似。

这是我可以用来解决我遇到的问题的最少代码。

    package LatinSquare;


import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Scanner;

public class Test
{
    public static void main(String[] args)
    {
        TestFrame testFrame = new TestFrame();
    }
}

class TestFrame extends JFrame
{

    public TestFrame()
    {
        this.setVisible(true);
        this.setBounds(400,300,400,300);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setLayout(new BorderLayout());
        TestJPanel testJPanel = new TestJPanel();
        this.add(testJPanel,BorderLayout.CENTER);

        TestContainerButtonJPanel testContainerButtonJPanel = new TestContainerButtonJPanel(testJPanel);
        this.add(testContainerButtonJPanel, BorderLayout.SOUTH);

        this.revalidate();
        this.repaint();
    }

}

class TestContainerButtonJPanel extends JPanel
{
    private JButton resolve;
    public TestJPanel testJPanel;

    public TestContainerButtonJPanel(TestJPanel testJPanel)
    {
        this.testJPanel = testJPanel;
        this.setVisible(true);
        resolve = new JButton("RESOLVE");
        ActionListener resolveListener = new ResolveListener();
        resolve.addActionListener(resolveListener);
        this.add(resolve);

    }

    class ResolveListener implements ActionListener
    {
        @Override
        public void actionPerformed(ActionEvent e)
        {
            try {
                TestContainerButtonJPanel.this.testJPanel.colourCells();
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
        }


    }
}


class TestJPanel extends JPanel
{
    private JButton[][] board;
    public TestJPanel()
    {
        this.board = new JButton[4][4];
        this.setVisible(true);
        this.setLayout(new GridLayout(4,4));
        for(int i=0; i<4;i++)
        {
            for(int j=0; j<4;j++)
            {
                JButton cell = new JButton();
                board[i][j] = cell;
                board[i][j].setBackground(Color.WHITE);
                this.add(cell);
            }
        }

    }

    public void colourCells() throws InterruptedException {
        for(int i=0; i<4;i++)
        {
            for(int j=0;j<4;j++)
            {
                this.board[i][j].setBackground(Color.RED);
                Thread.sleep(300);

            }
        }

    }


}

【问题讨论】:

  • 1) 我在您的代码中没有看到任何 Thread.sleep() 调用。 2)您正在混合两种编程范式,控制台应用程序和 GUI 应用程序,选择一个。 3) 要创建延迟,请使用 Swing Worker 或 Swing Timer 而不是Thread.sleep。 4)不要发布您的所有代码,而是发布minimal reproducible example,我们可以复制粘贴并查看相同的行为,在这种情况下,您只能有一个按钮,当您按下它时,它会在 1 秒后改变颜色或所以...
  • 以下是一些示例:example 1example 2
  • 好的,谢谢,我会阅读所有链接。好的,我知道我不需要线程,我会继续阅读链接
  • 看不懂的可以问链接

标签: java swing user-interface


【解决方案1】:

好的,第一件事:

  1. 不要使用Thread.sleep() 更新您的 GUI,它会阻止 EDT
  2. 您没有将程序放在 EDT,请参阅this answer 中的第 2 点
  3. 不要扩展JFrame,而是创建它的一个实例,参见:Extends JFrame vs. creating it inside the program
  4. 在添加所有组件之前,不要让您的程序可见(即调用setVisible(...))。它可能会导致您的程序以错误的方式运行。
  5. 尽量不要创建自己的线程,而是使用Swing TimerSwing Worker(问题 cmets 中的链接)

因此,考虑到所有这些,我决定创建一个新程序,该程序遵循所有上述规则,并在该时间过后使单元格变为蓝色 3 秒或白色,并更新 @987654332 中的文本@ 以及禁用以防止多个计时器同时执行。

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class Test {
    private JFrame frame;
    private JPanel pane;
    private JPanel cellsPane;
    private MyCell[][] cells;
    private JButton button;
    private Timer timer;

    private int counter = 3;
    private boolean isFinished = false;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Test().createAndShowGui());
    }

    private void createAndShowGui() {
        frame = new JFrame(getClass().getSimpleName());

        pane = new JPanel();
        cellsPane = new JPanel();

        pane.setLayout(new BoxLayout(pane, BoxLayout.PAGE_AXIS));
        cellsPane.setLayout(new GridLayout(4, 4, 5, 5));

        cells = new MyCell[4][4];

        for (int i = 0; i < cells.length; i++) {
            for (int j = 0; j < cells[i].length; j++) {
                cells[i][j] = new MyCell(Color.WHITE);
                cellsPane.add(cells[i][j]);
            }
        }

        button = new JButton("Press me!");
        timer = new Timer(1000, listener);

        button.addActionListener(e -> {
            button.setEnabled(false);
            isFinished = false;
            updateCellsColors();
            timer.start();
        });

        pane.add(cellsPane);
        pane.add(button);

        frame.add(pane);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    private void updateCellsColors() {
        for (int i = 0; i < cells.length; i++) {
            for (int j = 0; j < cells[i].length; j++) {
                cells[i][j].setCellColor(isFinished ? Color.WHITE : Color.BLUE);
            }
        }
    }

    private ActionListener listener = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (counter == 0) {
                timer.stop();
                counter = 3;
                isFinished = true;
                button.setEnabled(true);
                updateCellsColors();
            }
            if (isFinished) {
                button.setText("Press me!");
            } else {
                button.setText("You have " + counter + " seconds remaining");
            }
            counter--;
        }
    };
}

@SuppressWarnings("serial")
class MyCell extends JPanel {
    private Color cellColor;

    public Color getCellColor() {
        return cellColor;
    }

    public void setCellColor(Color cellColor) {
        this.cellColor = cellColor;
        this.setBackground(cellColor);
    }

    public MyCell(Color cellColor) {
        this.cellColor = cellColor;
        this.setOpaque(true);
        this.setBackground(cellColor);
    }

    @Override
    public Dimension getPreferredSize() {
        // TODO Auto-generated method stub
        return new Dimension(30, 30);
    }
}

你可以复制粘贴,看到和我一样的结果:

【讨论】:

  • 太好了,谢谢你,我想我还有很多东西要阅读和学习,非常感谢你的时间和精力!
  • @OnlyDavies 很高兴为您提供帮助,编码愉快:)
【解决方案2】:

需要另一个线程来修复它。

更改监听器类,工作正常:

 class ResolveListener implements ActionListener
    {
        @Override
        public void actionPerformed(ActionEvent e)
        {
            new Thread(new Runnable()
            {
                @Override
                public void run()
                {
                    try {
                        TestContainerButtonJPanel.this.testJPanel.colourCells();
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                }
            }).start();
        }


    }
}

【讨论】:

    猜你喜欢
    • 2015-01-26
    • 2013-12-05
    • 2019-05-01
    • 2011-06-26
    • 1970-01-01
    • 1970-01-01
    • 2011-07-15
    • 1970-01-01
    • 2021-07-20
    相关资源
    最近更新 更多