提问者:小点点

如何使我的用户界面自我适应JPanel的显示和隐藏?


最近我正在使用Java编写一个邮件系统客户端(我选择了swing来编写GUI并使用IDEA来硬编码我的GUI)。在撰写模块中,当我单击相应的按钮时,我想显示或隐藏CC和密件抄送的文本字段。

所以我在网上搜索并浏览了以下问题和文档:

  • 如何使JPanel在Java中滚动?
  • 如何使JPanel可滚动?
  • 滚动JPanel
  • Doc:JScrollPane

最后,我选择了JScrollPane来实现它。

我的简化示例代码如下(原始代码繁琐):

import java.awt.CardLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class Demo extends JFrame implements ActionListener {
    private static final long serialVersionUID = 1L;

    private JLabel lbl1;
    private JTextField txf1;

    private JLabel lbl2;
    private JTextField txf2;
    // container for lbl2 and txf2, which should be able to be shown or hidden
    private JPanel pnlContainer2;

    private JLabel lbl3;
    private JTextField txf3;
    // container for lbl3 and txf3
    private JPanel pnlContainer3; 

    private JButton btnShow;

    // the container I want to move when I click btnShow
    private JPanel pnlBody; 

    // the panel to hold my "cards"
    // In this example, I include it just to show what controls are on my interface.
    private JPanel pnlContent;

    private JPanel pnlContainer;

    // here, I want to use JScrollPane to make my pnlContainer scrollable
    // to adapt to my interface
    private JScrollPane scrollPane;

    public Demo() {
        init();
    }

    private void init() {
        pnlContainer = new JPanel(new CardLayout(), true);
        pnlContainer.setBounds(0, 0, 200, 180);

        pnlContent = new JPanel(null, true);
        pnlContent.setBounds(0, 0, 200, 180 + 50);

        scrollPane = new JScrollPane(pnlContent, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        scrollPane.setBounds(0, 0, 200, 180);
        pnlContainer.add(scrollPane);

        pnlBody = new JPanel(null, true);

        lbl1 = new JLabel("lbl1");
        lbl1.setBounds(10, 20, 40, 30);

        txf1 = new JTextField();
        txf1.setBounds(60, 20, 120, 30);

        pnlContent.add(lbl1);
        pnlContent.add(txf1);

        pnlContainer2 = new JPanel(null, true);
        pnlContainer2.setBounds(0, 70, 180, 30);

        lbl2 = new JLabel("lbl2");
        lbl2.setBounds(10, 0, 40, 30);

        txf2 = new JTextField();
        txf2.setBounds(60, 0, 120, 30);

        pnlContainer2.add(lbl2);
        pnlContainer2.add(txf2);
        pnlContainer2.setVisible(false);
        pnlContent.add(pnlContainer2);

        pnlBody = new JPanel(null, true);
        pnlBody.setBounds(0, 70, 180, 90);

        pnlContainer3 = new JPanel(null, true);
        pnlContainer3.setBounds(0, 0, 180, 30);
        pnlBody.add(pnlContainer3);

        lbl3 = new JLabel("lbl3");
        lbl3.setBounds(10, 0, 40, 30);

        txf3 = new JTextField();
        txf3.setBounds(60, 0, 120, 30);

        pnlContainer3.add(lbl3);
        pnlContainer3.add(txf3);

        btnShow = new JButton("show");
        btnShow.setBounds(60, 50, 80, 30);
        btnShow.addActionListener(this);
        pnlBody.add(btnShow);

        pnlContent.add(pnlBody);

        this.add(pnlContainer);
        this.setLayout(null);
        this.setTitle("Demo");
        this.setSize(200, 200);
        this.setLocationRelativeTo(null);
        this.setVisible(true);
        this.setResizable(false);
//      ImageIcon icon = new ImageIcon("E:\\Javarepo\\Hmail\\src\\main\\resources\\assets\\hmail.png");
//      this.setIconImage(icon.getImage());
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // TODO Auto-generated method stub
        Object src = e.getSource();
        if (src instanceof JButton) {
            JButton btn = (JButton) src;
            boolean showSelected = false;
            String altText;
            if (btn == btnShow) {
                showSelected = btnShow.getText() == "show";
                altText = showSelected ? "hide" : "show";
                btnShow.setText(altText);
            }
            relayout(showSelected);
        }
    }

    private void relayout(boolean showSelected) {
        int x = pnlBody.getX();
        int y = pnlBody.getY();
        if (showSelected) {
            pnlContainer2.setVisible(true);
            pnlBody.setBounds(x, y + 50, 180, 90);
        } else {
            pnlContainer2.setVisible(false);
            pnlBody.setBounds(x, y - 50, 180, 90);
        }

    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Demo());
    }

}

