SWT更新/重绘/布局问题
我知道很多人都遇到过这个问题,但是我在网上找到的解决方案似乎并不能解决我的问题。 我有一个包含三个按钮的组合。 我想要的是以下内容: 当我单击一个按钮时,我希望其他一些按钮变灰( setEnabled(false) ),并且在一段时间后(在方法执行之后),我希望再次启用该按钮。
许多此类问题可以通过在父容器上调用layout()方法来解决,或者这个非常相似的问题是通过调用 Display.getCurrent().update() 解决的;
简单地说,我的代码可以总结如下:
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
public class app1 {
protected Shell shell;
/**
* Launch the application.
* @param args
*/
public static void main(String[] args) {
try {
app1 window = new app1();
window.open();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Open the window.
*/
public void open() {
Display display = Display.getDefault();
createContents();
shell.open();
shell.layout();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
/**
* Create contents of the window.
*/
Button button1 , button2 , button3;
Label label;
protected void createContents() {
shell = new Shell();
shell.setSize(450, 300);
shell.setText("SWT Application");
shell.setLayout(new GridLayout(1,false));
{
final Composite composite = new Composite(shell, SWT.NONE);
composite.setLayout(new GridLayout(3,false));
GridData gd_composite = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL);
gd_composite.grabExcessHorizontalSpace = true;
gd_composite.horizontalSpan = 10; //?
gd_composite.verticalIndent = 5;
composite.setLayoutData(gd_composite);
GridData gd_button;
{
button1 = new Button(composite, SWT.NONE);
button1.setText("Button 1");
gd_button = new GridData(SWT.FILL, GridData.BEGINNING, false, false);
gd_button.horizontalSpan = 1;
button1.setLayoutData(gd_button);
button1.addSelectionListener(new SelectionListener(){
public void widgetSelected(SelectionEvent e){
try{
button2.setEnabled(false);
button2.redraw();
button2.update();
//composite.redraw();
//composite.update();
//composite.layout();
shell.redraw();
shell.update();
shell.layout();
Display.getCurrent().update();
} catch (Exception e2) {
System.err.println("exception e : " + e2.toString());
}
System.out.println("basla");
try {
System.out.println("sleep1");
Thread.sleep(100);
} catch (InterruptedException e1) {
e1.printStackTrace();
} catch (Throwable th) {
System.err.println("th: " + th.toString());
}
try {
System.out.println("sleep2");
Thread.sleep(100);
} catch (InterruptedException e1) {
e1.printStackTrace();
} catch (Throwable th) {
System.err.println("th: " + th.toString());
}
try {
System.out.println("sleep3");
Thread.sleep(100);
} catch (InterruptedException e1) {
e1.printStackTrace();
} catch (Throwable th) {
System.err.println("th: " + th.toString());
}
for(int i=0 ; i < 10000 ; i++)
{
System.out.println(i);
}
}
public void widgetDefaultSelected(SelectionEvent e) {
System.err.println("widgetDefault !");
}
});
}
{
button2 = new Button(composite, SWT.NONE);
button2.setText("Button 2");
gd_button = new GridData(SWT.FILL, GridData.CENTER, false, false);
gd_button.horizontalSpan = 1;
button2.setLayoutData(gd_button);
button2.addSelectionListener(new SelectionListener(){
public void widgetSelected(SelectionEvent e){
button1.setEnabled(false);
composite.layout();
for (int i=1; i<=100; i++) {
try {
Thread.sleep(10);
} catch (Throwable th) {}
label.setText(i + " %");
label.update();
}
}
public void widgetDefaultSelected(SelectionEvent e) {}
});
}
{
label = new Label(composite , SWT.NONE);
label.setText("0 %");
label.update();
}
}
}
}
发生的情况是,在达到 widgetSelected() 方法末尾后按钮被禁用。 但是,标签经常更新,没有任何问题(即使 label.update() 方法不存在)
附加信息:比如说,我禁用按钮,然后放置 Thread.sleep(),然后启用按钮; 它首先休眠,然后快速禁用和启用按钮。 所以我相信所有此类绘制请求都会排队并在执行结束时进行处理。
有用信息:我意识到,当我在显示更改后立即创建并显示 MessageBox 时,显示会发生更改。 因此,如果我在 widgetSelected 方法中进行以下更改:
button2.setEnabled(false)
MessageBox mBox = new MessageBox(Display.getCurrent().getActiveShell(), SWT.ICON_INFORMATION | SWT.OK);
mBox.setText("Information");
mBox.setMessage("Buttons updated!");
mBox.open();
一旦调用 widgetSelected() 方法,该按钮就会变灰。 这让我相信我的解决方案位于 Display.getCurrent() 方法中。 但是,我尝试了
Display.getCurrent().getActiveShell().redraw() Display.getCurrent().getActiveShell().update() Display.getCurrent().getActiveShell().layout()
一些方法,但没有解决我的问题。
谢谢, 埃格
I know many people experience this problem, but the solutions I found online do not seem to solve mine. I have a composite that has three buttons. What I want is the following :
When I click one button, I want some other button to be grayed out ( setEnabled(false) ) and after a while (after a method execution), I want the button to be enabled again.
Many such problems are solved by calling layout() method on the parent container, or this very similar one is solved by calling Display.getCurrent().update();
Simply, my code could be summarized as follows :
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
public class app1 {
protected Shell shell;
/**
* Launch the application.
* @param args
*/
public static void main(String[] args) {
try {
app1 window = new app1();
window.open();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Open the window.
*/
public void open() {
Display display = Display.getDefault();
createContents();
shell.open();
shell.layout();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
/**
* Create contents of the window.
*/
Button button1 , button2 , button3;
Label label;
protected void createContents() {
shell = new Shell();
shell.setSize(450, 300);
shell.setText("SWT Application");
shell.setLayout(new GridLayout(1,false));
{
final Composite composite = new Composite(shell, SWT.NONE);
composite.setLayout(new GridLayout(3,false));
GridData gd_composite = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL);
gd_composite.grabExcessHorizontalSpace = true;
gd_composite.horizontalSpan = 10; //?
gd_composite.verticalIndent = 5;
composite.setLayoutData(gd_composite);
GridData gd_button;
{
button1 = new Button(composite, SWT.NONE);
button1.setText("Button 1");
gd_button = new GridData(SWT.FILL, GridData.BEGINNING, false, false);
gd_button.horizontalSpan = 1;
button1.setLayoutData(gd_button);
button1.addSelectionListener(new SelectionListener(){
public void widgetSelected(SelectionEvent e){
try{
button2.setEnabled(false);
button2.redraw();
button2.update();
//composite.redraw();
//composite.update();
//composite.layout();
shell.redraw();
shell.update();
shell.layout();
Display.getCurrent().update();
} catch (Exception e2) {
System.err.println("exception e : " + e2.toString());
}
System.out.println("basla");
try {
System.out.println("sleep1");
Thread.sleep(100);
} catch (InterruptedException e1) {
e1.printStackTrace();
} catch (Throwable th) {
System.err.println("th: " + th.toString());
}
try {
System.out.println("sleep2");
Thread.sleep(100);
} catch (InterruptedException e1) {
e1.printStackTrace();
} catch (Throwable th) {
System.err.println("th: " + th.toString());
}
try {
System.out.println("sleep3");
Thread.sleep(100);
} catch (InterruptedException e1) {
e1.printStackTrace();
} catch (Throwable th) {
System.err.println("th: " + th.toString());
}
for(int i=0 ; i < 10000 ; i++)
{
System.out.println(i);
}
}
public void widgetDefaultSelected(SelectionEvent e) {
System.err.println("widgetDefault !");
}
});
}
{
button2 = new Button(composite, SWT.NONE);
button2.setText("Button 2");
gd_button = new GridData(SWT.FILL, GridData.CENTER, false, false);
gd_button.horizontalSpan = 1;
button2.setLayoutData(gd_button);
button2.addSelectionListener(new SelectionListener(){
public void widgetSelected(SelectionEvent e){
button1.setEnabled(false);
composite.layout();
for (int i=1; i<=100; i++) {
try {
Thread.sleep(10);
} catch (Throwable th) {}
label.setText(i + " %");
label.update();
}
}
public void widgetDefaultSelected(SelectionEvent e) {}
});
}
{
label = new Label(composite , SWT.NONE);
label.setText("0 %");
label.update();
}
}
}
}
What happens is, the button gets disabled after the end of widgetSelected() method is reached. However, the label gets updated frequently without any problem (even when the label.update() method is not there)
Additional information : Say, I disable the button, then put a Thread.sleep() and then enable the button ; it sleeps first and then quickly disables and enables the button. So I believe all such paint requests are queued and are processed at the end of the execution.
Useful information: I realized that, when I create and display a MessageBox right after my display changes, the display changes occur. So, if I make the following change in my widgetSelected method :
button2.setEnabled(false)
MessageBox mBox = new MessageBox(Display.getCurrent().getActiveShell(), SWT.ICON_INFORMATION | SWT.OK);
mBox.setText("Information");
mBox.setMessage("Buttons updated!");
mBox.open();
the button will be grayed out as soon as the widgetSelected() method is called. This makes me believe my solution lies within Display.getCurrent() methods. However, I tried
Display.getCurrent().getActiveShell().redraw() Display.getCurrent().getActiveShell().update() Display.getCurrent().getActiveShell().layout()
methods and they didnt solve my problem.
Thanks,
Ege
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
好吧,我已经纠正了 ginu 的答案:
New Runnable().run() 实际上没什么作用,但这个想法是正确的:
你需要一个新线程来完成你的工作。问题是,从那个线程你无法在按钮上调用 setEnabled,因为这只能在 SWT-Event 线程内完成。
因此,您需要另一个可运行程序来重置按钮。 第二个可运行对象被传递给 Display.callAsync 并在实际执行之前返回,但这在这里并不重要。 您还可以使用 Display.callSync( Runnable ),该调用将阻塞您的调用线程,直到可运行返回。
在 Eclipse 中进行了测试,到目前为止看起来不错。
编辑:顺便说一句,调用layout()或Display.update()不起作用的原因是您当前正在用您的工作阻塞SWT线程,因此对layout/update的调用会排队并且仅在您离开时执行事件处理程序。 切勿阻止事件处理程序执行长时间工作。 :)
}
Ok, i've corrected the answer from ginu:
New Runnable().run() does actually not much to nothing, but the idea is correct:
You need a new thread to do your work in. Problem is, from that thread you can't call setEnabled on the buttons, because that can only be done from within the SWT-Event thread.
So you need another runnable to reset the buttons. The second runnable is passed to Display.callAsync and returns before it is actually executed, but that doesn't matter here. You could also use Display.callSync( Runnable ), that call would block your calling thread until the runnable returns.
Tested it in Eclipse, looks good so far.
Edit: Btw, the reason why calling layout() or Display.update() did not work is that you're currently blocking the SWT-Thread with your work, so the calls to layout/update are queued and only executed when you leave the event handler. Never block an event handler to do long work. :)
}
您的代码片段似乎并不完整,但我想到了一些关于您的问题的事情。 您可能可以使用 setEnabled,如下面的代码片段所示。 对于更高级的事情,您可以将 .exclude 属性与 setVisible 结合使用来查看 GridLayout 和 GridData。 作为参考,SWT Snippets 页面 非常棒。
It doesn't appear that your snippet is complete, but a few things came to mind regarding your problem. You can probably use setEnabled as seen in the snippet below. For more advance things you could look at GridLayout and GridData with the .exclude property in conjunction with setVisible. For reference the SWT Snippets page is really great.
我不太确定您是否在启用/禁用按钮或在执行流程之间设置延迟方面遇到问题。
我已经修改了上面 Jared 的代码来执行提到的这两个操作。 请看一下这个,然后告诉我这是否是您正在寻找的。
干杯。 :-)
I am not really sure if you have a problem with the enabling / disabling of the buttons, or putting the delay in between the execution flow.
I have modified Jared's code above to perform both these operations mentioned. Please have a look at this and let me know if this what you were looking for.
Cheers. :-)