如何从另一个子 JPanel(Java Swing)中的输入触发一个子 JPanel 中的操作?

Posted

技术标签:

【中文标题】如何从另一个子 JPanel(Java Swing)中的输入触发一个子 JPanel 中的操作?【英文标题】:How to trigger action in one child JPanel from input in another child JPanel (Java Swing)? 【发布时间】:2017-07-24 14:59:54 【问题描述】:

我正在尝试在 Java Swing 中实现 GUI(我是 Swing 新手)。我有一个包含 2 个面板的父面板。一个左面板和一个右面板。左侧面板有一个 JComboBox 下拉菜单。右侧面板是带有 7 张卡片的 CardLayout。我想根据左侧面板中 JComboBox 中的选择更改右侧面板中显示的卡片。所有 3 个面板都是独立的类:LeftPanel.java、RightPanel.java 和 ParentPanel.java。我很难找到一个地方来放置这个动作的动作监听器。 LeftPanel 看不到 RightPanel 的 CardLayout,ParentPanel 也无法访问子 RightPanel 的 CardLayout。我看到了一些关于访问另一个 JPanel 的 CardLayout 的帖子,但到目前为止,没有一种方法对我有用。我的设计有缺陷吗?或者有可能实现这一目标吗?

编辑 感谢您迄今为止的建议。下面给出的是我的 MCVE。请注意,每个类都在其自己的 (.java) 文件中。我这样做不是为了方便维护而将所有内容都放在 Frame 类中。我以前在一堂课里有所有东西,它工作得很好,但它变成了一个包含 2000 多行代码和 20 多个面板的长文件。

//包含Main方法的类MainFrame:

包 tempgui; 公共类 MainFrame 扩展 JFrame

JFrame Frame1;

public static void main(String[] args)

    new MainFrame();


public MainFrame()

    Frame1 = new JFrame();
    Frame1.setDefaultCloseOperation(EXIT_ON_CLOSE);

    Frame1.getContentPane().add(new ParentPanel(), BorderLayout.CENTER);        

    Frame1.setSize(800, 600);
    Frame1.setLocationRelativeTo(null);
    Frame1.pack();

    Frame1.setVisible(true);

//类父面板: 公共类 ParentPanel 扩展 JPanel

private JPanel ParentPanel;
private LeftPanel LP;
private RightPanel RP;

public ParentPanel()

    ParentPanel = new JPanel();
    LP = new LeftPanel();
    RP = new RightPanel();

    ParentPanel.setLayout(new GridLayout(1,2));

    ParentPanel.add(LP);
    ParentPanel.add(RP);

    add(ParentPanel);

//类LeftPanel: 公共类 LeftPanel 扩展 JPanel

private JPanel LeftPanel;
private JComboBox J1;

public LeftPanel()

    LeftPanel = new JPanel();

    String[] Arr = "RP1","RP2";

    J1 = new JComboBox(Arr);

    LeftPanel.add(J1);

    add(LeftPanel);

//类右面板: 公共类 RightPanel 扩展 JPanel

private JPanel RightPanel;
private RP1Panel RP1;
private RP2Panel RP2;
private CardLayout C1;

public RightPanel()

    RightPanel = new JPanel();
    RP1 = new RP1Panel();
    RP2 = new RP2Panel();

    C1 = new CardLayout();

    RightPanel.setLayout(C1);

    RightPanel.add(RP1, "RP1");
    RightPanel.add(RP2, "RP2");
    C1.show(RightPanel, "RP1");

    add(RightPanel);

//类RP1Panel: 公共类 RP1Panel 扩展 JPanel

private JPanel RP1;
private JLabel JRP1;

public RP1Panel()

    RP1 = new JPanel();
    JRP1 = new JLabel("RP1 Panel");
    RP1.add(JRP1);
    add(RP1);

//类RP2Panel: 公共类 RP2Panel 扩展 JPanel

