How to make my user-interface self adapt to the show and hide of JPanel?

本秂侑毒 提交于 2021-01-28 05:13:40

问题


Recently I'm writing a mail system client using Java (I chose swing to write the GUI and use IDEA to hardcode my GUI). In the Compose module, I want to show or hide the textfield for CC and Bcc when I click the corresponding buttons.

So I googled and browsed the following questions and doc on the web:

  • How to make JPanel scrollable in Java?
  • How to make JPanel scrollable?
  • Scrolling a JPanel
  • Doc: JScrollPane

Finally, I chose the JScrollPane to implement it.

My simplified sample code is as follows (the original code is tedious):

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

}

However, no matter which JPanel I apply JScrollPane to, I cannot make my interface adaptive to the hide and show of my JContainer2.
How can I modify it, or what control to use to replace JScrollPane? Any suggestions will be welcome.

And here is my platform information:

java -version
java version "1.8.0_212" Java(TM) SE Runtime Environment (build 1.8.0_212-b10)
Java HotSpot(TM) 64-Bit Server VM (build 25.212-b10, mixed mode)

OS: win10 1909
arch: amd64


回答1:


I rewrote your code. Explanations appear after it.

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

You should always try to use a layout manager. The code above uses GridBagLayout but there are several other layout managers that are good at handling forms, including GroupLayout and SpringLayout as well as third party layout managers like MiG Layout and FormLayout.

In order to "show" and "hide" the middle row in your form, simply set the visible property to true or false. If the text of the button is SHOW, then when the user clicks on it, I change the button text to HIDE and make lbl2 and txf2 both visible. If the button text is HIDE, then when the user clicks the button I change the text to SHOW and make lbl2 and txf2 not visible.

Because I use a layout manager, it handles resizing the JPanel whenever the contents of the JPanel are changed. When you don't use a layout manager, then you have to write code that handles the resizing and of-course your code does not, hence your problem.



来源:https://stackoverflow.com/questions/62964489/how-to-make-my-user-interface-self-adapt-to-the-show-and-hide-of-jpanel

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!