我在GridLayout
内使用Section
一列。有三个"行"在网格中,具有白色背景。我希望Section
抓住水平空间,但只需要根据需要增加垂直空间:
每行使用自定义行布局,并有两个子项。此外,该行布局有两种状态:
a)在一条线上显示(如果总宽度足够大)
b)在额外的一行显示第二个孩子(红色)(如果两个孩子的窗口总宽度太小)
对于这两种状态,我希望截面内容(蓝色)的总高度等于行高(忽略间距)的总和。
然而,该部分的总高度是状态a)是我期望的情况b)的高度。该部分似乎保留了垂直空间,因此在调整宽度时不需要改变其高度。
如果GridLayout
未放置在某个部分内,则高度正常。如果我使用标准RowLayout
而不是我的自定义行布局,则总高度也很好。多余的垂直空间随着行数的增加而增加。
=> 我猜我的自定义行布局有问题吗?。
=> 或者我是否需要为Section
设置一个不保留空间的选项?
我的自定义布局"以某种方式沟通"父布局的第二种高度/提示?由于白色区域的高度很好而且所有行都位于顶部,因此 computeSize 方法似乎没问题。
我不希望Section
保留空间。我希望它能够根据需要懒洋洋地调整其高度。
相关问题:
SWT RowLayout with last element grabbing excess horizontal space?
我的自定义布局:
package org.treez.core.adaptable.composite;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Layout;
/**
* A custom row layout for exactly two children. If there is not enough space for the second child it is wrapped to a
* second line. The second child grabs excess horizontal space (which would not be possible with a normal RowLayout).
*/
public final class ExtendingRowLayout extends Layout {
//#region ATTRIBUTES
private int minWidthForFirstChild;
private int minWidthForSecondChild;
private int spacing = 5;
//#end region
//#region CONSTRUCTORS
public ExtendingRowLayout() {
this(80, 200);
}
public ExtendingRowLayout(int minWidthForFirstChild, int minWidthForSecondChild) {
this.minWidthForFirstChild = minWidthForFirstChild;
this.minWidthForSecondChild = minWidthForSecondChild;
}
//#end region
//#region METHODS
@Override
protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
Point extent = layoutHorizontal(composite, false, wHint, flushCache);
return extent;
}
@Override
protected void layout(Composite composite, boolean flushCache) {
Rectangle clientArea = composite.getClientArea();
layoutHorizontal(composite, true, clientArea.width, flushCache);
}
@Override
protected boolean flushCache(Control control) {
return true;
}
@Override
public String toString() {
return getClass().getSimpleName();
}
private Point layoutHorizontal(
Composite composite,
boolean doPositionChildren,
int clientWidth,
boolean flushCache) {
Control[] children = composite.getChildren();
if (children.length != 2) {
String message = "There must be exactly two children and not " + children.length + ".";
throw new IllegalStateException(message);
}
int clientX = 0;
int clientY = 0;
if (doPositionChildren) {
Rectangle rect = composite.getClientArea();
clientX = rect.x;
clientY = rect.y;
}
Control firstChild = children[0];
Control secondChild = children[1];
Point firstSize = firstChild.computeSize(SWT.DEFAULT, SWT.DEFAULT, flushCache);
Point secondSize = secondChild.computeSize(SWT.DEFAULT, SWT.DEFAULT, flushCache);
int firstChildWidth = Math.max(firstSize.x, minWidthForFirstChild);
int correctedSpacing = spacing;
if (firstChildWidth == 0) {
correctedSpacing = 0;
}
int minForSecondChildWidth = Math.max(secondSize.x, minWidthForSecondChild);
int minForTotalWidthOfSingleLine = firstChildWidth + correctedSpacing + minForSecondChildWidth;
int maxHeight = Math.max(firstSize.y, secondSize.y);
int firstY = maxHeight / 2 - firstSize.y / 2;
if (doPositionChildren) {
firstChild.setBounds(clientX, clientY + firstY, firstChildWidth, firstSize.y);
}
boolean showOnSingleLine = minForTotalWidthOfSingleLine + spacing <= clientWidth;
if (showOnSingleLine) {
int x = clientX + firstChildWidth + correctedSpacing;
int y = clientY + maxHeight / 2 - secondSize.y / 2;
int width = clientWidth - firstChildWidth - correctedSpacing;
int height = secondSize.y;
if (doPositionChildren) {
secondChild.setBounds(x, y, width, height);
}
int totalWidth = Math.max(minForTotalWidthOfSingleLine, clientWidth);
return new Point(totalWidth, maxHeight);
} else {
int x = clientX;
int y = (int) (clientY + firstSize.y + 1.5 * spacing);
int width = Math.max(clientWidth, minWidthForSecondChild);
int height = secondSize.y;
if (doPositionChildren) {
secondChild.setBounds(x, y, width, height);
}
int totalHeight = (int) (firstSize.y + 1.5 * spacing + secondSize.y);
return new Point(width, totalHeight);
}
}
//#end region
}
使用示例:
package org.treez.core.adaptable.composite;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.forms.widgets.ExpandableComposite;
import org.eclipse.ui.forms.widgets.Section;
public class ExtendingRowLayoutDemo {
public static void main(String[] args) {
Shell shell = createShell();
shell.setSize(500, 300);
Section section = createSection(shell);
Composite parentComposite = createParentComposite(section);
createRow(parentComposite, "first");
createRow(parentComposite, "second");
createRow(parentComposite, "third");
showUntilClosed(shell);
}
private static Shell createShell() {
Display display = new Display();
Shell shell = new Shell(display);
GridLayout shellGridLayout = new GridLayout(1, false);
shell.setLayout(shellGridLayout);
return shell;
}
private static Section createSection(Shell shell) {
Section section = new Section(
shell,
ExpandableComposite.TWISTIE | ExpandableComposite.EXPANDED | ExpandableComposite.TITLE_BAR);
GridData gridData = new GridData(SWT.FILL, SWT.NONE, true, false);
section.setLayoutData(gridData);
return section;
}
private static Composite createParentComposite(Section section) {
Composite parentComposite = new Composite(section, SWT.NONE);
section.setClient(parentComposite);
parentComposite.setBackground(new Color(null, 0, 0, 255));
GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
parentComposite.setLayoutData(gridData);
GridLayout gridLayout = new GridLayout(1, false);
parentComposite.setLayout(gridLayout);
return parentComposite;
}
private static Composite createRow(Composite parent, String text) {
Composite row = new Composite(parent, SWT.NONE);
row.setBackground(new Color(null, 255, 255, 255));
GridData rowGridData = new GridData(SWT.FILL, SWT.FILL, true, false);
row.setLayoutData(rowGridData);
Label label = new Label(row, SWT.NONE);
label.setText(text);
Button checkBox = new Button(row, SWT.CHECK);
checkBox.setBackground(new Color(null, 255, 0, 0));
ExtendingRowLayout rowLayout = new ExtendingRowLayout();
row.setLayout(rowLayout);
//RowLayout standardRowLayout = new RowLayout();
//row.setLayout(standardRowLayout);
return row;
}
private static void showUntilClosed(Shell shell) {
shell.open();
Display display = Display.getCurrent();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
答案 0 :(得分:2)
对于您要做的事情,我认为避免扩展Layout
最安全(也是最简单),而是使用现有的Layout
实现。在看到你附加的两个图像时想到的第一个想法是,当达到任意最小尺寸时,你在布局中有一列和两列之间切换。
考虑到这一点,您可以使用ControlListener
(实际上ControlAdapter
,因为我们只关心调整大小)并在达到所需的大小阈值时更新列数。例如:
public class RowControlListener extends ControlAdapter {
// This can be computed from other values instead of being constant
private static final int MIN_WIDTH = 200;
private final Composite row;
private final Section section;
public RowControlListener(final Composite row, final Section section) {
this.row = row;
this.section = section;
}
@Override
public void controlResized(final ControlEvent e) {
final int width = row.getClientArea().width;
final GridLayout rowLayout = (GridLayout) row.getLayout();
final int numColumns = rowLayout.numColumns;
final int updatedNumColumns = width < MIN_WIDTH ? 1 : 2;
// Only do this if there's a change
if (numColumns != updatedNumColumns) {
rowLayout.numColumns = updatedNumColumns;
section.layout(true, true);
}
}
}
现在我们有了一个监听器,唯一的其他变化是添加监听器,然后是一些小的化妆品更新:
public static void main(final String[] args) {
// ... other setup ...
final Composite row1 = createRow(parentComposite, "first");
final Composite row2 = createRow(parentComposite, "second");
final Composite row3 = createRow(parentComposite, "third");
row1.addControlListener(new RowControlListener(row1, section));
row2.addControlListener(new RowControlListener(row2, section));
row3.addControlListener(new RowControlListener(row3, section));
// ... other setup ...
}
GridData
和Label
设置Button
的细微更改。然后,我们使用widthHint
上的GridData
作为Label
,以便所有内容排成一行。在实际设置中,应该计算并传入(类似于您当前通过传递80
所做的事情),以确保它在所有情况下都大于文本的长度。
public static Composite createRow(final Composite parent, final String text) {
// ... other setup ...
final Label label = new Label(row, SWT.NONE);
final GridData labelGridData = new GridData(SWT.FILL, SWT.FILL, false,
false);
labelGridData.widthHint = 80;
label.setLayoutData(labelGridData);
label.setText(text);
final Button checkBox = new Button(row, SWT.CHECK);
checkBox.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
checkBox.setBackground(new Color(null, 255, 0, 0));
final GridLayout rowLayout = new GridLayout(2, false);
rowLayout.marginHeight = 0;
rowLayout.marginWidth = 0;
row.setLayout(rowLayout);
return row;
}
值得一提的是,我最初指定GridLayout
有2列,因为我知道Shell
足够容纳Shell
。实际上,如果您事先不知道section.layout()
大小,那么您可以随意选择1或2,但在添加侦听器后调用pan: {
enabled: true,
mode: 'x'
},
zoom: {
enabled: true,
mode: 'x'
}
,以便适当地重新排列。
结果: