如何在模板中显示弹出窗口并传递参数
How to display popup in a template and pass it arguments
我的应用程序的一部分是记录比赛的完成时间。因为这很可能是在 phone 或平板电脑上完成的,所以我想实现一个小弹出窗口来轻松修改时间,而不必准确设置焦点并输入它。但是时间开始为 00:00:00 对于每个完成时间都会使过程非常费力,所以我想让它初始化为最后输入的完成时间。如果输入的时间位于网格顶部,我希望弹出窗口直接出现在时间框下方,或者如果输入的时间位于网格底部的时间框上方。下面是我的代码的精简版本,希望有助于解释这个概念。
我的弹出窗口 window:entertime.zul
<window viewModel="@id('vmtp') @init('EnterTimeVM')" onBlur="@command('close')">
<caption>
<toolbarbutton label="Save" onClick="@command('save')"/>
<toolbarbutton label="Cancel" onClick="@command('close')"/>
</caption>
<hlayout>
<vlayout>
<button label="+" onClick="@command('changeHours', amount='1')" />
<intbox value="@load(vmtp.hours)" readonly="true" />
<button label="-" onClick="@command('changeHours', amount='-1')" />
</vlayout>
<vlayout>
<button label="+" onClick="@command('changeMinutes', amount='1')" />
<intbox value="@load(vmtp.minutes)" readonly="true" />
<button label="-" onClick="@command('changeMinutes', amount='-1')" />
</vlayout>
<vlayout>
<button label="+" onClick="@command('changeSeconds', amount='1')" />
<intbox value="@load(vmtp.seconds)" readonly="true" />
<button label="-" onClick="@command('changeSeconds', amount='-1')" />
</vlayout>
</hlayout>
</window>
EnterTimeVM.java
public class EnterTimeVM {
private LocalDateTime ldt;
private Component view;
@Init
public void init(@ExecutionArgParam("initTime") LocalDateTime initTime,
@ContextParam(ContextType.VIEW) Component view) {
ldt = initTime;
this.view = view;
}
public int getHours() {
return ldt.getHour();
}
public int getMinutes() {
return ldt.getMinute();
}
public int getSeconds() {
return ldt.getSecond();
}
@Command
@NotifyChange("hours")
public void changeHours(@BindingParam("amount") int amount) {
ldt = ldt.plusHours(amount);
}
@Command
@NotifyChange({ "hours", "minutes" })
public void changeMinutes(@BindingParam("amount") int amount) {
ldt = ldt.plusMinutes(amount);
}
@Command
@NotifyChange({ "hours", "minutes", "seconds" })
public void changeSeconds(@BindingParam("amount") int amount) {
ldt = ldt.plusSeconds(amount);
}
@Command
public void save() {
Map<String, Object> args = new HashMap<>();
args.put("finishTime", ldt);
BindUtils.postGlobalCommand(null, null, "finishTime", args);
close();
}
@Command
public void close() {
view.detach();
}
}
这是我的主要 zul 和视图模型。
timekeeper.zul(为简洁起见删除了多余的列)
<window viewModel="@id('vmtk') @init('TimeKeeperVM')">
<grid model="@load(vmtk.competitors)">
<columns>
<column label="Name" />
<column label="Finish time" />
</columns>
<template name="model">
<row>
<label value="@load(each.name)" />
<timebox format="HH:mm:ss" value="@bind(each.finishTime)"
onFocus="@command('changeFinishTime', comp=each)" />
</row>
</template>
</grid>
</window>
Competitor.java
public class Competitor {
private String name;
private LocalDateTime finishTime;
// getters and setters
}
TimeKeeperVM.java
public class TimeKeeperVM {
private List<Competitor> competitors;
private Competitor selectedCompetitor;
private LocalDateTime prevFinishTime;
@Init
public void timeKeeperInit() {
prevInitTime = LocalDateTime.now();
}
public List<Competitor> getCompetitors() {
return competitors;
}
@Command
public void changeFinishTime(@BindingParam("comp") Competitor competitor,
@ContextParam(ContextType.COMPONENT) Component timebox) {
selectedCompetitor = competitor;
Map<String, Object> args = new HashMap<>();
LocalDateTime currentFinishTime = competitor.getFinishTime();
args.put("initTime", (currentFinishTime != null) ? currentFinishTime : prevFinishTime);
Window win = (Window) Executions.createComponents("entertime.zul", timebox.getParent(), args);
// Need to use the parent of timebox in this case
win.setPosition("parent,bottom,right"); // positions the popup relative to timebox parent, not timebox
win.doPopup();
}
@GlobalCommand
@NotifyChange("competitors")
public void finishTime(@BindingParam("finishTime") LocalDateTime finishTime) {
if (selectedCompetitor != null && finishTime != null) {
selectedCompetitor.setFinishTime(finishTime);
prevFinishTime = finishTime;
}
}
}
我目前拥有的代码(即以编程方式创建弹出窗口 - 请参阅 changeFinishTime
方法)显示弹出窗口但不在理想位置。根据 zk popup demo,我可以通过在 zul 文件中的某处生成弹出窗口:
<popup id="timepop">
<include src="entertime.zul" />
</popup>
然后通过以下方式显示:
onFocus='timepop.open(self,@load(vm.popupPosition))'
问题是我无法将参数传递给 entertime.zul
。此外,我无法修改弹出窗口的位置,因为 popupPosition
将在渲染时解析;不是运行时。如果将包含行(从上面)更改为:
,则会出现同样的问题
<include initTime="@load(vm.prevFinishTime)" src="entertime.zul" />
initTime
在渲染时初始化;不是运行时。
任何 thoughts/advice 非常感谢。
我更愿意使用 Executions.createComponents 解决方案。
如果所有windows模态win的位置都一样,我一般直接在window组件中标记位置:
<window viewModel="@id('vmtp') @init('EnterTimeVM')" onBlur="@command('close')" position="parent, bottom, right" width="100px">
而不是将其设置为 VM。
那你有没有尝试移除仓位?在我使用您的代码进行的测试项目中,弹出窗口在 timebox.getParent().
旁边打开
对于您的代码,timebox.getParent 是组件行,因此可能存在行宽问题,例如。
你可以绕过这个问题,在时间盒之前使用父组件,比如 hbox。
<hbox>
<timebox format="HH:mm:ss" value="@bind(each.finishTime)" onFocus="@command('changeFinishTime', comp=each)" />
</hbox>
使父结果更有用。
我希望相对于弹出窗口所附加的行定位弹出窗口。我没有正确阅读 Window's setPosition 的 api。它说 Position the window relative to its parent. That is, the left and top is an offset to his parent's left-top corner.
但我可以使用会话属性操纵位置:
@Command
public void changeFinishTime(@BindingParam("comp") Competitor competitor,
@ContextParam(ContextType.COMPONENT) Component timebox) {
selectedCompetitor = competitor;
// set args map
Window win = (Window) Executions.createComponents("entertime.zul", timebox.getParent(), args);
Sessions.getCurrent().setAttribute("top", "-20px");
win.doPopup();
}
然后改entertime.zul:
<window viewModel="@id('vmtp') @init('EnterTimeVM')" onBlur="@command('close')" position="parent" top="${sessionScope.top}" width="100px">
这个解决方案有点笨拙,如果字体大小改变但它确实达到了我想要的效果,则必须调查问题有多大。
我也可以从 entertime.zul
window 元素中删除所有定位并在 java:
中执行
Window win = (Window) Executions.createComponents("entertime.zul", timebox.getParent(), args);
win.setPosition("parent");
win.setTop("-20px");
win.doPopup();
我的应用程序的一部分是记录比赛的完成时间。因为这很可能是在 phone 或平板电脑上完成的,所以我想实现一个小弹出窗口来轻松修改时间,而不必准确设置焦点并输入它。但是时间开始为 00:00:00 对于每个完成时间都会使过程非常费力,所以我想让它初始化为最后输入的完成时间。如果输入的时间位于网格顶部,我希望弹出窗口直接出现在时间框下方,或者如果输入的时间位于网格底部的时间框上方。下面是我的代码的精简版本,希望有助于解释这个概念。
我的弹出窗口 window:entertime.zul
<window viewModel="@id('vmtp') @init('EnterTimeVM')" onBlur="@command('close')">
<caption>
<toolbarbutton label="Save" onClick="@command('save')"/>
<toolbarbutton label="Cancel" onClick="@command('close')"/>
</caption>
<hlayout>
<vlayout>
<button label="+" onClick="@command('changeHours', amount='1')" />
<intbox value="@load(vmtp.hours)" readonly="true" />
<button label="-" onClick="@command('changeHours', amount='-1')" />
</vlayout>
<vlayout>
<button label="+" onClick="@command('changeMinutes', amount='1')" />
<intbox value="@load(vmtp.minutes)" readonly="true" />
<button label="-" onClick="@command('changeMinutes', amount='-1')" />
</vlayout>
<vlayout>
<button label="+" onClick="@command('changeSeconds', amount='1')" />
<intbox value="@load(vmtp.seconds)" readonly="true" />
<button label="-" onClick="@command('changeSeconds', amount='-1')" />
</vlayout>
</hlayout>
</window>
EnterTimeVM.java
public class EnterTimeVM {
private LocalDateTime ldt;
private Component view;
@Init
public void init(@ExecutionArgParam("initTime") LocalDateTime initTime,
@ContextParam(ContextType.VIEW) Component view) {
ldt = initTime;
this.view = view;
}
public int getHours() {
return ldt.getHour();
}
public int getMinutes() {
return ldt.getMinute();
}
public int getSeconds() {
return ldt.getSecond();
}
@Command
@NotifyChange("hours")
public void changeHours(@BindingParam("amount") int amount) {
ldt = ldt.plusHours(amount);
}
@Command
@NotifyChange({ "hours", "minutes" })
public void changeMinutes(@BindingParam("amount") int amount) {
ldt = ldt.plusMinutes(amount);
}
@Command
@NotifyChange({ "hours", "minutes", "seconds" })
public void changeSeconds(@BindingParam("amount") int amount) {
ldt = ldt.plusSeconds(amount);
}
@Command
public void save() {
Map<String, Object> args = new HashMap<>();
args.put("finishTime", ldt);
BindUtils.postGlobalCommand(null, null, "finishTime", args);
close();
}
@Command
public void close() {
view.detach();
}
}
这是我的主要 zul 和视图模型。
timekeeper.zul(为简洁起见删除了多余的列)
<window viewModel="@id('vmtk') @init('TimeKeeperVM')">
<grid model="@load(vmtk.competitors)">
<columns>
<column label="Name" />
<column label="Finish time" />
</columns>
<template name="model">
<row>
<label value="@load(each.name)" />
<timebox format="HH:mm:ss" value="@bind(each.finishTime)"
onFocus="@command('changeFinishTime', comp=each)" />
</row>
</template>
</grid>
</window>
Competitor.java
public class Competitor {
private String name;
private LocalDateTime finishTime;
// getters and setters
}
TimeKeeperVM.java
public class TimeKeeperVM {
private List<Competitor> competitors;
private Competitor selectedCompetitor;
private LocalDateTime prevFinishTime;
@Init
public void timeKeeperInit() {
prevInitTime = LocalDateTime.now();
}
public List<Competitor> getCompetitors() {
return competitors;
}
@Command
public void changeFinishTime(@BindingParam("comp") Competitor competitor,
@ContextParam(ContextType.COMPONENT) Component timebox) {
selectedCompetitor = competitor;
Map<String, Object> args = new HashMap<>();
LocalDateTime currentFinishTime = competitor.getFinishTime();
args.put("initTime", (currentFinishTime != null) ? currentFinishTime : prevFinishTime);
Window win = (Window) Executions.createComponents("entertime.zul", timebox.getParent(), args);
// Need to use the parent of timebox in this case
win.setPosition("parent,bottom,right"); // positions the popup relative to timebox parent, not timebox
win.doPopup();
}
@GlobalCommand
@NotifyChange("competitors")
public void finishTime(@BindingParam("finishTime") LocalDateTime finishTime) {
if (selectedCompetitor != null && finishTime != null) {
selectedCompetitor.setFinishTime(finishTime);
prevFinishTime = finishTime;
}
}
}
我目前拥有的代码(即以编程方式创建弹出窗口 - 请参阅 changeFinishTime
方法)显示弹出窗口但不在理想位置。根据 zk popup demo,我可以通过在 zul 文件中的某处生成弹出窗口:
<popup id="timepop">
<include src="entertime.zul" />
</popup>
然后通过以下方式显示:
onFocus='timepop.open(self,@load(vm.popupPosition))'
问题是我无法将参数传递给 entertime.zul
。此外,我无法修改弹出窗口的位置,因为 popupPosition
将在渲染时解析;不是运行时。如果将包含行(从上面)更改为:
<include initTime="@load(vm.prevFinishTime)" src="entertime.zul" />
initTime
在渲染时初始化;不是运行时。
任何 thoughts/advice 非常感谢。
我更愿意使用 Executions.createComponents 解决方案。
如果所有windows模态win的位置都一样,我一般直接在window组件中标记位置:
<window viewModel="@id('vmtp') @init('EnterTimeVM')" onBlur="@command('close')" position="parent, bottom, right" width="100px">
而不是将其设置为 VM。
那你有没有尝试移除仓位?在我使用您的代码进行的测试项目中,弹出窗口在 timebox.getParent().
旁边打开对于您的代码,timebox.getParent 是组件行,因此可能存在行宽问题,例如。
你可以绕过这个问题,在时间盒之前使用父组件,比如 hbox。
<hbox>
<timebox format="HH:mm:ss" value="@bind(each.finishTime)" onFocus="@command('changeFinishTime', comp=each)" />
</hbox>
使父结果更有用。
我希望相对于弹出窗口所附加的行定位弹出窗口。我没有正确阅读 Window's setPosition 的 api。它说 Position the window relative to its parent. That is, the left and top is an offset to his parent's left-top corner.
但我可以使用会话属性操纵位置:
@Command
public void changeFinishTime(@BindingParam("comp") Competitor competitor,
@ContextParam(ContextType.COMPONENT) Component timebox) {
selectedCompetitor = competitor;
// set args map
Window win = (Window) Executions.createComponents("entertime.zul", timebox.getParent(), args);
Sessions.getCurrent().setAttribute("top", "-20px");
win.doPopup();
}
然后改entertime.zul:
<window viewModel="@id('vmtp') @init('EnterTimeVM')" onBlur="@command('close')" position="parent" top="${sessionScope.top}" width="100px">
这个解决方案有点笨拙,如果字体大小改变但它确实达到了我想要的效果,则必须调查问题有多大。
我也可以从 entertime.zul
window 元素中删除所有定位并在 java:
Window win = (Window) Executions.createComponents("entertime.zul", timebox.getParent(), args);
win.setPosition("parent");
win.setTop("-20px");
win.doPopup();