【问题标题】:how to repaint and or revalidate a JPanel如何重绘和/或重新验证 JPanel
【发布时间】:2020-03-31 12:37:05
【问题描述】:

我现在正在学习 Java,并尝试使用 Swing 制作记忆游戏。

在应用程序中,我希望能够调整游戏板的大小(这是一个带有多个按钮的 JPanel)。我尝试使用几个 JButton 来实现这一点,它们都具有相同的自定义 Actionlistener。按钮在它们注册点击并成功设置我的模型尺寸的意义上起作用。但是我无法让我的面板重绘。

下面的代码是否足以发现问题?

编辑:有人询问后,我添加了更多代码。

我将面板作为参数传递给我的听众。我不确定这是否是 Java 中的好习惯。还有更优雅的方式吗?

public class MemoryApp {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                MemoryModel model = new MemoryModel();
                MemoryView view = new MemoryView(model);
                MemoryPanel panel = new MemoryPanel(model);
                new MemoryController(model, view, panel);
            }
        });
    }
}
public class MemoryModel {
    private String faceText;
    private boolean faceUp;
    private int rows;
    private int cols;
    private int size;
    private ArrayList<String> cards;

    MemoryModel(){
        this.rows = 2;
        this.cols = 3;
        this.size = this.rows * this.cols;
        this.cards = new ArrayList<String>();
        generateCards(getSize());
    }

    private void generateCards(int s) {
        for (int i=0; i<s; i++) {this.cards.add("" + i);}   
    }

    public String getCard(int index) {return cards.get(index);}
    public int getSize() {return size;}

    public void setCols(int cols) {this.cols = cols;}
    public void setRows(int rows) {this.rows = rows;}
    public void setSize(int size) {this.size = size;}
}
public class MemoryView extends JFrame{

    private MemoryPanel memoryPanel;
    private ToolBar toolBar;

    public MemoryView(MemoryModel model){
        super("title");
        // setup frame configuration
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(640, 320);
        setLocationRelativeTo(null);
        setVisible(true);

        // GUI elements
        memoryPanel = new MemoryPanel(model);
        toolBar = new ToolBar(model, memoryPanel);

        // layout
        setLayout(new BorderLayout());

        // add components
        add(toolBar, BorderLayout.NORTH);
        add(memoryPanel, BorderLayout.CENTER);
    }
}
public class MemoryPanel extends JPanel{

    private ArrayList<JButton> memoryButtons;
    private CardListener cardListener;

    public MemoryPanel(MemoryModel model) {
        memoryButtons = new ArrayList<JButton>();
        cardListener = new CardListener(model);

        for (int i=0; i < model.getSize() ; i++) {
            JButton button = new JButton("text");
            memoryButtons.add(button);
            add(button);
        }

        setBorder(BorderFactory.createEtchedBorder());
        setLayout(new GridLayout(model.getRows() ,model.getCols()));
    }
}
public class ToolBar extends JPanel{


    private JButton resizeSmall;
    private JButton resizeMedium;
    private ButtonListener buttonListener;

    public ToolBar(MemoryModel model, MemoryPanel memoryPanel) {
        buttonListener = new ButtonListener(model, memoryPanel);

        resizeSmall = new JButton("resizeSmall");
        resizeMedium = new JButton("resizeMedium");

        resizeSmall.setName("resizeSmall");
        resizeMedium.setName("resizeMedium");

        resizeSmall.addActionListener(buttonListener);
        resizeMedium.addActionListener(buttonListener);

        add(resizeSmall);
        add(resizeMedium);

        setBorder(BorderFactory.createEtchedBorder());
        setLayout(new GridLayout(1, 2));
    }
}
public class ButtonListener implements ActionListener{

    private MemoryModel model;
    private int rows;
    private int cols;
    private JButton button;
    private MemoryPanel panel;

    public ButtonListener(MemoryModel model, MemoryPanel memoryPanel) {
        this.model = model;
        this.panel = memoryPanel;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        button = ((JButton) e.getSource());
        switch(button.getName()) {
            case "resizeSmall":
                rows = 2;
                cols = 3;
                break;
            case "resizeMedium":
// etc
            case "resizeLarge":
// etc
        }
        model.setCols(cols);
        model.setRows(rows);
        model.setSize(rows*cols);
        panel.revalidate();
        panel.repaint();
    }
}

【问题讨论】:

  • 请发帖minimal reproducible example。 (ButtonListener 已发布但未在代码中使用。另一方面 CardListener 已使用但未发布)
  • 对不起。我添加了更多课程。并删除了对 CardListener 的引用,因为它与此处无关。
  • 用户点击ToolBar 中的两个JButtons resizeSmallresizeMedium 之一,这应该会改变网格的尺寸并且您想在网格的每个单元格中放置一个单独的JButton。我说的对吗?
  • 是的,没错。

标签: java swing listener


【解决方案1】:

但是我无法让我的面板重绘。

是的,当您在面板上调用repaint() 时,面板将重绘。

但是,没有任何变化,因为您没有更改面板上的任何内容。

在创建类的实例时创建所有按钮并将它们添加到面板中。

成功设置我的模型尺寸。

是的,但您从未告诉面板尺寸已更改。当内存模型发生变化时,您在面板中没有任何逻辑可以更改任何内容。

因此,在您的 MemoryPanel 类中,您需要一个 reset(...) 方法。此方法将删除所有按钮,然后根据MemoryModel 中的新值重新创建它们。请注意,在创建 MemoryPanel 实例时,也会在您的构造函数中调用此 reset() 方法。

【讨论】:

  • 谢谢这有帮助。我添加了 ClearPanel() 和 ResetPanel() 方法。我还在我的模型中添加了一个 ResetCards() 方法来添加额外的卡片。
【解决方案2】:

问题出在MemoryView 类中。你setVisible(true); 然后:

// GUI elements
memoryPanel = new MemoryPanel(model);
toolBar = new ToolBar(model, memoryPanel);

// layout
setLayout(new BorderLayout());

// add components
add(toolBar, BorderLayout.NORTH);
add(memoryPanel, BorderLayout.CENTER);

您应该首先添加组件并准备布局,然后将框架设置为可见。例如:

frame.add(panel);
frame.add(anotherPanel);
//after adds, show the frame
frame.setVisible(true);

提到它的好答案是Does placing setVisible() function in the beginning of the function be different when I placed it at the end of that function?

【讨论】:

  • 我听从了你的建议。但它并没有改变程序的功能。只是要清楚。我可以绘制 GUI 及其所有组件。它只是不重绘。您发布的链接建议不要扩展 JFrame。我也改变了这个,但这也没有改变任何东西。
猜你喜欢
  • 1970-01-01
  • 2013-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-22
  • 2013-10-18
  • 1970-01-01
  • 2012-06-18
相关资源
最近更新 更多