我正在尝试构建一个在左侧锚定两个垂直列的应用程序, 还有一个大盒子在右边我可以将第一个菜单贴在右边, 但由于某种原因,第二个菜单不会出现在第一个菜单的旁边。我已经读到一些有关将多余的空间推向最后一列和最后一行(右侧)的内容。我应该如何处理?
P.S。我正在使用网格袋布局。
这就是我所拥有的:
主要的UserView类: 包gui;
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);
}
}
另一个代表第一个按钮行为的类:
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();
}
}
谢谢!
答案 0 :(得分:3)
我用两个Box
(两列一行)的JPanel
(按钮面板)中的按钮使用了两个垂直的GridLayout
es(布局)进行了尝试。此按钮面板位于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;
}
}
示例的输出:
答案 1 :(得分:2)
请记住,您不仅限于使用单个布局管理器。您可以通过使用多个容器来组合布局管理器,从而使您可以专注于每个容器的个性化需求,并进一步隔离功能并降低重叠的布局要求的复杂性。
您还应该查看How to Use CardLayout,这将为您提供在不同视图之间切换的方式。
为此,我采取了一种略有不同的方式,从“菜单容器”的概念开始,其中可以包含“子菜单”
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
类进行配置和管理的,除此之外,它什么也不做。
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);
好的,所以有很多“什么……代码”。为了简洁起见,我使用了许多匿名类,实际上,我可能为每个菜单操作都设置了子类,但这提供了基础工作。
关键是,每个子菜单都可以通过控制器绑定在一起而独立于MenuPane
进行简单,轻松地制作。
您可以进一步扩展控制器以提供其他功能,以触发创建子视图的操作,或者直接通过控制器提供一种方法来打开您提供的子视图。
我之所以要证明这一点是因为,当您添加新的子菜单时,它将对剩余内容区域产生影响,如果您尝试将其维护在单个布局/容器中,则您将不断挣扎尝试将所有内容保持在一起并一起良好地工作。
相反,此解决方案包含其自己的容器的子菜单,该子菜单仅管理菜单,然后将其添加到另一个容器,可能使用其他布局管理器,然后分别管理外部问题。
只是一个想法
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:这是一个不完整的解决方案,旨在解决此类问题时会提倡“不同的思维方式”
答案 2 :(得分:1)
“ constraints.weightx”是你的朋友。
从Javadoc中获取“ double java.awt.GridBagConstraints.weightx ”:
网格袋布局管理器将一列的重量计算为一列中所有组件的最大权重x。如果生成的布局在水平方向上小于需要填充的区域,则多余的空间将按其重量成比例地分配给每列。权重为零的列不会收到多余的空间。
这意味着,如果您指定值“ 0”,则下一个组件将被分配在上一个组件的旁边。
在测试完代码之后,我可以通过操作 initialize() 函数上的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++;
如果需要在隐藏组件的情况下执行此操作(仅在按下按钮时显示),则需要更新主框架布局的约束,以使其正确显示。
希望对您有帮助。