小编典典

Java Swing: GUI未更新某些属性

java

编辑:以下最简单,可检查的问题

恢复

我正在做一个Latin Square应用程序,该应用程序设置一个大小为s的正方形,并且您
需要对它进行着色,例如在
同一行或同一列中使用不同的颜色。

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

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

问题是,比找到解决方案时,我要停下
来观察几秒钟,然后继续寻找其他对象(我将使用
Thread.sleep()进行此操作)。

但是我正在看广场没有变色。仅当完成
方法时,才会改变自身。

主要问题

在此处输入图片说明

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

在此处输入图片说明

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

而且我不知道为什么:(

更详细

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

为此,我使用BorderLayout。

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

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

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

因此,我进行了检查,然后检查是否为正方形着色并暂停执行
(Scanner.nextLine()或Thread.sleep())不会在GUI中进行更改,但是
在调试时,属性中的正方形已着色,所以我不太明白
为什么会失败。

我在想什么

所以我有一个按钮,单击该按钮可以解决正方形。而且我认为,我
真的不知道,但是我怀疑这样做会创建一个新的Thread
或其他东西,因此无法更新GUI。并且只有当完成时才这样做。

反正有改变吗?

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

一个简单的问题

我已阅读注释,以搜索与此类似的最小和容易检查的问题

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

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

我认为这类似于我之前遇到的问题。

这是我可以解决的最低代码。

    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);

            }
        }

    }


}

阅读 267

收藏
2020-11-26

共1个答案

小编典典

好的,首先要注意的是:

  1. 不要使用Thread.sleep()它更新您的GUI,这会阻止EDT
  2. 您没有将程序放在EDT上,请参见此答案中的第2点
  3. 不要扩展JFrame,而是创建它的实例,请参见:扩展JFrame与在程序内部创建它
  4. setVisible(...)在将所有组件添加到程序之前,不要使其可见(即,调用)。这可能会导致您的程序以错误的方式运行。
  5. 尝试不要创建自己的线程,而是使用aSwing Timer或a Swing Worker(问题注释中的链接)
    因此,考虑到所有这些因素后,我决定创建一个
    遵循上述所有规则的新程序,并
    在这段时间过后使单元格变蓝3秒钟或变白,并更新JButton
    以及禁用防止一次执行多个计时器。

    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);
    }
    

    }

2020-11-26