试图让摆动菜单与 GridBagLayout 一起使用
Trying to get a swing menu to work with GridBagLayout
我正在尝试构建一个具有两个垂直列的应用程序,锚定在左侧,
右边是一个大盒子。我可以让第一个菜单贴在右边,
但由于某种原因,第二个菜单不会出现在第一个菜单旁边。我已经阅读了一些关于将额外的 space 推向最后一列和最后一行(向右)的内容。我该如何处理?
P.S。我正在使用网格包布局。
这是我得到的:
主用户视图class:
包图形用户界面;
import actions.DepositAddButtonAction;
import actions.DepositButtonAction;
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
public class UserView {
public JFrame frame;
private JPanel menuPanel;
private JPanel secondMenuPanel;
private JPanel contentPanel;
private JButton depositButton;
private JButton creditButton;
private JButton exchangeButton;
private JButton simulationButton;
private JButton informationButton;
private JLabel menuLabel;
private GridBagLayout gridBagLayout;
private GridBagConstraints constraints;
private Border border;
public UserView() {
frame = new JFrame("E-Banking");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
menuPanel = new JPanel();
secondMenuPanel = new JPanel();
contentPanel = new JPanel();
depositButton = new JButton("Deposit: ", new ImageIcon(UserView.class.getResource("/money_box_icon.png")));
creditButton = new JButton("Credit: ", new ImageIcon(UserView.class.getResource("/credit_icon.png")));
exchangeButton = new JButton("Exchange: ", new ImageIcon(UserView.class.getResource("/exchange_icon.png")));
simulationButton = new JButton("Simulation: ", new ImageIcon(UserView.class.getResource("/simulation_icon.png")));
informationButton = new JButton("Information: ", new ImageIcon(UserView.class.getResource("/info_icon.png")));
menuLabel = new JLabel(new ImageIcon(UserView.class.getResource("/bank_icon.png")), SwingConstants.LEFT);
gridBagLayout = new GridBagLayout();
constraints = new GridBagConstraints();
border = BorderFactory.createLineBorder(new Color(102, 102, 153), 1, true);
frame.setSize(800, 600);
applyButtonStyles();
initialize();
}
private void applyButtonStyles() {
depositButton.setHorizontalTextPosition(SwingConstants.RIGHT);
creditButton.setHorizontalTextPosition(SwingConstants.RIGHT);
exchangeButton.setHorizontalTextPosition(SwingConstants.RIGHT);
simulationButton.setHorizontalTextPosition(SwingConstants.RIGHT);
informationButton.setHorizontalTextPosition(SwingConstants.RIGHT);
menuLabel.setHorizontalAlignment(SwingConstants.RIGHT);
menuPanel.setBorder(border);
secondMenuPanel.setBorder(border);
secondMenuPanel.setVisible(false);
contentPanel.setBorder(border);
contentPanel.setVisible(false);
}
private void initialize() {
menuLabel.setText("E-Banking");
constraints.gridx = 0;
constraints.gridy = 0;
constraints.anchor = GridBagConstraints.FIRST_LINE_START;
constraints.fill = GridBagConstraints.BOTH;
constraints.insets = new Insets(4, 4, 4, 4);
menuPanel.setLayout(gridBagLayout);
menuPanel.add(menuLabel);
constraints.gridy++;
menuPanel.add(depositButton, constraints);
constraints.gridy++;
menuPanel.add(creditButton, constraints);
constraints.gridy++;
menuPanel.add(exchangeButton, constraints);
constraints.gridy++;
menuPanel.add(simulationButton, constraints);
constraints.gridy++;
menuPanel.add(informationButton, constraints);
constraints.gridx = 1;
constraints.gridy = 0;
frame.getContentPane().setLayout(gridBagLayout);
constraints.gridx = 0;
constraints.gridy = 0;
constraints.weightx = 0.4;
constraints.weighty = 0.4;
constraints.fill = GridBagConstraints.NONE;
frame.getContentPane().add(menuPanel, constraints);
constraints.gridx++;
frame.getContentPane().add(secondMenuPanel, constraints);
constraints.gridx++;
frame.getContentPane().add(contentPanel, constraints);
constraints.gridx++;
DepositAddButtonAction depositAddButtonAction = new DepositAddButtonAction(contentPanel);
DepositButtonAction depositButtonAction = new DepositButtonAction(secondMenuPanel, contentPanel, depositAddButtonAction, null, null);
depositButton.addActionListener(depositButtonAction);
}
}
另一个 class 表示第一个按钮的行为:
package actions;
import gui.UserView;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class DepositButtonAction implements ActionListener {
private JPanel secondMenuPanel;
private JPanel contentPanel;
private JButton addButton;
private JButton queryButton;
private JLabel operationLabel;
private GridBagLayout gridBagLayout;
private GridBagConstraints constraints;
public DepositButtonAction(JPanel secondMenuPanel, JPanel contentPanel, ActionListener otherDepositAddButtonAction,
ActionListener otherDepositRemoveButtonAction, ActionListener otherDepositQueryButtonAction) {
this.secondMenuPanel = secondMenuPanel;
secondMenuPanel.setVisible(false);
this.contentPanel = contentPanel;
addButton = new JButton("Request", new ImageIcon(UserView.class.getResource("/add_icon.png")));
queryButton = new JButton("Query", new ImageIcon(UserView.class.getResource("/info_icon.png")));
operationLabel = new JLabel(new ImageIcon(UserView.class.getResource("/options_icon.png")));
operationLabel.setText("Options ");
gridBagLayout = new GridBagLayout();
constraints = new GridBagConstraints();
applyStyles();
addButton.addActionListener(otherDepositAddButtonAction);
// removeButton.addActionListener(otherDepositRemoveButtonAction);
// queryButton.addActionListener(otherDepositQueryButtonAction);
}
private void applyStyles() {
secondMenuPanel.setLayout(gridBagLayout);
addButton.setHorizontalTextPosition(SwingConstants.RIGHT);
queryButton.setHorizontalTextPosition(SwingConstants.RIGHT);
}
private void initialize() {
constraints.gridx = 0;
constraints.gridy = 0;
constraints.anchor = GridBagConstraints.FIRST_LINE_START;
constraints.fill = GridBagConstraints.BOTH;
constraints.insets = new Insets(4, 4, 4, 4);
secondMenuPanel.add(operationLabel, constraints);
constraints.gridy++;
secondMenuPanel.add(addButton, constraints);
constraints.gridy++;
secondMenuPanel.add(queryButton, constraints);
}
@Override
public void actionPerformed(ActionEvent arg0) {
secondMenuPanel.setVisible(true);
contentPanel.setVisible(false);
secondMenuPanel.removeAll();
contentPanel.removeAll();
contentPanel.revalidate();
contentPanel.repaint();
initialize();
secondMenuPanel.revalidate();
secondMenuPanel.repaint();
}
}
我想得到什么:
提前致谢!
"constraints.weightx"是你的朋友。
来自“double java.awt.GridBagConstraints.weightx”的 Javadoc:
The grid bag layout manager calculates the weight of a column to be the maximum weightx of all the components in a column. If the resulting layout is smaller horizontally than the area it needs to fill, the extra space is distributed to each column in proportion to its weight. A column that has a weight of zero receives no extra space.
这意味着如果您指定值“0”,下一个组件将紧挨着前一个组件分发。
测试你的代码后,我能够通过在你的 initialize()[=36= 上操纵 constraints.weightx 来实现你想要的] 功能。不过有一个技巧,我只能在所有 MenuPanels 都可见的情况下应用它!
我所做的是这样,所有菜单面板都可见:
constraints.weightx = secondMenuPanel.isVisible() ? 0.0 : 0.4;
constraints.weighty = 0.4;
constraints.fill = GridBagConstraints.NONE;
frame.getContentPane().add(menuPanel, constraints);
constraints.gridx++;
constraints.weightx = 0.4;
frame.getContentPane().add(secondMenuPanel, constraints);
constraints.gridx++;
结果:
如果您需要在隐藏组件(仅在点击按钮时显示)的情况下执行此操作,您将需要更新主框架布局的约束,以便它们正确显示。
希望对您有所帮助。
我已经尝试过在 JPanel
(按钮面板)中使用两个垂直 Box
es(布局)按钮,GridLayout
有两列和一行。此按钮面板位于 JFrame
.
的左侧 (BorderLayout.WEST)
示例代码:
import java.awt.*;
import javax.swing.*;
public class TestingLayout {
public static void main(String[] args) {
gui();
}
private static void gui() {
JFrame frame = new JFrame();
frame.setTitle("JButtons Layout");
JPanel pane = new JPanel();
pane.setLayout(new GridLayout(1, 2));
pane.add(getLeftButtons());
pane.add(getRightButtons());
frame.add(pane, BorderLayout.WEST);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setSize(800, 500);
frame.setVisible(true);
}
private static Box getLeftButtons() {
Box box = Box.createVerticalBox();
box.add(new JButton("b1"));
box.add(new JButton("b2"));
box.add(new JButton("b3"));
box.add(new JButton("b4"));
box.add(new JButton("b5"));
return box;
}
private static Box getRightButtons() {
Box box = Box.createVerticalBox();
box.add(new JButton("b11"));
box.add(new JButton("b12"));
box.add(new JButton("b13"));
return box;
}
}
示例的输出:
请记住,您并不局限于使用单个布局管理器。您可以通过使用多个容器来组合布局管理器,让您专注于每个容器的个性化需求,并进一步隔离功能并降低重叠布局要求的复杂性。
您还应该看看 How to Use CardLayout,它将为您提供在不同视图之间切换的方法。
为此,我采取了稍微不同的方式,我从一个可以包含 "sub menus"
的 "menu container" 的概念开始
public class MenuPane extends JPanel {
public MenuPane() {
setLayout(new GridBagLayout());
}
public void addSubMenuPane(SubMenuPane pane) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.NORTH;
gbc.weighty = 1;
add(pane, gbc);
revalidate();
repaint();
}
public void removeSubMenu(SubMenuPane pane) {
remove(pane);
revalidate();
repaint();
}
public void popLastMenu() {
if (getComponentCount() == 1) {
return;
}
remove(getComponent(getComponentCount() - 1));
revalidate();
repaint();
}
}
public class SubMenuPane extends JPanel {
public SubMenuPane(String name) {
setLayout(new GridLayout(0, 1));
setBorder(new LineBorder(Color.DARK_GRAY));
add(new JLabel(name, JLabel.CENTER));
}
public SubMenuPane addAction(MenuAction action) {
JButton btn = new JButton(action);
add(btn);
return this;
}
}
我想做的是解耦 API 的某些部分并减少 API 的任何一部分对其余部分的知识量。
基本上,这体现在 SubMenuPane
中,它只是一些按钮的容器,这些按钮通过 MenuAction
class 配置和管理,除此之外,它什么都不做.
public interface MenuAction extends Action {
public MenuController getController();
}
public abstract class AbstractMenuAction extends AbstractAction implements MenuAction {
private MenuController controller;
public AbstractMenuAction(MenuController controller, String name) {
this.controller = controller;
putValue(NAME, name);
}
@Override
public MenuController getController() {
return controller;
}
}
MenuAction
基于 Actions API,它提供了一个自包含和可配置的工作单元
为了更好的衡量,我在菜单窗格和菜单操作之间放入了一个控制器。
public interface MenuController {
public void addSubMenu(SubMenuPane subMenuPane);
public void popLastMenu();
}
public class DefaultMenuController implements MenuController {
private MenuPane menuPane;
public DefaultMenuController(MenuPane menuPane) {
this.menuPane = menuPane;
}
@Override
public void addSubMenu(SubMenuPane subMenuPane) {
menuPane.addSubMenuPane(subMenuPane);
}
@Override
public void popLastMenu() {
menuPane.popLastMenu();
}
}
这里的目的是,我不希望这些操作能够对菜单窗格进行不利修改,相反,我将它们限制为只有两个操作。
好的,但这对您有何帮助?
好吧,让我们建立一个菜单并找出...
MenuPane menuPane = new MenuPane();
DefaultMenuController controller = new DefaultMenuController(menuPane);
SubMenuPane ebanking = new SubMenuPane("E-Banking");
ebanking.addAction(new AbstractMenuAction(controller, "Deposit") {
@Override
public void actionPerformed(ActionEvent e) {
getController().popLastMenu();
SubMenuPane deposit = new SubMenuPane("Options").addAction(new AbstractMenuAction(getController(), "Request") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
}).addAction(new AbstractMenuAction(getController(), "Query") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
});
getController().addSubMenu(deposit);
}
}).addAction(new AbstractMenuAction(controller, "Credit") {
@Override
public void actionPerformed(ActionEvent e) {
getController().popLastMenu();
SubMenuPane deposit = new SubMenuPane("Credit-Options").addAction(new AbstractMenuAction(getController(), "Request") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
}).addAction(new AbstractMenuAction(getController(), "Query") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
});
getController().addSubMenu(deposit);
}
}).addAction(new AbstractMenuAction(controller, "Exchange") {
@Override
public void actionPerformed(ActionEvent e) {
getController().popLastMenu();
SubMenuPane deposit = new SubMenuPane("Exchange-Options").addAction(new AbstractMenuAction(getController(), "Request") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
}).addAction(new AbstractMenuAction(getController(), "Query") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
});
getController().addSubMenu(deposit);
}
}).addAction(new AbstractMenuAction(controller, "Simulation") {
@Override
public void actionPerformed(ActionEvent e) {
getController().popLastMenu();
SubMenuPane deposit = new SubMenuPane("Simulation-Options").addAction(new AbstractMenuAction(getController(), "Request") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
}).addAction(new AbstractMenuAction(getController(), "Query") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
});
getController().addSubMenu(deposit);
}
}).addAction(new AbstractMenuAction(controller, "Information") {
@Override
public void actionPerformed(ActionEvent e) {
getController().popLastMenu();
SubMenuPane deposit = new SubMenuPane("Information-Options").addAction(new AbstractMenuAction(getController(), "Request") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
}).addAction(new AbstractMenuAction(getController(), "Query") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
});
getController().addSubMenu(deposit);
}
});
controller.addSubMenu(ebanking);
好的,"What the ... code" 就这么多了。为了简洁起见,我使用了很多匿名 classes,实际上,我可能为每个菜单操作设置了 subclass,但这提供了基本的基础工作。
关键是,每个子菜单都可以简单轻松地制作,独立于 MenuPane
,因为它们通过控制器绑定在一起。
您可以进一步扩展控制器以提供额外的功能来触发创建子视图的操作或提供一种直接通过控制器打开您提供的子视图的方法。
我想展示这个想法的原因是,当你添加新的子菜单时,它会对剩余的内容区域产生影响,如果你试图在单个 layout/container 中维护它,你将不断努力将它们保持在一起并很好地协同工作。
相反,此解决方案包含自己容器的子菜单,该容器仅管理菜单,然后将其添加到另一个容器,可能使用不同的布局管理器,然后单独管理外部关注点。
只是一个想法
可运行示例...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
MenuPane menuPane = new MenuPane();
DefaultMenuController controller = new DefaultMenuController(menuPane);
SubMenuPane ebanking = new SubMenuPane("E-Banking");
ebanking.addAction(new AbstractMenuAction(controller, "Deposit") {
@Override
public void actionPerformed(ActionEvent e) {
getController().popLastMenu();
SubMenuPane deposit = new SubMenuPane("Options").addAction(new AbstractMenuAction(getController(), "Request") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
}).addAction(new AbstractMenuAction(getController(), "Query") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
});
getController().addSubMenu(deposit);
}
}).addAction(new AbstractMenuAction(controller, "Credit") {
@Override
public void actionPerformed(ActionEvent e) {
getController().popLastMenu();
SubMenuPane deposit = new SubMenuPane("Credit-Options").addAction(new AbstractMenuAction(getController(), "Request") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
}).addAction(new AbstractMenuAction(getController(), "Query") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
});
getController().addSubMenu(deposit);
}
}).addAction(new AbstractMenuAction(controller, "Exchange") {
@Override
public void actionPerformed(ActionEvent e) {
getController().popLastMenu();
SubMenuPane deposit = new SubMenuPane("Exchange-Options").addAction(new AbstractMenuAction(getController(), "Request") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
}).addAction(new AbstractMenuAction(getController(), "Query") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
});
getController().addSubMenu(deposit);
}
}).addAction(new AbstractMenuAction(controller, "Simulation") {
@Override
public void actionPerformed(ActionEvent e) {
getController().popLastMenu();
SubMenuPane deposit = new SubMenuPane("Simulation-Options").addAction(new AbstractMenuAction(getController(), "Request") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
}).addAction(new AbstractMenuAction(getController(), "Query") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
});
getController().addSubMenu(deposit);
}
}).addAction(new AbstractMenuAction(controller, "Information") {
@Override
public void actionPerformed(ActionEvent e) {
getController().popLastMenu();
SubMenuPane deposit = new SubMenuPane("Information-Options").addAction(new AbstractMenuAction(getController(), "Request") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
}).addAction(new AbstractMenuAction(getController(), "Query") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
});
getController().addSubMenu(deposit);
}
});
controller.addSubMenu(ebanking);
JPanel someContent = new JPanel() {
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
};
someContent.setBackground(Color.RED);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(menuPane, BorderLayout.WEST);
frame.add(someContent);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface MenuController {
public void addSubMenu(SubMenuPane subMenuPane);
public void popLastMenu();
}
public class DefaultMenuController implements MenuController {
private MenuPane menuPane;
public DefaultMenuController(MenuPane menuPane) {
this.menuPane = menuPane;
}
@Override
public void addSubMenu(SubMenuPane subMenuPane) {
menuPane.addSubMenuPane(subMenuPane);
}
@Override
public void popLastMenu() {
menuPane.popLastMenu();
}
}
public interface MenuAction extends Action {
public MenuController getController();
}
public abstract class AbstractMenuAction extends AbstractAction implements MenuAction {
private MenuController controller;
public AbstractMenuAction(MenuController controller, String name) {
this.controller = controller;
putValue(NAME, name);
}
@Override
public MenuController getController() {
return controller;
}
}
public class MenuPane extends JPanel {
public MenuPane() {
setLayout(new GridBagLayout());
}
public void addSubMenuPane(SubMenuPane pane) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.NORTH;
gbc.weighty = 1;
add(pane, gbc);
revalidate();
repaint();
}
public void removeSubMenu(SubMenuPane pane) {
remove(pane);
revalidate();
repaint();
}
public void popLastMenu() {
if (getComponentCount() == 1) {
return;
}
remove(getComponent(getComponentCount() - 1));
revalidate();
repaint();
}
}
public class SubMenuPane extends JPanel {
public SubMenuPane(String name) {
setLayout(new GridLayout(0, 1));
setBorder(new LineBorder(Color.DARK_GRAY));
add(new JLabel(name, JLabel.CENTER));
}
public SubMenuPane addAction(MenuAction action) {
JButton btn = new JButton(action);
add(btn);
return this;
}
public void pop() {
Container parent = getParent();
if (parent != null) {
parent.remove(this);
parent.revalidate();
parent.repaint();
}
}
}
}
nb:这是一个不完整的解决方案,旨在在处理此类问题时促进 "different way of thinking"
我正在尝试构建一个具有两个垂直列的应用程序,锚定在左侧, 右边是一个大盒子。我可以让第一个菜单贴在右边, 但由于某种原因,第二个菜单不会出现在第一个菜单旁边。我已经阅读了一些关于将额外的 space 推向最后一列和最后一行(向右)的内容。我该如何处理?
P.S。我正在使用网格包布局。
这是我得到的:
主用户视图class: 包图形用户界面;
import actions.DepositAddButtonAction;
import actions.DepositButtonAction;
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
public class UserView {
public JFrame frame;
private JPanel menuPanel;
private JPanel secondMenuPanel;
private JPanel contentPanel;
private JButton depositButton;
private JButton creditButton;
private JButton exchangeButton;
private JButton simulationButton;
private JButton informationButton;
private JLabel menuLabel;
private GridBagLayout gridBagLayout;
private GridBagConstraints constraints;
private Border border;
public UserView() {
frame = new JFrame("E-Banking");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
menuPanel = new JPanel();
secondMenuPanel = new JPanel();
contentPanel = new JPanel();
depositButton = new JButton("Deposit: ", new ImageIcon(UserView.class.getResource("/money_box_icon.png")));
creditButton = new JButton("Credit: ", new ImageIcon(UserView.class.getResource("/credit_icon.png")));
exchangeButton = new JButton("Exchange: ", new ImageIcon(UserView.class.getResource("/exchange_icon.png")));
simulationButton = new JButton("Simulation: ", new ImageIcon(UserView.class.getResource("/simulation_icon.png")));
informationButton = new JButton("Information: ", new ImageIcon(UserView.class.getResource("/info_icon.png")));
menuLabel = new JLabel(new ImageIcon(UserView.class.getResource("/bank_icon.png")), SwingConstants.LEFT);
gridBagLayout = new GridBagLayout();
constraints = new GridBagConstraints();
border = BorderFactory.createLineBorder(new Color(102, 102, 153), 1, true);
frame.setSize(800, 600);
applyButtonStyles();
initialize();
}
private void applyButtonStyles() {
depositButton.setHorizontalTextPosition(SwingConstants.RIGHT);
creditButton.setHorizontalTextPosition(SwingConstants.RIGHT);
exchangeButton.setHorizontalTextPosition(SwingConstants.RIGHT);
simulationButton.setHorizontalTextPosition(SwingConstants.RIGHT);
informationButton.setHorizontalTextPosition(SwingConstants.RIGHT);
menuLabel.setHorizontalAlignment(SwingConstants.RIGHT);
menuPanel.setBorder(border);
secondMenuPanel.setBorder(border);
secondMenuPanel.setVisible(false);
contentPanel.setBorder(border);
contentPanel.setVisible(false);
}
private void initialize() {
menuLabel.setText("E-Banking");
constraints.gridx = 0;
constraints.gridy = 0;
constraints.anchor = GridBagConstraints.FIRST_LINE_START;
constraints.fill = GridBagConstraints.BOTH;
constraints.insets = new Insets(4, 4, 4, 4);
menuPanel.setLayout(gridBagLayout);
menuPanel.add(menuLabel);
constraints.gridy++;
menuPanel.add(depositButton, constraints);
constraints.gridy++;
menuPanel.add(creditButton, constraints);
constraints.gridy++;
menuPanel.add(exchangeButton, constraints);
constraints.gridy++;
menuPanel.add(simulationButton, constraints);
constraints.gridy++;
menuPanel.add(informationButton, constraints);
constraints.gridx = 1;
constraints.gridy = 0;
frame.getContentPane().setLayout(gridBagLayout);
constraints.gridx = 0;
constraints.gridy = 0;
constraints.weightx = 0.4;
constraints.weighty = 0.4;
constraints.fill = GridBagConstraints.NONE;
frame.getContentPane().add(menuPanel, constraints);
constraints.gridx++;
frame.getContentPane().add(secondMenuPanel, constraints);
constraints.gridx++;
frame.getContentPane().add(contentPanel, constraints);
constraints.gridx++;
DepositAddButtonAction depositAddButtonAction = new DepositAddButtonAction(contentPanel);
DepositButtonAction depositButtonAction = new DepositButtonAction(secondMenuPanel, contentPanel, depositAddButtonAction, null, null);
depositButton.addActionListener(depositButtonAction);
}
}
另一个 class 表示第一个按钮的行为:
package actions;
import gui.UserView;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class DepositButtonAction implements ActionListener {
private JPanel secondMenuPanel;
private JPanel contentPanel;
private JButton addButton;
private JButton queryButton;
private JLabel operationLabel;
private GridBagLayout gridBagLayout;
private GridBagConstraints constraints;
public DepositButtonAction(JPanel secondMenuPanel, JPanel contentPanel, ActionListener otherDepositAddButtonAction,
ActionListener otherDepositRemoveButtonAction, ActionListener otherDepositQueryButtonAction) {
this.secondMenuPanel = secondMenuPanel;
secondMenuPanel.setVisible(false);
this.contentPanel = contentPanel;
addButton = new JButton("Request", new ImageIcon(UserView.class.getResource("/add_icon.png")));
queryButton = new JButton("Query", new ImageIcon(UserView.class.getResource("/info_icon.png")));
operationLabel = new JLabel(new ImageIcon(UserView.class.getResource("/options_icon.png")));
operationLabel.setText("Options ");
gridBagLayout = new GridBagLayout();
constraints = new GridBagConstraints();
applyStyles();
addButton.addActionListener(otherDepositAddButtonAction);
// removeButton.addActionListener(otherDepositRemoveButtonAction);
// queryButton.addActionListener(otherDepositQueryButtonAction);
}
private void applyStyles() {
secondMenuPanel.setLayout(gridBagLayout);
addButton.setHorizontalTextPosition(SwingConstants.RIGHT);
queryButton.setHorizontalTextPosition(SwingConstants.RIGHT);
}
private void initialize() {
constraints.gridx = 0;
constraints.gridy = 0;
constraints.anchor = GridBagConstraints.FIRST_LINE_START;
constraints.fill = GridBagConstraints.BOTH;
constraints.insets = new Insets(4, 4, 4, 4);
secondMenuPanel.add(operationLabel, constraints);
constraints.gridy++;
secondMenuPanel.add(addButton, constraints);
constraints.gridy++;
secondMenuPanel.add(queryButton, constraints);
}
@Override
public void actionPerformed(ActionEvent arg0) {
secondMenuPanel.setVisible(true);
contentPanel.setVisible(false);
secondMenuPanel.removeAll();
contentPanel.removeAll();
contentPanel.revalidate();
contentPanel.repaint();
initialize();
secondMenuPanel.revalidate();
secondMenuPanel.repaint();
}
}
我想得到什么:
提前致谢!
"constraints.weightx"是你的朋友。
来自“double java.awt.GridBagConstraints.weightx”的 Javadoc:
The grid bag layout manager calculates the weight of a column to be the maximum weightx of all the components in a column. If the resulting layout is smaller horizontally than the area it needs to fill, the extra space is distributed to each column in proportion to its weight. A column that has a weight of zero receives no extra space.
这意味着如果您指定值“0”,下一个组件将紧挨着前一个组件分发。
测试你的代码后,我能够通过在你的 initialize()[=36= 上操纵 constraints.weightx 来实现你想要的] 功能。不过有一个技巧,我只能在所有 MenuPanels 都可见的情况下应用它!
我所做的是这样,所有菜单面板都可见:
constraints.weightx = secondMenuPanel.isVisible() ? 0.0 : 0.4;
constraints.weighty = 0.4;
constraints.fill = GridBagConstraints.NONE;
frame.getContentPane().add(menuPanel, constraints);
constraints.gridx++;
constraints.weightx = 0.4;
frame.getContentPane().add(secondMenuPanel, constraints);
constraints.gridx++;
结果:
如果您需要在隐藏组件(仅在点击按钮时显示)的情况下执行此操作,您将需要更新主框架布局的约束,以便它们正确显示。
希望对您有所帮助。
我已经尝试过在 JPanel
(按钮面板)中使用两个垂直 Box
es(布局)按钮,GridLayout
有两列和一行。此按钮面板位于 JFrame
.
示例代码:
import java.awt.*;
import javax.swing.*;
public class TestingLayout {
public static void main(String[] args) {
gui();
}
private static void gui() {
JFrame frame = new JFrame();
frame.setTitle("JButtons Layout");
JPanel pane = new JPanel();
pane.setLayout(new GridLayout(1, 2));
pane.add(getLeftButtons());
pane.add(getRightButtons());
frame.add(pane, BorderLayout.WEST);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setSize(800, 500);
frame.setVisible(true);
}
private static Box getLeftButtons() {
Box box = Box.createVerticalBox();
box.add(new JButton("b1"));
box.add(new JButton("b2"));
box.add(new JButton("b3"));
box.add(new JButton("b4"));
box.add(new JButton("b5"));
return box;
}
private static Box getRightButtons() {
Box box = Box.createVerticalBox();
box.add(new JButton("b11"));
box.add(new JButton("b12"));
box.add(new JButton("b13"));
return box;
}
}
示例的输出:
请记住,您并不局限于使用单个布局管理器。您可以通过使用多个容器来组合布局管理器,让您专注于每个容器的个性化需求,并进一步隔离功能并降低重叠布局要求的复杂性。
您还应该看看 How to Use CardLayout,它将为您提供在不同视图之间切换的方法。
为此,我采取了稍微不同的方式,我从一个可以包含 "sub menus"
的 "menu container" 的概念开始public class MenuPane extends JPanel {
public MenuPane() {
setLayout(new GridBagLayout());
}
public void addSubMenuPane(SubMenuPane pane) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.NORTH;
gbc.weighty = 1;
add(pane, gbc);
revalidate();
repaint();
}
public void removeSubMenu(SubMenuPane pane) {
remove(pane);
revalidate();
repaint();
}
public void popLastMenu() {
if (getComponentCount() == 1) {
return;
}
remove(getComponent(getComponentCount() - 1));
revalidate();
repaint();
}
}
public class SubMenuPane extends JPanel {
public SubMenuPane(String name) {
setLayout(new GridLayout(0, 1));
setBorder(new LineBorder(Color.DARK_GRAY));
add(new JLabel(name, JLabel.CENTER));
}
public SubMenuPane addAction(MenuAction action) {
JButton btn = new JButton(action);
add(btn);
return this;
}
}
我想做的是解耦 API 的某些部分并减少 API 的任何一部分对其余部分的知识量。
基本上,这体现在 SubMenuPane
中,它只是一些按钮的容器,这些按钮通过 MenuAction
class 配置和管理,除此之外,它什么都不做.
public interface MenuAction extends Action {
public MenuController getController();
}
public abstract class AbstractMenuAction extends AbstractAction implements MenuAction {
private MenuController controller;
public AbstractMenuAction(MenuController controller, String name) {
this.controller = controller;
putValue(NAME, name);
}
@Override
public MenuController getController() {
return controller;
}
}
MenuAction
基于 Actions API,它提供了一个自包含和可配置的工作单元
为了更好的衡量,我在菜单窗格和菜单操作之间放入了一个控制器。
public interface MenuController {
public void addSubMenu(SubMenuPane subMenuPane);
public void popLastMenu();
}
public class DefaultMenuController implements MenuController {
private MenuPane menuPane;
public DefaultMenuController(MenuPane menuPane) {
this.menuPane = menuPane;
}
@Override
public void addSubMenu(SubMenuPane subMenuPane) {
menuPane.addSubMenuPane(subMenuPane);
}
@Override
public void popLastMenu() {
menuPane.popLastMenu();
}
}
这里的目的是,我不希望这些操作能够对菜单窗格进行不利修改,相反,我将它们限制为只有两个操作。
好的,但这对您有何帮助?
好吧,让我们建立一个菜单并找出...
MenuPane menuPane = new MenuPane();
DefaultMenuController controller = new DefaultMenuController(menuPane);
SubMenuPane ebanking = new SubMenuPane("E-Banking");
ebanking.addAction(new AbstractMenuAction(controller, "Deposit") {
@Override
public void actionPerformed(ActionEvent e) {
getController().popLastMenu();
SubMenuPane deposit = new SubMenuPane("Options").addAction(new AbstractMenuAction(getController(), "Request") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
}).addAction(new AbstractMenuAction(getController(), "Query") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
});
getController().addSubMenu(deposit);
}
}).addAction(new AbstractMenuAction(controller, "Credit") {
@Override
public void actionPerformed(ActionEvent e) {
getController().popLastMenu();
SubMenuPane deposit = new SubMenuPane("Credit-Options").addAction(new AbstractMenuAction(getController(), "Request") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
}).addAction(new AbstractMenuAction(getController(), "Query") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
});
getController().addSubMenu(deposit);
}
}).addAction(new AbstractMenuAction(controller, "Exchange") {
@Override
public void actionPerformed(ActionEvent e) {
getController().popLastMenu();
SubMenuPane deposit = new SubMenuPane("Exchange-Options").addAction(new AbstractMenuAction(getController(), "Request") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
}).addAction(new AbstractMenuAction(getController(), "Query") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
});
getController().addSubMenu(deposit);
}
}).addAction(new AbstractMenuAction(controller, "Simulation") {
@Override
public void actionPerformed(ActionEvent e) {
getController().popLastMenu();
SubMenuPane deposit = new SubMenuPane("Simulation-Options").addAction(new AbstractMenuAction(getController(), "Request") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
}).addAction(new AbstractMenuAction(getController(), "Query") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
});
getController().addSubMenu(deposit);
}
}).addAction(new AbstractMenuAction(controller, "Information") {
@Override
public void actionPerformed(ActionEvent e) {
getController().popLastMenu();
SubMenuPane deposit = new SubMenuPane("Information-Options").addAction(new AbstractMenuAction(getController(), "Request") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
}).addAction(new AbstractMenuAction(getController(), "Query") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
});
getController().addSubMenu(deposit);
}
});
controller.addSubMenu(ebanking);
好的,"What the ... code" 就这么多了。为了简洁起见,我使用了很多匿名 classes,实际上,我可能为每个菜单操作设置了 subclass,但这提供了基本的基础工作。
关键是,每个子菜单都可以简单轻松地制作,独立于 MenuPane
,因为它们通过控制器绑定在一起。
您可以进一步扩展控制器以提供额外的功能来触发创建子视图的操作或提供一种直接通过控制器打开您提供的子视图的方法。
我想展示这个想法的原因是,当你添加新的子菜单时,它会对剩余的内容区域产生影响,如果你试图在单个 layout/container 中维护它,你将不断努力将它们保持在一起并很好地协同工作。
相反,此解决方案包含自己容器的子菜单,该容器仅管理菜单,然后将其添加到另一个容器,可能使用不同的布局管理器,然后单独管理外部关注点。
只是一个想法
可运行示例...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
MenuPane menuPane = new MenuPane();
DefaultMenuController controller = new DefaultMenuController(menuPane);
SubMenuPane ebanking = new SubMenuPane("E-Banking");
ebanking.addAction(new AbstractMenuAction(controller, "Deposit") {
@Override
public void actionPerformed(ActionEvent e) {
getController().popLastMenu();
SubMenuPane deposit = new SubMenuPane("Options").addAction(new AbstractMenuAction(getController(), "Request") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
}).addAction(new AbstractMenuAction(getController(), "Query") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
});
getController().addSubMenu(deposit);
}
}).addAction(new AbstractMenuAction(controller, "Credit") {
@Override
public void actionPerformed(ActionEvent e) {
getController().popLastMenu();
SubMenuPane deposit = new SubMenuPane("Credit-Options").addAction(new AbstractMenuAction(getController(), "Request") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
}).addAction(new AbstractMenuAction(getController(), "Query") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
});
getController().addSubMenu(deposit);
}
}).addAction(new AbstractMenuAction(controller, "Exchange") {
@Override
public void actionPerformed(ActionEvent e) {
getController().popLastMenu();
SubMenuPane deposit = new SubMenuPane("Exchange-Options").addAction(new AbstractMenuAction(getController(), "Request") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
}).addAction(new AbstractMenuAction(getController(), "Query") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
});
getController().addSubMenu(deposit);
}
}).addAction(new AbstractMenuAction(controller, "Simulation") {
@Override
public void actionPerformed(ActionEvent e) {
getController().popLastMenu();
SubMenuPane deposit = new SubMenuPane("Simulation-Options").addAction(new AbstractMenuAction(getController(), "Request") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
}).addAction(new AbstractMenuAction(getController(), "Query") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
});
getController().addSubMenu(deposit);
}
}).addAction(new AbstractMenuAction(controller, "Information") {
@Override
public void actionPerformed(ActionEvent e) {
getController().popLastMenu();
SubMenuPane deposit = new SubMenuPane("Information-Options").addAction(new AbstractMenuAction(getController(), "Request") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
}).addAction(new AbstractMenuAction(getController(), "Query") {
@Override
public void actionPerformed(ActionEvent e) {
// Use Card layout to show next avaliable options
}
});
getController().addSubMenu(deposit);
}
});
controller.addSubMenu(ebanking);
JPanel someContent = new JPanel() {
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
};
someContent.setBackground(Color.RED);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(menuPane, BorderLayout.WEST);
frame.add(someContent);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface MenuController {
public void addSubMenu(SubMenuPane subMenuPane);
public void popLastMenu();
}
public class DefaultMenuController implements MenuController {
private MenuPane menuPane;
public DefaultMenuController(MenuPane menuPane) {
this.menuPane = menuPane;
}
@Override
public void addSubMenu(SubMenuPane subMenuPane) {
menuPane.addSubMenuPane(subMenuPane);
}
@Override
public void popLastMenu() {
menuPane.popLastMenu();
}
}
public interface MenuAction extends Action {
public MenuController getController();
}
public abstract class AbstractMenuAction extends AbstractAction implements MenuAction {
private MenuController controller;
public AbstractMenuAction(MenuController controller, String name) {
this.controller = controller;
putValue(NAME, name);
}
@Override
public MenuController getController() {
return controller;
}
}
public class MenuPane extends JPanel {
public MenuPane() {
setLayout(new GridBagLayout());
}
public void addSubMenuPane(SubMenuPane pane) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.NORTH;
gbc.weighty = 1;
add(pane, gbc);
revalidate();
repaint();
}
public void removeSubMenu(SubMenuPane pane) {
remove(pane);
revalidate();
repaint();
}
public void popLastMenu() {
if (getComponentCount() == 1) {
return;
}
remove(getComponent(getComponentCount() - 1));
revalidate();
repaint();
}
}
public class SubMenuPane extends JPanel {
public SubMenuPane(String name) {
setLayout(new GridLayout(0, 1));
setBorder(new LineBorder(Color.DARK_GRAY));
add(new JLabel(name, JLabel.CENTER));
}
public SubMenuPane addAction(MenuAction action) {
JButton btn = new JButton(action);
add(btn);
return this;
}
public void pop() {
Container parent = getParent();
if (parent != null) {
parent.remove(this);
parent.revalidate();
parent.repaint();
}
}
}
}
nb:这是一个不完整的解决方案,旨在在处理此类问题时促进 "different way of thinking"