从列表中的一个选择项,创建另一个列表框ZK

Osc*_*ayo 2 listbox mvvm zk

我为此感到头疼。我想从第一个列表中选择一本书,并与该书一起创建第二个列表,以显示该书的详细信息(书名,页数)

这是代码:

public class Book {

    private int numBook;
    private String nameBook;
    private String author;

    public Book(int numBook, String nameBook, String author) {
        super();
        this.numBook = numBook;
        this.nameBook = nameBook;
        this.author = author;
    }
    public int getNumBook() {
        return numBook;
    }
    public void setNumBook(int numBook) {
        this.numBook = numBook;
    }
    public String getNameBook() {
        return nameBook;
    }
    public void setNameBook(String nameBook) {
        this.nameBook = nameBook;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
Run Code Online (Sandbox Code Playgroud)

BookData类:将信息加载到数组中

public class BookData {
    private List<Book> books = new ArrayList<Book>();

    public BookData() {
        loadBooks();
    }
    public List<Book> getBooks() {
        return books;
    }
    public void setBooks(List<Book> books) {
        this.books = books;
    }
    public void loadBooks() {
        Book b;
        for(int i = 0; i<4;i++){
            b = new Book(i+1, "Libro "+i+1, "Author "+i+1);
            books.add(b);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

类BookViewModel:Listbox的ViewModel

public class BookViewModel {
    private static Book selectedBook;
    private List<Book> booksData = new ArrayList<Book>(new BookData().getBooks()); // Armo los libros

    public List<Book> getBooksData() {
        return booksData;
    }
    public void setBooksData(List<Book> booksData) {
        this.booksData = booksData;
    }
    //Getters and Setter the SelectedCar
    @NotifyChange("selectedBook")
    public Book getSelectedBook() {
        if(selectedBook!=null) {
            //setSelectedBook(selectedBook);
            new DetailData(selectedBook);
            //new ArrayList<>(new DetailData().getDetailsFilterByBook());
            //Then here pass the Book Selected
        }
        return selectedBook;
    }
    public void setSelectedBook(Book selectedBook) {
        this.selectedBook = selectedBook;
    }
}
Run Code Online (Sandbox Code Playgroud)

类的详细信息:选择书的详细模型

public class Detail {
    private int idBook;
    private String title;
    private int numPages;

    public Detail(int idBook, String title, int numPages) {
        this.idBook = idBook;
        this.title = title;
        this.numPages = numPages;
    }
    public int getIdBook() {
        return idBook;
    }
    public void setIdBook(int idBook) {
        this.idBook = idBook;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public int getNumPages() {
        return numPages;
    }
    public void setNumPages(int numPages) {
        this.numPages = numPages;
    }

    @Override
    public String toString() {
        return "Detail [idBook=" + idBook + ", title=" + title + ", numPages=" + numPages + "]";
    }
}
Run Code Online (Sandbox Code Playgroud)

类DetailData:将数据加载到数组中

//Clase que se ecarga de manejar la data
public class DetailData {
    private List<Detail> details = loadAllDetails();
    private List<Detail> detailsFilterByBook;
    private static Book bookSelected;
    /*public DetailData(){
        //Previously all the data is loaded
        System.out.println(bookSelected);
        detailsFilterByBook = new ArrayList<>();
        filterDetailsByBook();
    }*/
    public void setBookSelected(Book bookSelected){
        this.bookSelected = bookSelected;
    }
    public DetailData(){
        this(bookSelected);
    }
    public DetailData(Book b){
        bookSelected = b;
        System.out.println(bookSelected);
        detailsFilterByBook = new ArrayList<>();
        filterDetailsByBook();      
    }
    public List<Detail> loadAllDetails(){
        List tmp = new ArrayList<Detail>();
        //Libro 1
        Detail d1b1 = new Detail(1, "Preview", 15);
        Detail d2b1 = new Detail(1, "Inicio", 10);
        Detail d3b1 = new Detail(1, "Zk Bind", 50);
        //Libro 2
        Detail d1b2 = new Detail(2, "Introduccion", 15);
        Detail d2b2 = new Detail(2, "JAVA", 100);
        Detail d3b2 = new Detail(2, "CSS", 25);
        //Libro 3
        Detail d1b3 = new Detail(3, "HTML", 35);
        Detail d2b3 = new Detail(3, "Javascript", 40);
        Detail d3b3 = new Detail(3, "Ajax", 25);
        //Libro 4
        Detail d1b4 = new Detail(4, "Android", 100);
        Detail d2b4 = new Detail(4, "IOS", 100);
        tmp.add(d1b1);
        tmp.add(d2b1);
        tmp.add(d3b1);
        tmp.add(d1b2);
        tmp.add(d2b2);
        tmp.add(d3b2);  
        tmp.add(d1b3);
        tmp.add(d2b3);
        tmp.add(d3b3);
        tmp.add(d1b4);
        tmp.add(d2b4);
        return tmp;
    }
    private void filterDetailsByBook() {
        for(Detail d:details){
            if(d.getIdBook() == bookSelected.getNumBook())
                detailsFilterByBook.add(d);
        }
        print();
    }
    public void print(){
        System.out.println("Imprimiendo detalles del libro escogido");
        for(Detail d: detailsFilterByBook){
            System.out.println(d);
        }
    }
    public List<Detail> getDetails() {
        return details;
    }
    public void setDetails(List<Detail> details) {
        this.details = details;
    }
    public List<Detail> getDetailsFilterByBook() {
        return detailsFilterByBook;
    }
    public void setDetailsFilterByBook(List<Detail> detailsFilterByBook) {
        this.detailsFilterByBook = detailsFilterByBook;
    }
}
Run Code Online (Sandbox Code Playgroud)

类:第二个ListBox的DetailViewModel:ViewModel

public class DetailViewModel {
    private List<Detail> detailsData = new ArrayList<>();
    @NotifyChange("detailsData")
    public void refreshList(){
        System.out.println("REFRESH");
        detailsData = new ArrayList<>(new DetailData().getDetailsFilterByBook());
    }
    public List<Detail> getDetailsData() {
        return detailsData;
    }
    @NotifyChange("detailsData")
    public void setDetailsData(List<Detail> detailsData) {
        this.detailsData = detailsData;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是zul文件

<window title="" border="none" height="100%" apply="org.zkoss.bind.BindComposer" viewmodel="@id('vm') @init('book.BookViewModel')"> 
    <listbox model="@bind(vm.booksData)" selecteditem="@bind(vm.selectedBook)" emptymessage="No car found in the result"> 
        <listhead> 
            <listheader label="Num Libro"/> 
            <listheader label="Libro"/> 
            <listheader label="Autor"/> 
        </listhead> 
        <template name="model" var="book"> 
            <listitem> 
                <listcell label="@bind(book.numBook)"/> 
                <listcell label="@bind(book.nameBook)"/> 
                <listcell label="@bind(book.author)"/> 
            </listitem> 
        </template> 
    </listbox>
    <separator height="100px"/>
    <window title="" border="none" height="100%" apply="org.zkoss.bind.BindComposer"
        viewModel="@id('vm') @init('detail.DetailViewModel')">
        <listbox model="@bind(vm.detailsData)" emptyMessage="No existen datos que presentar">
            <listhead>
                <listheader label="Num Capitulos"/>
                <listheader label="Titulo del Cap"/>
            </listhead> 
            <template name="model" var="detail">
                <listitem>
                    <listcell label="@bind(detail.idBook)"/>
                    <listcell label="@bind(detail.title)"/>
                    <listcell label="@bind(detail.numPages)"/>
                </listitem>
            </template>             
        </listbox>
    </window>
</window>
Run Code Online (Sandbox Code Playgroud)

我尝试在第二个列表框中(开始时必须为空),每次在第一个列表框中选择一本书时都显示该书的详细信息。我得到正确的信息。当选择一本书时,我会得到那本书的正确详细信息,但是我的第二个列表框什么也没显示。我将感谢所有帮助。PD:对不起英语

chi*_*rld 5

好吧,您想像中的这段代码还有更多要说的要点。

切勿将static用于用户/会话变量。

在您的VM中,您具有以下代码:

private static Book selectedBook;
Run Code Online (Sandbox Code Playgroud)

想象一下,我选择书1,而您选择2秒后再选择书2
因为它是静态的,所以我也选择了Book 2,而我的视图没有意识到。
这意味着GUI和服务器端不同步=>从来都不是一件好事。
如果您可以将视图与所选项目同步,则意味着您为我选择了第二本书,而我将搜索“幽灵克星”的编号。

对于ZK,始终使用ListModel接口将集合提供给GUI。

虽然返回List<Book>效果很好,但是您需要了解此操作的后果。
一个ListGrid预期的实现ListModel,如果你不给它,会有一个创建每次通知更改名单的时间。
虽然这是一个很好的功能,但它也消除了列表模型的智能性,并且GUI渲染将更多。
一个例子总是更加清楚:

我们有Collection9个项目,将附加1个。

  • 添加1 ObjectList并通知它意味着所有呈现的内容Listbox将被删除,然后重新添加所有内容的Listbox
    这意味着我们将删除并添加9条未更改的行。

  • Object即使通知ListModel更改,将1添加到ListModel 也会导致仅在其中附加1项的操作Listbox。这是ListModel的智能=>添加和删除项将持久保存到GUI,而不会产生开销。

因此,您的代码应如下所示:

private Book selectedBook;
private final ListModelList<Book> booksData = new ListModelList<Book>(new BookData().getBooks()); // Armo los libros
Run Code Online (Sandbox Code Playgroud)

为什么不使用该界面,为什么最终使用?

因此,我只是向您介绍了该接口ListModel,但是ListModel,即使我们学习如何使用接口,也要设置as代码的实现。
原因很简单,ListModel在实现中没有附加和删除项目的方法。
因此,我决定对这个对象进行处理,而不是在需要这些方法时强制转换它。
请记住,全局获取器booksData可以如下所示:

public ListModel<Book> getBooksData() {
    return booksData;
}
Run Code Online (Sandbox Code Playgroud)

因此,这里我们将的实现隐藏ListModelList在外面。

这样做的原因final是,您将迫使自己或正在执行代码的其他人使用clear()方法来代替new ListModelList
只是不需要创建它的新实例。

使用2个viewmodel的

您使自己难以使用2个VM。
但是尽管有时这样做是个好主意,但我会帮助您解决问题。
您的第一个问题是命名问题。

  • Viewmodel 1 =>在zul中称为vm。
  • Viewmodel 2 =>在zul中称为vm。

你看到了吗?当我哭泣时,谁会听?
让我们称之为细节的视图模型detailVM

viewModel="@id('detailVM') @init('detail.DetailViewModel')"
Run Code Online (Sandbox Code Playgroud)

第二个问题是,详细视图模型没有第一个列表框的任何线索。
我想说的是,您的第二个视图模型应该保存第一个列表框中所选项目的正确信息。

Zul代码应如下所示:

<window title="" border="none" height="100%" apply="org.zkoss.bind.BindComposer" viewmodel="@id('vm') @init('book.BookViewModel')">
    <div apply="org.zkoss.bind.BindComposer"
        viewModel="@id('detailVM') @init('detail.DetailViewModel')">
        <listbox model="@init(vm.booksData)" selecteditem="@bind(detailVM.selectedBook)" emptymessage="No book found in the result"> 
            <listhead> 
                <listheader label="Num Libro"/> 
                <listheader label="Libro"/> 
                <listheader label="Autor"/> 
            </listhead> 
            <template name="model" var="book"> 
                <listitem> 
                    <listcell label="@load(book.numBook)"/> 
                    <listcell label="@load(book.nameBook)"/> 
                    <listcell label="@load(book.author)"/> 
                </listitem> 
            </template> 
        </listbox>
    <separator height="100px"/>

        <listbox model="@init(detailVM.detailsData)" emptyMessage="No existen datos que presentar">
            <listhead>
                <listheader label="Num Capitulos"/>
                <listheader label="Titulo del Cap"/>
            </listhead> 
            <template name="model" var="detail">
                <listitem>
                    <listcell label="@load(detail.idBook)"/>
                    <listcell label="@load(detail.title)"/>
                    <listcell label="@load(detail.numPages)"/>
                </listitem>
            </template>             
        </listbox>
    </div>
</window>
Run Code Online (Sandbox Code Playgroud)

因此,我为您设置了正确的zul,现在由您来修改视图模型。
请记住,我在detailVM中设置了selectedBook,所以现在在第一个viewmodel中不需要它。
我不会为您编写所有内容,否则您将不会从中学习。

还有一些小事情要说。

您会看到我将列表框模型更改为@init而不是@bind
模型始终是只读的,因此请永远不要使用@bind
@load是您可以使用的最高注释,仅当您将为创建新实例时才需要这种情况ListModel

标签也不能在GUI中更新。
再次强调@bind@load应该在正常情况下使用(当值可以更改时,通常是这样),或者@init值永远不会更改时使用,但是如果您使用,@load我会很高兴的。

希望这可以为您指明正确的方向。
如果您还有其他问题,请在下面评论。