Java Swing:GUI没有更新某些属性

问题描述 投票:2回答:2

编辑:一个最简单,最简单和可检查的问题

恢复

我正在做一个拉丁方应用程序,它设置一个大小为s的正方形,你需要用一些限制来着色它,例如,在同一行或同一列中不是相同的颜色。

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

我试图用Swing来做一些图形和更好的外观。

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

但我看着这个广场没有变色。只有完成方法后,才能自行更改。

主要问题

enter image description here

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

enter image description here

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

我不知道为什么:(

更详细

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

为此,我使用BorderLayout。

所以左边的第一个面板,就像基本的配置菜单,用户可以设置方块的大小并运行它以获得解决方案。

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

所以我需要按钮的事件。大小不是给我问题,但解决是的。

所以我检查了,比如我为某些正方形着色并暂停执行(Scanner.nextLine()或Thread.sleep())没有在GUI中进行更改,但是当我调试时,正方形在属性中着色,所以我不太明白为什么是faling。

在哪里我认为是问题

所以我有一个按钮,点击时解决方块。我想,我真的不知道,但我怀疑,这样做会创建一个新的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);

            }
        }

    }


}
java swing user-interface
2个回答
2
投票

好的,首先要做的事情:

  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(问题评论中的链接)

因此,考虑到所有这些因素,我决定创建一个遵循上述所有规则的新程序,并在该时间过后使单元格变为蓝色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);
    }
}

你可以复制粘贴它并看到与我相同的结果:

enter image description here enter image description here


0
投票

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

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

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


    }
}
© www.soinside.com 2019 - 2024. All rights reserved.