Как отобразить всплывающее окно в шаблоне и передать ему аргументы - PullRequest
0 голосов
/ 10 мая 2018

Часть моего приложения записывает время финиша гонки. Поскольку это, скорее всего, будет сделано на телефоне или планшете, я хотел бы реализовать небольшое всплывающее окно, чтобы легко изменять время без необходимости точно устанавливать фокус и вводить его. Однако время начала должно начинаться с 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 инициализируется во время рендеринга; не время выполнения.

Любые мысли / советы с благодарностью.

Ответы [ 2 ]

0 голосов
/ 13 мая 2018

Я надеялся разместить всплывающее окно относительно строки, к которой оно прикреплено. Я не прочитал API setPosition окна должным образом. Там написано 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 и сделать это в java:

Window win = (Window) Executions.createComponents("entertime.zul", timebox.getParent(), args);
win.setPosition("parent");
win.setTop("-20px");
win.doPopup();
0 голосов
/ 11 мая 2018

Я бы предпочел использовать решение Executions.createComponents.

Если позиция модального выигрыша одинакова для всех окон, я обычно помечаю непосредственно позицию в компоненте окна:

<window viewModel="@id('vmtp') @init('EnterTimeVM')" onBlur="@command('close')" position="parent, bottom, right" width="100px">

вместо того, чтобы установить его VM.

Тогда вы пытались удалить позицию?В моем тестовом проекте с вашим кодом всплывающее окно открывается рядом с timebox.getParent ().

С вашим кодом timebox.getParent является компонентом Row, поэтому, возможно, могут возникнуть проблемы с шириной строки, например.

Вы можете обойти проблему, используя родительский компонент перед временным ящиком, например hbox.

<hbox>
    <timebox format="HH:mm:ss" value="@bind(each.finishTime)" onFocus="@command('changeFinishTime', comp=each)" />
</hbox>

, чтобы родительский результат стал более удобным.

enter image description here

...