gpt4 book ai didi

java - swing自定义布局-组件包裹和高度计算

转载 作者:行者123 更新时间:2023-12-01 05:01:33 24 4
gpt4 key购买 nike

我正在尝试创建自定义布局,它允许我以百分比指定组件的宽度,并根据该百分比宽度来布局组件。以下是我最终实现的实现。

我遇到的问题是,最里面的面板之一的计算宽度不足以将其所有组件容纳在一行中,下面的实现将它们包装到下一行,但是父级的高度 [all层次结构中的容器]固定为一些像素[在我的例子中我使用了40px],并且它不允许显示包装的组件。

您能建议一种解决方法吗...

import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager2;
import java.awt.Rectangle;
import java.util.LinkedHashMap;
import java.util.Map.Entry;

import javax.swing.BoxLayout;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;


/**
* @author Rakesh.A
*
*/
public class Example extends JPanel {

public Example() {
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
for (int i = 0; i < 1; i++) {
JPanel row = new JPanel();
row.setLayout(new PercentageWidthLayout(5, 5));

JPanel column1 = new JPanel();
column1.setOpaque(true);
column1.setBackground(Color.white);

JPanel column2 = createColumn2();

row.add(column1, new MyConstraints(15, false)); // uses 15% of the available size
row.add(column2, new MyConstraints(50, false, true, true)); // uses 50% of the available size and wraps its contents
row.add(new JPanel(), new MyConstraints(25, false)); // uses 25% of the available size
add(row);
}
}

private JPanel createColumn2() {
JPanel column = new JPanel();
column.setOpaque(true);
column.setBackground(Color.green);

column.setLayout(new PercentageWidthLayout(3, 3, 35));
// total percentage is 100% for all the below components
column.add(new MyComponent(30, 28), new MyConstraints(20, true, false, true));
column.add(new MyComponent(30, 28), new MyConstraints(10, true, false, true));
column.add(new MyComponent(30, 28), new MyConstraints(20, true, false, true));
column.add(new MyComponent(30, 28), new MyConstraints(20, true, false, true));
column.add(new MyComponent(30, 28), new MyConstraints(10, true, false, true));
column.add(new MyComponent(30, 28), new MyConstraints(10, true, false, true));
column.add(new MyComponent(30, 28), new MyConstraints(10, true, false, true));
return column;
}

public static void main(final String[] args) {
JDialog dialog = new JDialog();
dialog.setSize(500, 150);
Example content = new Example();
JScrollPane scrl = new JScrollPane(content, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
dialog.getContentPane().add(scrl);
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setVisible(true);
}

public static class MyComponent extends JPanel {
private Dimension minSize;
public MyComponent(final int minWidth, final int minHeight) {
minSize = new Dimension(minWidth, minHeight);

setOpaque(true);
setBackground(Color.yellow);

add(new JLabel("Block"));
}

@Override
public Dimension getPreferredSize() {
return minSize;
}

@Override
public Dimension getMaximumSize() {
return minSize;
}
@Override
public Dimension getMinimumSize() {
return minSize;
}
}

public static class PercentageWidthLayout implements LayoutManager2 {
private LinkedHashMap<Component, MyConstraints> components;

private final int leftMargin;
private final int topMargin;
private final int rowHeight;

// default size of the block
public static final Dimension minimumSize = new Dimension(10, 40);
public static final Dimension preferredSize = new Dimension(100, 40);

// default left margin between components
public static final int defaultLeftMargin = 5;
// default bottom margin between components
public static final int defaultTopMargin = 5;
// default row height
public static final int defaultRowHeight = 0;

public PercentageWidthLayout() {
this(defaultLeftMargin, defaultTopMargin);
}

public PercentageWidthLayout(final int leftMargin, final int topMargin) {
this(leftMargin, topMargin, defaultRowHeight);
}

public PercentageWidthLayout(final int leftMargin, final int topMargin, final int rowHeight) {
this.leftMargin = leftMargin;
this.topMargin = topMargin;
this.rowHeight = rowHeight;

components = new LinkedHashMap<Component, MyConstraints>();
}

@Override
public Dimension preferredLayoutSize(final Container parent) {
int maxX = 0;
int maxY = 0;
for (Entry<Component, MyConstraints> compEntry : components.entrySet()) {
Rectangle bounds = compEntry.getKey().getBounds();
maxX = Math.max(maxX, (int) bounds.getMaxX());
maxY = Math.max(maxY, (int) bounds.getMaxY());
}
if (maxX == 0 || maxY == 0) {
return preferredSize;
}
return new Dimension(maxX, maxY);
}

@Override
public Dimension minimumLayoutSize(final Container parent) {
return minimumSize;
}

@Override
public Dimension maximumLayoutSize(final Container target) {
return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
}

@Override
public void layoutContainer(final Container parent) {
synchronized (parent.getTreeLock()) {
// validate total percentage
validatePercentages();
// calculate available width & height for the components
Insets insets = parent.getInsets();
// available width after removing border space
int maxClientWidth = parent.getWidth() - insets.left - insets.right;
// calculated available width for the components
int clientWidth = maxClientWidth - (parent.getComponents().length * leftMargin);
// calculated available height for the components
int clientHeight = ((rowHeight > 0) ? rowHeight : preferredSize.height) - insets.top - insets.bottom - topMargin * 2;

// layout the components
int x = insets.left + leftMargin;
int y = insets.top + topMargin;

if (clientWidth > 0 && clientHeight > 0) {
for (Component component : parent.getComponents()) {
// get the constraints to be applied
MyConstraints constraints = components.get(component);
// calculate component width according to the given percentage
int componentWidth = clientWidth * constraints.percentage / 100;

// calculate the preferred size of the component
int prefW = component.getPreferredSize().width;
if (constraints.usePreferredSize && componentWidth < prefW) {
// configured to use preferred size if calculated size is less than the
// preferred size
componentWidth = prefW;
}

// calculate the minimum size of the component
int minW = component.getMinimumSize().width;
if (constraints.useMinWidth && componentWidth < minW) {
// configured to use minimum width if calculated size is less than the
// minimum size
componentWidth = minW;
}
// check and wrap component to next row if needed
if (constraints.wrapComponents && x + componentWidth > parent.getWidth()) {
x = insets.left + leftMargin;
y += clientHeight + insets.top;
// update height of the parent component if it doesn fit
// if (parent.getHeight() < y + clientHeight) {
// parent.setSize(parent.getWidth(), parent.getHeight() + rowHeight);
// }
}
component.setBounds(x, y, componentWidth, clientHeight);
// update x coordinate
x += componentWidth + leftMargin;
}
}
}
}

@Override
public void addLayoutComponent(final String name, final Component comp) {
}

@Override
public void removeLayoutComponent(final Component comp) {
components.remove(comp); // remove component from map
}

@Override
public void addLayoutComponent(final Component comp, final Object constraints) {
if (constraints == null || !(constraints instanceof MyConstraints)) {
throw new IllegalArgumentException("Invalid constraints object! - " + constraints);
}
MyConstraints myConstraints = (MyConstraints) constraints;
if (myConstraints.percentage > 100) {
throw new IllegalArgumentException("Invalid percentage value [" + myConstraints.percentage + "]!");
}
components.put(comp, myConstraints);
}

@Override
public float getLayoutAlignmentX(final Container target) {
return 0;
}

@Override
public float getLayoutAlignmentY(final Container target) {
return 0;
}

@Override
public void invalidateLayout(final Container target) {
}

public int getLeftMargin() {
return leftMargin;
}

public int getTopMargin() {
return topMargin;
}

public int getRowHeight() {
return rowHeight;
}

public static Integer calculatePercentage(final float value, final int total) {
return new Integer((int) (value / total * 100));
}

private void validatePercentages() {
int total = 0;
for (Entry<Component, MyConstraints> compEntry : components.entrySet()) {
total += compEntry.getValue().percentage;
}
if (total > 100) {
throw new IllegalArgumentException("Total percentage [" + total + "] of the components in the layout is more than 100!");
}
}

}

/**
* @author Rakesh.A
*
*/
public static class MyConstraints {
public final int percentage;
public final boolean usePreferredSize, useMinWidth, wrapComponents;

public MyConstraints(final int percentage, final boolean usePreferredSize) {
this(percentage, usePreferredSize, false);
}

public MyConstraints(final int percentage, final boolean usePreferredSize, final boolean useMinWidth) {
this(percentage, usePreferredSize, useMinWidth, false);
}

public MyConstraints(final int percentage, final boolean usePreferredSize, final boolean useMinWidth, final boolean wrapComponents) {
this.percentage = percentage;
this.usePreferredSize = usePreferredSize;
this.useMinWidth = useMinWidth;
this.wrapComponents = wrapComponents;
}
}
}

除此之外,根面板已添加到 JScrollPane 中,并且还需要更新。

最佳答案

感谢大家的投入。我选择了解决此问题的方法,而不是包装组件,而是添加了水平滚动条:)

关于java - swing自定义布局-组件包裹和高度计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13331393/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com