但是,无论我将JScrollPane应用到哪个JPanel,我都无法使我的界面适应我的JContainer2的隐藏和显示。
我如何修改它,或者使用什么控件来替换JScrollPane?欢迎任何建议。

这是我的平台信息:

java-version
java版本"1.8.0_212"Java(TM)SE运行时环境(build 1.8.0_212-b10)
JavaHotSpot(TM)64位服务器VM(build 25.212-b10,混合模式)

OS: win10 1909
arch:amd64


共1个答案

匿名用户

我重写了你的代码。解释出现在它之后。

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ScrollPaneConstants;
import javax.swing.WindowConstants;

public class Demo2 implements ActionListener, Runnable {
    private static final String HIDE = "HIDE";
    private static final String SHOW = "SHOW";
    
    private JButton button;
    private JLabel lbl2;
    private JFrame frame;
    private JTextField txf2;

    @Override
    public void run() {
        showGui();
    }

    @Override
    public void actionPerformed(ActionEvent event) {
        boolean visible;
        String text;
        String actionCommand = event.getActionCommand();
        switch (actionCommand) {
            case HIDE:
                text = SHOW;
                visible = false;
                break;
            case SHOW:
                text = HIDE;
                visible = true;
                break;
            default:
                text = "???";
                visible = false;
        }
        button.setText(text);
        lbl2.setVisible(visible);
        txf2.setVisible(visible);
    }

    private JPanel createButtonsPanel() {
        JPanel buttonsPanel = new JPanel();
        button = new JButton(SHOW);
        button.addActionListener(this);
        buttonsPanel.add(button);
        return buttonsPanel;
    }

    private JScrollPane createForm() {
        JPanel form = new JPanel(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 0;

        JLabel lbl1 = new JLabel("lbl1");
        form.add(lbl1, gbc);

        gbc.gridx = 1;
        JTextField txf1 = new JTextField(6);
        form.add(txf1, gbc);

        gbc.gridx = 0;
        gbc.gridy = 1;

        lbl2 = new JLabel("lbl2");
        lbl2.setVisible(false);
        form.add(lbl2, gbc);

        gbc.gridx = 1;
        txf2 = new JTextField(6);
        txf2.setVisible(false);
        form.add(txf2, gbc);

        gbc.gridx = 0;
        gbc.gridy = 2;

        JLabel lbl3 = new JLabel("lbl3");
        form.add(lbl3, gbc);

        gbc.gridx = 1;
        JTextField txf3 = new JTextField(6);
        form.add(txf3, gbc);

        return new JScrollPane(form,
                               ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
                               ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
    }

    private void showGui() {
        frame = new JFrame("Demo");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setResizable(false);
        frame.add(createForm(), BorderLayout.CENTER);
        frame.add(createButtonsPanel(), BorderLayout.PAGE_END);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    /**
     * Start here.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Demo2());
    }
}

您应该始终尝试使用布局管理器。上面的代码使用GridBagLayout,但还有其他几个擅长处理表单的布局管理器,包括GroupLayoutSpringLayout以及第三方布局管理器,如MiG Layout和FormLayout。

为了在表单中“显示”和“隐藏”中间行,只需将可见属性设置为truefalse。如果按钮的文本是SHOW,那么当用户单击它时,我将按钮文本更改为HIDE,并使lbl2txf2都可见。如果按钮文本是HIDE,那么当用户单击按钮时,我将文本更改为SHOW,并使lbl2txf2不可见。

因为我使用布局管理器,所以每当JPanel的内容发生变化时,它都会处理调整JPanel的大小。当你不使用布局管理器时,你必须编写处理调整大小的代码,当然你的代码没有,因此你的问题。