Часть моего приложения записывает время финиша гонки. Поскольку это, скорее всего, будет сделано на телефоне или планшете, я хотел бы реализовать небольшое всплывающее окно, чтобы легко изменять время без необходимости точно устанавливать фокус и вводить его. Однако время начала должно начинаться с 00:00:00 для каждого время окончания сделает процесс очень трудоемким, поэтому я хочу, чтобы он инициализировался до последнего введенного времени окончания. Я хочу, чтобы всплывающее окно отображалось непосредственно под временным ящиком, если вводимые времена находятся в верхней части сетки или над временным ящиком для вводимых времен, которые находятся в нижней части сетки. Ниже урезаны версии моего кода, которые, надеюсь, помогут объяснить концепцию.
Мое всплывающее окно: 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();
}
}
Вот мой основной зул и вид модели.
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 я мог создать всплывающее окно в zul, имея где-то в файле 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
инициализируется во время рендеринга; не время выполнения.
Любые мысли / советы с благодарностью.