我已将问题缩小到这个简单的代码段:
this.addClickListener(new ClickListener(){
@Override
public void buttonClick(ClickEvent event) {
Label spinner = new Label();
spinner.addStyleName("spinner");
((HorizontalLayout) event.getButton().getParent()).replaceComponent(event.getButton(), spinner);
}
});
它的作用是创建一个加载指示器并相应地替换单击的按钮:
好的,让我们(再次,当然简化)通过添加行getSaveListener().saveClick();
来执行另一个侦听器。总体而言,代码如下所示:
this.addClickListener(new ClickListener(){
@Override
public void buttonClick(ClickEvent event) {
Label spinner = new Label();
spinner.addStyleName("spinner");
((HorizontalLayout) event.getButton().getParent()).replaceComponent(event.getButton(), spinner);
getSaveListener().saveClick();
}
});
" SaveListener"设置如下:
bu.addSaveClickListener(new SaveClickListener() {
@Override
public void saveClick() {
System.out.println("Yes1");
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Yes2");
}
});
所需的行为是按钮变为微调器,写入" Yes1",等待4秒,最后写入" Yes2"。
问题在于它会执行" saveClick"在旋转器之前的东西:
为什么" SaveListener" (.saveClick()
)在" ClickListener"之前执行。 (.buttonClick()
)?我怎么能纠正这个?
@Override
public void buttonClick(ClickEvent event) {
Label spinner = new Label();
spinner.addStyleName("spinner");
System.out.println("SPINNER!");
((HorizontalLayout) event.getButton().getParent()).replaceComponent(event.getButton(), spinner);
System.out.println("Yes?");
getSaveListener().saveClick();
}
结果:
.replaceComponent()
看起来像这样:
public void replaceComponent(Component oldComponent, Component newComponent) {
// Gets the locations
int oldLocation = -1;
int newLocation = -1;
int location = 0;
for (final Iterator<Component> i = components.iterator(); i.hasNext();) {
final Component component = i.next();
if (component == oldComponent) {
oldLocation = location;
}
if (component == newComponent) {
newLocation = location;
}
location++;
}
if (oldLocation == -1) {
addComponent(newComponent);
} else if (newLocation == -1) {
Alignment alignment = getComponentAlignment(oldComponent);
float expandRatio = getExpandRatio(oldComponent);
removeComponent(oldComponent);
addComponent(newComponent, oldLocation);
applyLayoutSettings(newComponent, alignment, expandRatio);
} else {
// Both old and new are in the layout
if (oldLocation > newLocation) {
components.remove(oldComponent);
components.add(newLocation, oldComponent);
components.remove(newComponent);
components.add(oldLocation, newComponent);
} else {
components.remove(newComponent);
components.add(oldLocation, newComponent);
components.remove(oldComponent);
components.add(newLocation, oldComponent);
}
markAsDirty();
}
}
来自API:
replaceComponent
- public void replaceComponent(Component oldComponent, 组件newComponent)
用另一个组件替换容器中的组件而不改变位置。
此方法用另一个方法替换组件,使得新组件超过旧组件的位置。如果 旧组件不在容器中,新组件被添加到 容器。如果两个组件已经在容器中, 他们的职位被交换了。组件附加和分离事件应该 与添加和删除一样要小心。
指定人:
在ComponentContainer接口中的replaceComponent
参数:
- oldComponent:将被替换的旧组件。
- newComponent:要替换的新组件。
答案 0 :(得分:1)
正如cfrick指出的那样,一旦监听器执行完成,客户端UI将被更新是正常的Vaadin行为。在您的示例中,侦听器执行长时间运行的操作(休眠)。完成后,将更新UI,以便显示最后一个状态。
Vaadin文档涵盖了这个主题:https://vaadin.com/docs/-/part/framework/components/components-progressbar.html
有一个很好的例子。我们的想法是在一个单独的线程中运行该操作,并通过轮询或Vaadin推送来更新UI。
P.S。:由于这个问题已经被cfrick作为评论回答,我将把它作为社区维基提供。