private JPanel RP2;
private JLabel JRP2;

public RP2Panel()

    RP2 = new JPanel();
    JRP2 = new JLabel("RP2 Panel");
    RP2.add(JRP2);
    add(RP2);

【问题讨论】:

"Or is it possible to achieve this?" -- 是的,非常肯定。 "Is there a flaw in my design?" -- 没有相关代码,最好是有效的minimal reproducible example,无法说出您的问题出在哪里。同样,考虑创建和发布一个 MCVE,一个小程序,小到可以作为代码格式的文本发布在您的问题中,一个可以编译和运行的程序,它可以向我们展示您的问题。它不是你的整个程序,它没有它的所有功能,但它再次为我们运行,它向我们展示了问题。 “所有 3 个面板都是单独的类” 解决这个难题的第一步可能是“不要不必要地扩展组件类”。您能在这里解释一下扩展面板的情况吗? 【参考方案1】:

我会尝试为我的类提供允许其他类从中提取“state”信息的方法,例如组合框的状态,并允许其他类改变它们,例如允许要添加到组合框中的侦听器。例如:

// Class LeftPanel:
class LeftPanel extends JPanel 
    private JPanel leftPanel;
    private JComboBox<String> comboBox; //!!

    // !!
    public LeftPanel(String[] comboTexts) 
        leftPanel = new JPanel();
        comboBox = new JComboBox<>(comboTexts); // !!
        leftPanel.add(comboBox);
        add(leftPanel);
    

    // !!
    public String getComboSelection() 
        return comboBox.getSelectedItem().toString();
    

    // !!
    public void comboAddActionListener(ActionListener listener) 
        comboBox.addActionListener(listener);
    

然后其他类可以监听组合框的变化,并在需要时提取选择。右侧面板同样具有允许更改其显示的“卡片”JPanel 的方法。比如:

// Class RightPanel:
class RightPanel extends JPanel 
    private JPanel rightPanel;
    private RP1Panel rightPanel1;
    private RP2Panel rightPanel2;
    private CardLayout cardLayout;

    public RightPanel() 
        rightPanel = new JPanel();
        rightPanel1 = new RP1Panel();
        rightPanel2 = new RP2Panel();
        cardLayout = new CardLayout();
        rightPanel.setLayout(cardLayout);
        rightPanel.add(rightPanel1, RP1Panel.NAME); //!!
        rightPanel.add(rightPanel2, RP2Panel.NAME);  // !!
        cardLayout.show(rightPanel, RP1Panel.NAME); // !!
        add(rightPanel);
    

    // !! 
    public void showCard(String name) 
        cardLayout.show(rightPanel, name);
    

它们可以主要捆绑在一起:

// Class ParentPanel:
class ParentPanel extends JPanel 
    private JPanel ParentPanel;
    private LeftPanel leftPanel;
    private RightPanel rightPanel;

    public ParentPanel() 
        ParentPanel = new JPanel();
        leftPanel = new LeftPanel(new String[] RP1Panel.NAME, RP2Panel.NAME);
        rightPanel = new RightPanel();
        ParentPanel.setLayout(new GridLayout(1, 2));
        ParentPanel.add(leftPanel);
        ParentPanel.add(rightPanel);
        add(ParentPanel);

        // !!
        leftPanel.comboAddActionListener(e -> 
            String selection = leftPanel.getComboSelection();
            rightPanel.showCard(selection);
        );
    

整个 MCVE 可能如下所示:

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.GridLayout;
import java.awt.event.ActionListener;

import javax.swing.*;

public class FooGui 
    public static void main(String[] args) 
        new MainFrame();
    


class MainFrame extends JFrame 
    JFrame Frame1;

    public MainFrame() 
        Frame1 = new JFrame();
        Frame1.setDefaultCloseOperation(EXIT_ON_CLOSE);
        Frame1.getContentPane().add(new ParentPanel(), BorderLayout.CENTER);
        Frame1.setSize(800, 600);
        Frame1.setLocationRelativeTo(null);
        Frame1.pack();
        Frame1.setVisible(true);
    


