使用GridBagLayout表示动态仪表板的布局

时间:2013-05-24 09:07:38

标签: java swing gridbaglayout

我有一个应用程序应该在8x6网格上的不同位置显示不同“大小”(更好的不同跨度)的切片。这些位置会更改,并且会在运行时添加新的切片。我尝试了不同的布局来实现这一目标,但没有成功。 BoxLayout:无法在多个单元格上跨越组件 GridLayout:无法跨多个单元格跨越组件 GridBagLayout:我使用了这个布局,直到我意识到当我尝试合并两个单元格时,布局只是扩展了组件所在的单元格,但没有合并单元格。文档

中也对此进行了描述
  

GridBagLayout does not allow components to span multiple rows

示例:

当我向我的GridBagLayout添加虚拟面板时的外观:

Grid with faint white lines

添加瓷砖时的实际效果如下:

Tiles grid

它应该如何:

Actual grid

是否有可以完成此任务的布局,或者是否有其他可能使这个工作正常工作(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);

4 个答案:

答案 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组织器。

Original Widget Organizer

在我移动了几个小部件后,这是Widget组织器。

Moved Widgit Organizer

我把它作为一个源模块放在一起,这样就很容易复制和粘贴。在实际项目中,这些类应该位于不同的源模块中。

这是代码。

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

    }

}