我正在尝试创建一个带有 CardLayout 的 JPanel,按下按钮时可以在菜单和论坛之间切换,但我遇到了一个视觉错误,当我切换到论坛时,菜单元素仍在显示。
(如果相关,我的系统规格是: MacBook Air(13 英寸,2015 年初), 2.2 GHz 双核英特尔酷睿 i7, 8 GB 1600 MHz DDR3, 英特尔高清显卡 6000 1536 MB, MacOS 蒙特利 12.6.7)
以下是我的基本实现的简化示例。显然,示例中的某些功能并未完全实现。
主要课程:
import javax.swing.*;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setContentPane(new MainPanel());
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
主面板类:
import javax.swing.*;
import java.awt.*;
public class MainPanel extends JPanel {
private final CardLayout layout = new CardLayout();
private final Menu menuScreen;
private final Forum forumScreen;
public static final String MENU = "1";
public static final String FORUM = "2";
public MainPanel() {
setLayout(layout);
menuScreen = new Menu(this);
add(menuScreen, MENU);
forumScreen = new Forum(this);
add(forumScreen, FORUM);
layout.show(this, MENU);
}
public void navigate (String destination) {
layout.show(this, destination);
switch (destination) {
case MENU -> menuScreen.updateUI();
case FORUM -> forumScreen.updateUI();
}
this.revalidate();
this.updateUI();
}
}
菜单类别:
import java.awt.*;
import java.awt.event.ActionEvent;
public class Menu extends Screen {
private final MainPanel panel;
public Menu(MainPanel panel) {
this.panel = panel;
Button deleteButton = new Button("Delete");
deleteButton.addActionListener(this::delete);
add(deleteButton);
Button loadButton = new Button("Load");
loadButton.addActionListener(this::load);
add(loadButton);
Button forumButton = new Button("Forum");
forumButton.addActionListener(this::toForum);
add(forumButton);
}
private void toForum(ActionEvent actionEvent) {
panel.navigate(MainPanel.FORUM);
}
private void load(ActionEvent actionEvent) {
}
private void delete(ActionEvent actionEvent) {
}
}
论坛课程:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
public class Forum extends Screen {
private final MainPanel panel;
private final JSpinner heightField = new JSpinner(new SpinnerNumberModel(1,1,Integer.MAX_VALUE,1));
private final JSpinner widthField = new JSpinner(new SpinnerNumberModel(1, 1, Integer.MAX_VALUE, 1));
public Forum(MainPanel panel) {
this.panel = panel;
add(new Label("Forum", Label.CENTER));
add(new Label("Height"));
add(heightField);
add(new Label("Width"));
add(widthField);
Button exitButton = new Button("Exit");
exitButton.addActionListener(this::exit);
add(exitButton);
}
private void exit(ActionEvent actionEvent) {
panel.navigate(MainPanel.MENU);
}
}
屏幕类别:
import javax.swing.*;
public class Screen extends JPanel {
public Screen() {
setBorder(BorderFactory.createEmptyBorder(30,30,30,30));
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
}
}
从功能上讲,代码成功地在面板之间切换,但我一直遇到视觉故障,即最后一个面板的元素显示并覆盖新面板上的元素。我仍然可以选择新面板中被覆盖的元素,并且在我这样做之后,它们似乎被切换到有故障的元素前面的前景。
注意:这是一个较大项目的一部分,因此此处看到的 UI 可能与上面的代码不完全匹配。不过,我要指出的是,在使用 CardLayout 时,整个项目中都出现了类似的故障。
我尝试了多种修复方法。我将java版本回滚到java 11,但仍然遇到同样的问题。我制作了一个加载卡来强制用户界面通过两个开关进行更新,但我发现空的加载卡并不能解决问题,并且带有元素的加载卡仍然会导致视觉故障。如代码中所示,我尝试了各种可能更新面板的调用,例如 revalidate、updateUI 和 repaint,但我尝试过的任何方法都不起作用。
如果您有任何建议,请告诉我。
看来,通过从 awt 组件(Button 和 Label)切换到 swing 轻量级组件(JButton 和 JLabel)可以解决视觉问题。例如,菜单类是:
import javax.swing.*;
import java.awt.event.ActionEvent;
public class Menu extends Screen {
private final MainPanel panel;
public Menu(MainPanel panel) {
this.panel = panel;
JButton deleteButton = new JButton("Delete");
deleteButton.addActionListener(this::delete);
add(deleteButton);
JButton loadButton = new JButton("Load");
loadButton.addActionListener(this::load);
add(loadButton);
JButton forumButton = new JButton("Forum");
forumButton.addActionListener(this::toForum);
add(forumButton);
}
private void toForum(ActionEvent actionEvent) {
panel.navigate(MainPanel.FORUM);
}
private void load(ActionEvent actionEvent) {
}
private void delete(ActionEvent actionEvent) {
}
}
感谢并感谢充满鳗鱼的气垫船