// Class ParentPanel:
class ParentPanel extends JPanel 
    private JPanel ParentPanel;
    private LeftPanel leftPanel;
    private RightPanel rightPanel;

    public ParentPanel() 
        ParentPanel = new JPanel();
        leftPanel = new LeftPanel(new String[] RP1Panel.NAME, RP2Panel.NAME);
        rightPanel = new RightPanel();
        ParentPanel.setLayout(new GridLayout(1, 2));
        ParentPanel.add(leftPanel);
        ParentPanel.add(rightPanel);
        add(ParentPanel);

        // !!
        leftPanel.comboAddActionListener(e -> 
            String selection = leftPanel.getComboSelection();
            rightPanel.showCard(selection);
        );
    


// Class LeftPanel:
class LeftPanel extends JPanel 
    private JPanel leftPanel;
    private JComboBox<String> comboBox; //!!

    // !!
    public LeftPanel(String[] comboTexts) 
        leftPanel = new JPanel();
        comboBox = new JComboBox<>(comboTexts); // !!
        leftPanel.add(comboBox);
        add(leftPanel);
    

    // !!
    public String getComboSelection() 
        return comboBox.getSelectedItem().toString();
    

    // !!
    public void comboAddActionListener(ActionListener listener) 
        comboBox.addActionListener(listener);
    


// Class RightPanel:
class RightPanel extends JPanel 
    private JPanel rightPanel;
    private RP1Panel rightPanel1;
    private RP2Panel rightPanel2;
    private CardLayout cardLayout;

    public RightPanel() 
        rightPanel = new JPanel();
        rightPanel1 = new RP1Panel();
        rightPanel2 = new RP2Panel();
        cardLayout = new CardLayout();
        rightPanel.setLayout(cardLayout);
        rightPanel.add(rightPanel1, RP1Panel.NAME); //!!
        rightPanel.add(rightPanel2, RP2Panel.NAME);  // !!
        cardLayout.show(rightPanel, RP1Panel.NAME); // !!
        add(rightPanel);
    

    // !! 
    public void showCard(String name) 
        cardLayout.show(rightPanel, name);
    


// Class RP1Panel:
class RP1Panel extends JPanel 
    // !!
    public static final String NAME = "right panel 1";
    private JPanel RP1;
    private JLabel JRP1;

    public RP1Panel() 
        setName(NAME);
        RP1 = new JPanel();
        JRP1 = new JLabel("RP1 Panel");
        RP1.add(JRP1);
        add(RP1);
    


// Class RP2Panel:
class RP2Panel extends JPanel 
    // !!
    public static final String NAME = "right panel 2";
    private JPanel RP2;
    private JLabel JRP2;

    public RP2Panel() 
        setName(NAME);
        RP2 = new JPanel();
        JRP2 = new JLabel("RP2 Panel");
        RP2.add(JRP2);
        add(RP2);
    

【讨论】:

非常感谢!这非常适合我的情况。我想我可以使用类似的方法在一个 JPanel 上实现 Back、Next 按钮来控制在另一个 JPanel 上的 Cards 之间来回翻转。类似于创建向导对话框。

以上是关于如何从另一个子 JPanel(Java Swing)中的输入触发一个子 JPanel 中的操作?的主要内容,如果未能解决你的问题,请参考以下文章

Java Swing - 如何更改 JPanel 的 TitledBorder 上的字体大小?

如何在 JPanel java swing 中移动标签

Java Swing 在单击我要删除的 jpanel 中存在的 Jbutton 时删除 Jpanel

React Native ScrollView - 如何从另一个子组件按钮滚动到子组件?

如何从另一个子 td 元素检查父 tr 元素内的 td 元素的值

Java / Swing:从JPanel内部获取Window / JFrame