【发布时间】:2017-08-14 18:43:54
【问题描述】:
打开新对话框时,在加载时,您在父 shell 上单击了几次,显然新对话框无法正确显示。 请看下面的例子:
示例
- https://i.stack.imgur.com/ZovxE.png(Eclipse IDE 示例)
- https://i.stack.imgur.com/5zVar.png
- https://i.stack.imgur.com/u86b9.png
- https://i.stack.imgur.com/FGaAr.png
最初我在 2014 年 12 月遇到了这个问题,当时也被许多内部开发人员报告过,他们使用不同的开发系统,然后我们的几个客户也报告了同样的问题。
可以使用以下环境重现此行为:
- Windows 版本:7 Pro 64 位 - 6.1.7601
- Java 版本:RE 1.8.0_121_b13
- SWT 版本
- 3.8.2
- 4.6.2
- 4.7M6
- I20170319-2000
我只能在 Windows 7 上使用 Windows 基本主题/设计/样式(不能使用经典或航空)重现该问题。 在 Windows 10 上,它无法重现。
再现
重现代码
package test;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Dialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
public class Main {
public static void main(String[] args) {
Display display = new Display();
final Shell shell = createShell(display);
createButton(shell);
shell.open();
eventLoop(display, shell);
display.dispose();
}
private static Shell createShell(Display display) {
final Shell shell = new Shell(display);
shell.setLayout(new RowLayout());
shell.setSize(500, 200);
return shell;
}
private static void createButton(final Shell shell) {
final Button openDialog = new Button(shell, SWT.PUSH);
openDialog.setText("Click here to open Dialog ...");
openDialog.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
TestDialog inputDialog = new TestDialog(shell);
inputDialog.open();
}
});
}
private static void eventLoop(Display display, final Shell shell) {
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
}
class TestDialog extends Dialog {
public TestDialog(Shell parent) {
super(parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL | SWT.MIN | SWT.MAX | SWT.RESIZE);
setText("Dialog");
}
public void open() {
Shell shell = new Shell(getParent(), getStyle());
shell.setText(getText());
createContents(shell);
shell.pack();
initializeBounds(shell);
shell.open();
eventLoop(shell);
}
private void createContents(final Shell shell) {
shell.setLayout(new GridLayout(2, true));
Label label = new Label(shell, SWT.NONE);
label.setText("Some Label text ...");
final Text text = new Text(shell, SWT.BORDER);
GridData data = new GridData(GridData.FILL_HORIZONTAL);
text.setLayoutData(data);
createCloseButton(shell);
/* time for the user to create the misbehavior */
try {
Thread.sleep(15000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void createCloseButton(final Shell shell) {
Button closeButton = new Button(shell, SWT.PUSH);
closeButton.setText("Close");
GridData data = new GridData(GridData.FILL_HORIZONTAL);
closeButton.setLayoutData(data);
closeButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
shell.close();
}
});
shell.setDefaultButton(closeButton);
}
private void initializeBounds(Shell shell) {
Rectangle bounds = shell.getBounds();
Rectangle parentBounds = getParent().getBounds();
bounds.x = parentBounds.x;
bounds.y = parentBounds.y;
shell.setBounds(bounds);
}
private void eventLoop(Shell shell) {
Display display = getParent().getDisplay();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
}
重现步骤
- 启动应用程序
- 点击按钮。
- 不断点击父shell的右下角(避免点击新的打开对话框),直到鼠标光标变为等待图标,父shell改变颜色。
- 等到新对话框出现。
- 如下所示:https://i.stack.imgur.com/kTDgQ.png(显示不正确)
- 改为:https://i.stack.imgur.com/cHVjn.png(正确显示)
在视频中重现的步骤
当您将鼠标悬停在某些 UI 元素(最初未正确绘制)时,您会注意到其中一些被绘制(例如表格行)。
- https://i.stack.imgur.com/kkMKn.png(在打开对话框之前)
- https://i.stack.imgur.com/ZXIKc.png(打开对话框后)
- https://i.stack.imgur.com/25M7S.jpg(鼠标悬停后)
即使在对话框打开后调用Shell.update() 或Shell.redraw() 也无法修复它。
在 Windows 性能选项 -> 视觉效果 -> 禁用“在窗口和按钮上使用视觉样式”是我发现的唯一提供解决方法的选项, 这似乎与将设计/主题/样式更改为经典相同。
最后,我有以下问题: 是 SWT 还是 Windows 问题? Windows 的错误条目或 Eclipse Bugzilla 中是否有任何相关主题? 有没有其他人遇到过同样的问题?请分享经验。 SWT 或 Windows 中是否有任何设置会影响其外观并解决问题?
【问题讨论】:
-
在 SWT UI 线程中执行
Thread.sleep肯定会导致问题,因为它会停止调用display.readAndDispatch的线程,这对于 SWT 上的正确操作至关重要。 -
@greg-449
Thread.sleep只是模拟 UI 线程上不可避免的更长操作。例如在TestDialog inputDialog = new TestDialog(shell);和inputDialog.open();之间也可能发生这种情况,关键是操作完成后UI 没有赶上描述的情况并导致描述的结果。有没有办法强制正确绘制对话框? -
您不得在 UI 线程上执行任何长操作 - 您必须在后台线程中执行这些操作。不及时拨打
readAndDispatch总会出问题。 -
我知道响应式 UI 需要
Display.readAndDispatch()(在这种情况下我不关心)。我不知道您不允许在 UI 线程上执行任何长时间的操作,这对我来说似乎很奇怪。 @greg-449 请分享您指定的来源。 -
几乎任何关于 SWT 的描述都会告诉你这一点。首先出现的是 Eclipse 后台任务中的Vogella tutorial(Eclipse 只是一个大型 SWT 应用程序)。请参阅第 2.1 节“主线程”。正如我所说,要求是必须不断调用
readAndDispatch,任何延迟调用都会导致问题。
标签: user-interface windows-7 dialog swt