WizardDialog 中的 StackLayout 以及具有固定高度和动态显示滚动条的可变多行文本
StackLayout in WizardDialog and varying multiline Text with fixed height and dynamically showed scrollbar
我正在开发一个向导,如果发生错误,它应该在控件顶部显示一个错误组合。该组合包含一个列出所有错误的 Text
和两个 Label
:位于该组件上方和下方。错误列表下面的Label
可以省略。根据错误的数量,错误列表的高度应该有所不同。但是它不应超过父组合的高度。如果错误不适合整个高度的 Text
,则应显示滚动条。
这是我到目前为止所达到的最小化片段:
package de.dannylo.issues;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Text;
public class TestWizardPage
extends WizardPage
{
private static final String PLUGIN_ID = "de.dannylo.issues.TestPlugin";
private Composite mainComposite;
private Composite stackComposite;
private StackLayout stackLayout;
private Composite defaultMessageComposite;
private Text idText;
private static Wizard wizard;
public TestWizardPage()
{
super("portalAppWizardMavenPage");
setTitle("TestWizard");
setDescription("Testing...");
}
@Override
public void createControl(Composite parent)
{
mainComposite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
mainComposite.setLayout(layout);
layout.numColumns = 1;
layout.verticalSpacing = 15;
// source folder
Composite idComposite = new Composite(mainComposite, SWT.NONE);
idComposite.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false));
idComposite.setLayout(new GridLayout(2, false));
Label label = new Label(idComposite, SWT.NONE);
label.setText("ID:");
idText = new Text(idComposite, SWT.BORDER | SWT.SINGLE);
idText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
label = new Label(mainComposite, SWT.SEPARATOR | SWT.HORIZONTAL);
label.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false));
stackComposite = new Composite(mainComposite, SWT.NONE);
GridData layoutData = new GridData(SWT.FILL, SWT.NONE, true, false);
layoutData.heightHint = 250; // For testing purposes in the real GUI
// there are several components filling
// this composite
stackComposite.setLayoutData(layoutData);
stackLayout = new StackLayout();
stackComposite.setLayout(stackLayout);
defaultMessageComposite = new Composite(stackComposite, SWT.NONE);
defaultMessageComposite.setLayout(new GridLayout());
stackLayout.topControl = defaultMessageComposite;
label = new Label(defaultMessageComposite, SWT.NONE);
label.setText("Enter \"1\", \"2\" or \"3\" into the text field above.");
idText.addModifyListener(new ModifyListener()
{
@Override
public void modifyText(ModifyEvent e)
{
if ("1".equals(idText.getText()))
showErrorComposite("You entered id 1", "Nice job!", createTestStatusList(4));
else if ("2".equals(idText.getText()))
showErrorComposite("You entered id 2", "Oops", createTestStatusList(20));
else if ("3".equals(idText.getText()))
showErrorComposite("You entered id 3", null, createTestStatusList(20));
else
{
stackLayout.topControl = defaultMessageComposite;
stackComposite.layout();
}
}
});
setControl(mainComposite);
}
private static List<IStatus> createTestStatusList(int amount)
{
List<IStatus> toRet = new ArrayList<IStatus>();
for (int i = 0; i < amount; i++)
{
toRet.add(new Status(IStatus.ERROR, PLUGIN_ID, "Error message " + i + ": " + toRet.hashCode()));
}
return toRet;
}
private void showErrorComposite(String topMessage, String bottomMessage, List<IStatus> statusList)
{
final Composite errorComposite = new Composite(stackComposite, SWT.BORDER);
final GridLayout layout = new GridLayout();
layout.verticalSpacing = 20;
errorComposite.setLayout(layout);
errorComposite.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false));
final Label topLabel = new Label(errorComposite, SWT.WRAP | SWT.BORDER);
topLabel.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false));
topLabel.setText(topMessage);
final Text errorList = new Text(errorComposite, SWT.MULTI | SWT.WRAP | SWT.READ_ONLY | SWT.V_SCROLL
| SWT.BORDER);
final GridData gd_errorList = new GridData(SWT.FILL, SWT.NONE, true, false);
gd_errorList.horizontalIndent = 20;
errorList.setLayoutData(gd_errorList);
for (int i = 0; i < statusList.size(); i++)
{
IStatus status = statusList.get(i);
errorList.append("\u2022 " + status.getMessage());
if (i != statusList.size() - 1)
errorList.append("\n\n");
}
final Label bottomLabel;
if (bottomMessage != null)
{
bottomLabel = new Label(errorComposite, SWT.WRAP | SWT.BORDER);
bottomLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
bottomLabel.setText(bottomMessage);
}
else
bottomLabel = null;
final Listener scrollBarListener = new Listener()
{
@Override
public void handleEvent(Event event)
{
errorList.removeListener(SWT.Resize, this);
int marginHeight = ((GridLayout)errorComposite.getLayout()).marginHeight;
int stackCompositeHeight = stackComposite.getClientArea().height;
int topLabelHeight = topLabel.getSize().y;
int verticalSpacing = layout.verticalSpacing;
int bottomLabelHeight = bottomLabel == null ? 0 : bottomLabel.getSize().y;
int spaceAboveErrorList = marginHeight + topLabelHeight + verticalSpacing;
int spaceBelowErrorList = bottomLabel == null ? marginHeight + 15 : verticalSpacing
+ bottomLabelHeight
+ marginHeight + 15;
int hHint = stackCompositeHeight - spaceAboveErrorList - spaceBelowErrorList;
Rectangle errorListClientArea = errorList.getClientArea();
Point errorListSize = errorList.computeSize(errorListClientArea.x, SWT.DEFAULT, true);
if (stackCompositeHeight < spaceAboveErrorList + errorListSize.y + spaceBelowErrorList)
{
gd_errorList.heightHint = hHint;
errorList.getVerticalBar().setVisible(true);
}
else
{
gd_errorList.heightHint = errorListSize.y;
errorList.getVerticalBar().setVisible(false);
}
errorComposite.layout();
errorList.addListener(SWT.Resize, this);
}
};
errorList.addListener(SWT.Resize, scrollBarListener);
stackLayout.topControl = errorComposite;
stackComposite.layout();
}
public static void main(String[] args)
{
Display.getDefault().syncExec(new Runnable()
{
@Override
public void run()
{
wizard = new Wizard()
{
@Override
public void addPages()
{
addPage(new TestWizardPage());
}
@Override
public boolean performFinish()
{
MessageDialog.openInformation(getShell(), "Bye!", "Thanks for testing!");
return true;
}
};
}
});
new WizardDialog(wizard.getShell(), wizard).open();
}
}
我的 ID2 有问题。在这种情况下,Text
的高度最大,应该显示 bottomLabel
。不幸的是,这个标签并没有像复合标签那样出现,而是仅在 window 的宽度发生变化后才出现。这似乎是布局的一些问题。我已经尝试使用 errorComposite.layout(true, true)
(甚至 getShell().layout(true, true)
)来刷新缓存并重绘子项,但这没有帮助。关于如何解决该问题的任何想法?
我通过完全删除 scrollBarListener
并稍微修复一下布局解决了您的问题。
showErrorComposite(...)
方法现在看起来像这样:
private void showErrorComposite(String topMessage, String bottomMessage, List<IStatus> statusList)
{
final Composite errorComposite = new Composite(stackComposite, SWT.BORDER);
final GridLayout layout = new GridLayout();
layout.verticalSpacing = 20;
errorComposite.setLayout(layout);
errorComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
final Label topLabel = new Label(errorComposite, SWT.WRAP | SWT.BORDER);
topLabel.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
topLabel.setText(topMessage);
final Text errorList = new Text(errorComposite, SWT.MULTI | SWT.WRAP | SWT.READ_ONLY | SWT.V_SCROLL
| SWT.BORDER);
final GridData gd_errorList = new GridData(SWT.FILL, SWT.FILL, true, true);
gd_errorList.horizontalIndent = 20;
errorList.setLayoutData(gd_errorList);
for (int i = 0; i < statusList.size(); i++)
{
IStatus status = statusList.get(i);
errorList.append("\u2022 " + status.getMessage());
if (i != statusList.size() - 1)
errorList.append("\n\n");
}
errorList.setTopIndex(0);
final Label bottomLabel;
if (bottomMessage != null)
{
bottomLabel = new Label(errorComposite, SWT.WRAP | SWT.BORDER);
bottomLabel.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, false));
bottomLabel.setText(bottomMessage);
}
else
bottomLabel = null;
stackLayout.topControl = errorComposite;
stackComposite.layout();
}
现在看起来像这样:
更新
好的,在你的特定情况下,保持你的代码不变,只需在你的 showErrorComposite(...)
方法的末尾添加这一行:
scrollBarListener.handleEvent(null);
我正在开发一个向导,如果发生错误,它应该在控件顶部显示一个错误组合。该组合包含一个列出所有错误的 Text
和两个 Label
:位于该组件上方和下方。错误列表下面的Label
可以省略。根据错误的数量,错误列表的高度应该有所不同。但是它不应超过父组合的高度。如果错误不适合整个高度的 Text
,则应显示滚动条。
这是我到目前为止所达到的最小化片段:
package de.dannylo.issues;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Text;
public class TestWizardPage
extends WizardPage
{
private static final String PLUGIN_ID = "de.dannylo.issues.TestPlugin";
private Composite mainComposite;
private Composite stackComposite;
private StackLayout stackLayout;
private Composite defaultMessageComposite;
private Text idText;
private static Wizard wizard;
public TestWizardPage()
{
super("portalAppWizardMavenPage");
setTitle("TestWizard");
setDescription("Testing...");
}
@Override
public void createControl(Composite parent)
{
mainComposite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
mainComposite.setLayout(layout);
layout.numColumns = 1;
layout.verticalSpacing = 15;
// source folder
Composite idComposite = new Composite(mainComposite, SWT.NONE);
idComposite.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false));
idComposite.setLayout(new GridLayout(2, false));
Label label = new Label(idComposite, SWT.NONE);
label.setText("ID:");
idText = new Text(idComposite, SWT.BORDER | SWT.SINGLE);
idText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
label = new Label(mainComposite, SWT.SEPARATOR | SWT.HORIZONTAL);
label.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false));
stackComposite = new Composite(mainComposite, SWT.NONE);
GridData layoutData = new GridData(SWT.FILL, SWT.NONE, true, false);
layoutData.heightHint = 250; // For testing purposes in the real GUI
// there are several components filling
// this composite
stackComposite.setLayoutData(layoutData);
stackLayout = new StackLayout();
stackComposite.setLayout(stackLayout);
defaultMessageComposite = new Composite(stackComposite, SWT.NONE);
defaultMessageComposite.setLayout(new GridLayout());
stackLayout.topControl = defaultMessageComposite;
label = new Label(defaultMessageComposite, SWT.NONE);
label.setText("Enter \"1\", \"2\" or \"3\" into the text field above.");
idText.addModifyListener(new ModifyListener()
{
@Override
public void modifyText(ModifyEvent e)
{
if ("1".equals(idText.getText()))
showErrorComposite("You entered id 1", "Nice job!", createTestStatusList(4));
else if ("2".equals(idText.getText()))
showErrorComposite("You entered id 2", "Oops", createTestStatusList(20));
else if ("3".equals(idText.getText()))
showErrorComposite("You entered id 3", null, createTestStatusList(20));
else
{
stackLayout.topControl = defaultMessageComposite;
stackComposite.layout();
}
}
});
setControl(mainComposite);
}
private static List<IStatus> createTestStatusList(int amount)
{
List<IStatus> toRet = new ArrayList<IStatus>();
for (int i = 0; i < amount; i++)
{
toRet.add(new Status(IStatus.ERROR, PLUGIN_ID, "Error message " + i + ": " + toRet.hashCode()));
}
return toRet;
}
private void showErrorComposite(String topMessage, String bottomMessage, List<IStatus> statusList)
{
final Composite errorComposite = new Composite(stackComposite, SWT.BORDER);
final GridLayout layout = new GridLayout();
layout.verticalSpacing = 20;
errorComposite.setLayout(layout);
errorComposite.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false));
final Label topLabel = new Label(errorComposite, SWT.WRAP | SWT.BORDER);
topLabel.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false));
topLabel.setText(topMessage);
final Text errorList = new Text(errorComposite, SWT.MULTI | SWT.WRAP | SWT.READ_ONLY | SWT.V_SCROLL
| SWT.BORDER);
final GridData gd_errorList = new GridData(SWT.FILL, SWT.NONE, true, false);
gd_errorList.horizontalIndent = 20;
errorList.setLayoutData(gd_errorList);
for (int i = 0; i < statusList.size(); i++)
{
IStatus status = statusList.get(i);
errorList.append("\u2022 " + status.getMessage());
if (i != statusList.size() - 1)
errorList.append("\n\n");
}
final Label bottomLabel;
if (bottomMessage != null)
{
bottomLabel = new Label(errorComposite, SWT.WRAP | SWT.BORDER);
bottomLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
bottomLabel.setText(bottomMessage);
}
else
bottomLabel = null;
final Listener scrollBarListener = new Listener()
{
@Override
public void handleEvent(Event event)
{
errorList.removeListener(SWT.Resize, this);
int marginHeight = ((GridLayout)errorComposite.getLayout()).marginHeight;
int stackCompositeHeight = stackComposite.getClientArea().height;
int topLabelHeight = topLabel.getSize().y;
int verticalSpacing = layout.verticalSpacing;
int bottomLabelHeight = bottomLabel == null ? 0 : bottomLabel.getSize().y;
int spaceAboveErrorList = marginHeight + topLabelHeight + verticalSpacing;
int spaceBelowErrorList = bottomLabel == null ? marginHeight + 15 : verticalSpacing
+ bottomLabelHeight
+ marginHeight + 15;
int hHint = stackCompositeHeight - spaceAboveErrorList - spaceBelowErrorList;
Rectangle errorListClientArea = errorList.getClientArea();
Point errorListSize = errorList.computeSize(errorListClientArea.x, SWT.DEFAULT, true);
if (stackCompositeHeight < spaceAboveErrorList + errorListSize.y + spaceBelowErrorList)
{
gd_errorList.heightHint = hHint;
errorList.getVerticalBar().setVisible(true);
}
else
{
gd_errorList.heightHint = errorListSize.y;
errorList.getVerticalBar().setVisible(false);
}
errorComposite.layout();
errorList.addListener(SWT.Resize, this);
}
};
errorList.addListener(SWT.Resize, scrollBarListener);
stackLayout.topControl = errorComposite;
stackComposite.layout();
}
public static void main(String[] args)
{
Display.getDefault().syncExec(new Runnable()
{
@Override
public void run()
{
wizard = new Wizard()
{
@Override
public void addPages()
{
addPage(new TestWizardPage());
}
@Override
public boolean performFinish()
{
MessageDialog.openInformation(getShell(), "Bye!", "Thanks for testing!");
return true;
}
};
}
});
new WizardDialog(wizard.getShell(), wizard).open();
}
}
我的 ID2 有问题。在这种情况下,Text
的高度最大,应该显示 bottomLabel
。不幸的是,这个标签并没有像复合标签那样出现,而是仅在 window 的宽度发生变化后才出现。这似乎是布局的一些问题。我已经尝试使用 errorComposite.layout(true, true)
(甚至 getShell().layout(true, true)
)来刷新缓存并重绘子项,但这没有帮助。关于如何解决该问题的任何想法?
我通过完全删除 scrollBarListener
并稍微修复一下布局解决了您的问题。
showErrorComposite(...)
方法现在看起来像这样:
private void showErrorComposite(String topMessage, String bottomMessage, List<IStatus> statusList)
{
final Composite errorComposite = new Composite(stackComposite, SWT.BORDER);
final GridLayout layout = new GridLayout();
layout.verticalSpacing = 20;
errorComposite.setLayout(layout);
errorComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
final Label topLabel = new Label(errorComposite, SWT.WRAP | SWT.BORDER);
topLabel.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
topLabel.setText(topMessage);
final Text errorList = new Text(errorComposite, SWT.MULTI | SWT.WRAP | SWT.READ_ONLY | SWT.V_SCROLL
| SWT.BORDER);
final GridData gd_errorList = new GridData(SWT.FILL, SWT.FILL, true, true);
gd_errorList.horizontalIndent = 20;
errorList.setLayoutData(gd_errorList);
for (int i = 0; i < statusList.size(); i++)
{
IStatus status = statusList.get(i);
errorList.append("\u2022 " + status.getMessage());
if (i != statusList.size() - 1)
errorList.append("\n\n");
}
errorList.setTopIndex(0);
final Label bottomLabel;
if (bottomMessage != null)
{
bottomLabel = new Label(errorComposite, SWT.WRAP | SWT.BORDER);
bottomLabel.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, false));
bottomLabel.setText(bottomMessage);
}
else
bottomLabel = null;
stackLayout.topControl = errorComposite;
stackComposite.layout();
}
现在看起来像这样:
更新
好的,在你的特定情况下,保持你的代码不变,只需在你的 showErrorComposite(...)
方法的末尾添加这一行:
scrollBarListener.handleEvent(null);