我有一个应用程序应该在8x6网格上的不同位置显示不同“大小”(更好的不同跨度)的切片。这些位置会更改,并且会在运行时添加新的切片。我尝试了不同的布局来实现这一目标,但没有成功。 BoxLayout:无法在多个单元格上跨越组件 GridLayout:无法跨多个单元格跨越组件 GridBagLayout:我使用了这个布局,直到我意识到当我尝试合并两个单元格时,布局只是扩展了组件所在的单元格,但没有合并单元格。文档
中也对此进行了描述
GridBagLayout does not allow components to span multiple rows
。
示例:
当我向我的GridBagLayout添加虚拟面板时的外观:
添加瓷砖时的实际效果如下:
它应该如何:
是否有可以完成此任务的布局,或者是否有其他可能使这个工作正常工作(JTable?!?)?如果你可以为我提供一些新的想法(如果可能的话,有些教程)会很棒。我使用的Netbeans 7.3没有任何GUI Builder扩展。
代码编辑:
布局(由Netbeans创建)
java.awt.GridBagLayout contentPaneLayout = new java.awt.GridBagLayout();
contentPaneLayout.columnWidths = new int[] {240};
contentPaneLayout.rowHeights = new int[] {160};
contentPane.setLayout(contentPaneLayout);
添加面板(每个面板都需要)
GridBagConstraints c = new GridBagConstraints();
c.gridx = positionx;
c.gridy = positiony;
c.insets = new Insets(2, 2, 2, 2);
c.weightx = width == 0 ? 2 : width;
c.weighty = height == 0 ? 2 : height;
c.anchor = GridBagConstraints.FIRST_LINE_START;
contentPane.add(myPanel, c);
答案 0 :(得分:1)
请勿将 weightX 与 gridWidth 混淆。它应该是这样的:
GridBagConstraints c = new GridBagConstraints();
c.gridx = positionx;
c.gridy = positiony;
c.insets = new Insets(2, 2, 2, 2);
c.gridWidth= width == 0 ? 2 : width; //should be
c.gridHeight = height == 0 ? 2 : height; //should be
c.anchor = GridBagConstraints.FIRST_LINE_START;
contentPane.add(myPanel, c);
答案 1 :(得分:1)
对不起,我还是不明白。这是问题的延续,而不是尝试回答。
我从未弄清楚GridBagLayout;对我来说,这是一个未解释的组件的纯粹例子。我从未见过对其许多约束等的解释,只是例子。但是我想做的事情从来都不像是例子,我讨厌通过反复试验,希望能够实现我想要的组合。有什么方法可以编程。
编辑:好的,现在这是一个答案,至少对于延续问题。通过典型的反复试验,我相信我已经发现了缺失的原则,并在此提供它,以便当有人查看官方文档时它会丢失。
Oracle“如何使用GridBagLayout”包含以下内容:“... GridBagLayout将组件放置在网格中的矩形(单元格)中,然后使用组件的首选大小来确定单元格的大小”
很容易错过这个含义:gridbag通过使用该列/行中所有组件的首选大小来确定列的宽度和行的高度。在实现时,将GBL视为通过列中出现的所有组件,确定最大的首选大小宽度,并将其作为第一列的宽度等。
下面的代码尝试将GridBagLayout面板视为一个网格,其中列和行由面板中组件的“x”,“y”,“width”和“height”属性确定,GBL显然忽略这一点。
这就是为什么我的程序不符合我的预期;我可以摆弄设置组件的首选大小,引起那些声称程序不应该这样做的人的愤怒。如果我确实要解决这个问题,我实际上不会这样做。
我不能对OP有任何明确的建议;在这个练习之后,我仍然更喜欢使用GroupLayout(我自己添加一些)来布局组件。要选择一种解决原始问题的好方法,我们需要更多地了解如何选择组件的大小以及OP需要的灵活性。
这是我有不起作用:
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.border.Border;
/**
* trying to do this:
* <pre>
* +----------------+----------------+--------+
* | | | |
* | tile 1 | tile 3 | |
* | | | |
* +----------------+----------------+ tile 5 |
* | | | |
* | | | |
* | | | |
* | tile 2 +----------------+--------+-------+
* | | | |
* | | tile 4 | tile 6 |
* | | | |
* |----------------+----------------+----------------+
*
* </pre>
*/
public class Tiles extends JFrame
{
private static final long serialVersionUID = 1L;
private GridBagConstraints constraints = new GridBagConstraints();
private Border lineBorder = BorderFactory.createLineBorder(Color.black);
JPanel gblPanel = new JPanel(new GridBagLayout());
public static void main(String[] args)
{
Tiles tiles = new Tiles();
tiles.go();
}
public void go()
{
createUI();
setVisible(true);
}
private void createUI()
{
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
addLabelToGblPanel("1", 2, 1, 0, 0); // label, width, height, x position, y position
addLabelToGblPanel("3", 2, 1, 2, 0);
addLabelToGblPanel("5", 1, 2, 4, 0);
addLabelToGblPanel("2", 2, 2, 0, 1);
addLabelToGblPanel("4", 2, 1, 2, 2);
addLabelToGblPanel("6", 2, 1, 4, 2);
getContentPane().add(gblPanel);
pack();
}
private void addLabelToGblPanel(String num, int width, int height, int x, int y)
{
String numString = "Tile " + num;
JLabel tile = new JLabel(numString, SwingConstants.CENTER);
tile.setBorder(lineBorder);
constraints.ipadx = 25;
constraints.ipady = 25;
constraints.gridwidth = width;
constraints.gridheight = height;
constraints.gridx = x;
constraints.gridy = y;
// constraints.fill = GridBagConstraints.BOTH;
// constraints.weightx = 0.5;
// constraints.weighty = 0.5;
gblPanel.add(tile, constraints);
}
}
显然我有些不对劲;我得到的东西显示为3x2网格。我给他们的尺寸和位置没有任何区别。是否有人可以解释约束如何使其成功?
这是驱使我学习如何手工制作GroupLayout的原因......
答案 2 :(得分:1)
在Oliver的答案的帮助下,我设法让布局工作。 Oliver是对的,在我的原始代码中,我混合了weightX和gridWidth(由于各种尝试)。但是,当我只用gridWidth / Height交换weigthX / Y时,则不会显示任何图块。所以我还需要定义1的权重。
所以添加面板的代码如下所示:
GridBagConstraints c = new GridBagConstraints();
c.gridx = positionx;
c.gridy = positiony;
c.insets = new Insets(2, 2, 2, 2);
c.gridwidth = width == 0 ? 2 : width;
c.gridheight = height == 0 ? 2 : height;
c.weightx = 1;
c.weighty = 1;
c.anchor = GridBagConstraints.FIRST_LINE_START;
contentPane.add(myPanel, c);
但GridBagLayout仍然合并了我的行和列,我必须添加一些虚拟面板,如问题GridBagLayout in Java Column Issue中所述(在添加我的图块之前)
for (int i = 0; i < columnCount; i++) {
for (int j = 0; j < rowCount; j++) {
GridBagConstraints c = new GridBagConstraints();
c.gridx = i;
c.gridy = j;
c.insets = new Insets(2, 2, 2, 2);
c.weightx = 1;
c.weighty = 1;
c.gridheight = 1;
c.gridwidth = 1;
c.anchor = GridBagConstraints.FIRST_LINE_START;
NewJPanel p = new NewJPanel(); //A JPanel I created with the same background, width and height of a cell. May work with a normal JPanel as well.
//p.setVisible(false);
p.setOpaque(false);
contentPanel.add(p, c);
}
}
我的图块扩展了JPanel并且是这样创建的(不知道是否需要):
Size size = new Dimension(cellWidth * gridbagconstraint.gridwidth, cellHeight * gridbagconstraint.gridheight);
setSize(size);
setMaximumSize(size);
setMinimumSize(size);
setPreferredSize(size);
谢谢你们的支持!
答案 3 :(得分:0)
事实证明,空布局效果最佳。
这是我创建的原始Widget组织器。
在我移动了几个小部件后,这是Widget组织器。
我把它作为一个源模块放在一起,这样就很容易复制和粘贴。在实际项目中,这些类应该位于不同的源模块中。
这是代码。
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
public class WidgetOrganizer implements Runnable {
@Override
public void run() {
createFrame();
}
private void createFrame() {
JFrame frame = new JFrame("Widget Organizer");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DragAndDrop dragAndDrop = new DragAndDrop();
WidgetFactory widgetFactory = new WidgetFactory();
DrawingPanel drawingPanel = new DrawingPanel(widgetFactory.getWidgets());
drawingPanel.setDragAndDrop(dragAndDrop);
drawingPanel.drawWidgets();
dragAndDrop.setDragAndDrop(drawingPanel);
frame.add(drawingPanel.getPanel());
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new WidgetOrganizer());
}
public class DrawingPanel {
private JPanel panel;
private List<Widget> widgets;
public DrawingPanel(List<Widget> widgets) {
super();
this.widgets = widgets;
createDrawingPanel();
}
private void createDrawingPanel() {
panel = new JPanel();
panel.setLayout(null);
panel.setPreferredSize(new Dimension(600, 500));
}
public void drawWidgets() {
panel.removeAll();
for (Widget widget : widgets) {
JPanel widgetPanel = widget.getPanel();
widgetPanel.setBounds(widget.getWidgetBounds());
panel.add(widgetPanel);
}
panel.validate();
panel.repaint();
}
public JPanel getPanel() {
return panel;
}
public List<Widget> getWidgets() {
return widgets;
}
public void setDragAndDrop(DragAndDrop dragAndDrop) {
panel.addMouseListener(dragAndDrop);
panel.addMouseMotionListener(dragAndDrop);
}
}
public class Widget {
private Border normalBorder;
private Border movingBorder;
/** x, y, width, and height in pixels */
private Rectangle widgetBounds;
private JLabel originLabel;
private JPanel panel;
private String widgetName;
public Widget(String widgetName) {
this.widgetName = widgetName;
this.normalBorder = BorderFactory.createLineBorder(Color.BLUE, 3);
this.movingBorder = BorderFactory.createLineBorder(Color.RED, 3);
}
public void setWidgetBounds(Rectangle widgetBounds) {
this.widgetBounds = widgetBounds;
setOriginLabel();
}
public void createWidget() {
panel = new JPanel();
panel.setBorder(normalBorder);
panel.setLayout(new GridBagLayout());
panel.setPreferredSize(new Dimension(widgetBounds.width,
widgetBounds.height));
GridBagConstraints gbc = new GridBagConstraints();
JLabel nameLabel = new JLabel(widgetName + " widget");
panel.add(nameLabel, gbc);
originLabel = new JLabel();
setOriginLabel();
gbc.gridy = 1;
panel.add(originLabel, gbc);
String s = widgetBounds.width + "x" + widgetBounds.height
+ " pixels";
JLabel sizeLabel = new JLabel(s);
gbc.gridy = 2;
panel.add(sizeLabel, gbc);
}
private void setOriginLabel() {
if (originLabel != null) {
String s = widgetBounds.x + "," + widgetBounds.y;
originLabel.setText(s);
}
}
public void setNormalBorder() {
panel.setBorder(normalBorder);
}
public void setMovingBorder() {
panel.setBorder(movingBorder);
}
public boolean isClickedWidget(Point clickedPoint) {
int x = clickedPoint.x - widgetBounds.x;
int y = clickedPoint.y - widgetBounds.y;
boolean insideWidth = (x >= 0) && (x < widgetBounds.width);
boolean insideHeight = (y >= 0) && (y < widgetBounds.height);
return insideWidth && insideHeight;
}
public JPanel getPanel() {
return panel;
}
public Rectangle getWidgetBounds() {
return widgetBounds;
}
}
public class WidgetFactory {
private List<Widget> widgets;
public WidgetFactory() {
widgets = new ArrayList<Widget>();
createWidgets();
}
private void createWidgets() {
Widget widget = new Widget("Square");
widget.setWidgetBounds(new Rectangle(0, 0, 150, 150));
widget.createWidget();
widgets.add(widget);
widget = new Widget("Tall");
widget.setWidgetBounds(new Rectangle(150, 0, 150, 250));
widget.createWidget();
widgets.add(widget);
widget = new Widget("Wide");
widget.setWidgetBounds(new Rectangle(0, 250, 250, 150));
widget.createWidget();
widgets.add(widget);
}
public List<Widget> getWidgets() {
return widgets;
}
}
public class DragAndDrop extends MouseAdapter {
/** drag and drop resolution in pixels */
private int resolution = 10;
private DrawingPanel drawingPanel;
private List<Widget> widgets;
private Point mouseClicked;
private Rectangle movingWidgetBounds;
private Widget movingWidget;
public void setDragAndDrop(DrawingPanel drawingPanel) {
this.drawingPanel = drawingPanel;
this.widgets = drawingPanel.getWidgets();
}
@Override
public void mousePressed(MouseEvent event) {
mouseClicked = event.getPoint();
for (Widget widget : widgets) {
if (widget.isClickedWidget(mouseClicked)) {
movingWidget = widget;
movingWidgetBounds = copy(widget.getWidgetBounds());
return;
}
}
movingWidget = null;
}
@Override
public void mouseReleased(MouseEvent event) {
if (movingWidget != null) {
movingWidget.setNormalBorder();
Rectangle r = calculateWidgetOrigin(event);
movingWidget.setWidgetBounds(r);
drawingPanel.drawWidgets();
movingWidget = null;
}
}
@Override
public void mouseDragged(MouseEvent event) {
if (movingWidget != null) {
movingWidget.setMovingBorder();
Rectangle r = calculateWidgetOrigin(event);
movingWidget.setWidgetBounds(r);
drawingPanel.drawWidgets();
}
}
private Rectangle calculateWidgetOrigin(MouseEvent event) {
Rectangle r = copy(movingWidgetBounds);
Point endPoint = event.getPoint();
int diffX = endPoint.x - mouseClicked.x;
int diffY = endPoint.y - mouseClicked.y;
diffX = (diffX + resolution / 2) / resolution * resolution;
diffY = (diffY + resolution / 2) / resolution * resolution;
r.x += diffX;
r.y += diffY;
return r;
}
private Rectangle copy(Rectangle r) {
Rectangle s = new Rectangle();
s.x = r.x;
s.y = r.y;
s.width = r.width;
s.height = r.height;
return s;
}
}
}