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

这是代码:

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;
    }

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);
        }
    }
}

类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;
    }
}

类的详细信息:选择书的详细模型
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 + "]";
    }
}

类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;
    }
}

类:第二个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;
    }
}

这是祖尔文件
<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>

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

最佳答案

好吧,您想像得到的关于此代码的更多要说的内容。

切勿将static用于用户/ session 变量。

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

private static Book selectedBook;

想象一下,我选择 Book 1 ,而您选择2秒后 Book 2
因为它是静态的,所以我也选择了 Book 2 ,而我的 View 不知道。
这意味着GUI和服务器端不同步=>从来都不是一件好事。
如果您可以将 View 与所选项目同步,则意味着您为我选择了 book 2 ,我将搜索Ghost Busters的编号。

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

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

我们有9个项目的Collection,并将其追加1。
  • 将1个Object添加到List中并通知它意味着将删除Listbox呈现的所有内容,然后将所有内容再次添加到Listbox中。
    这意味着我们将删除并添加9条未更改的行。
  • 向ListModel中添加1个Object,甚至在没有通知ListModel更改的情况下,即使是也将导致在Listbox上仅附加一项的操作。这是ListModel的智能=>添加和删除项将持久保存到GUI,而不会产生开销。

  • 因此,您的代码应如下所示:
    private Book selectedBook;
    private final ListModelList<Book> booksData = new ListModelList<Book>(new BookData().getBooks()); // Armo los libros
    

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

    因此,我只是告诉您有关ListModel接口(interface)的信息,但是,即使我们学习如何使用接口(interface),我也将ListModel的实现设置为代码。
    原因很简单,因为ListModel在实现中没有添加和删除项目的方法。
    因此,我决定对这个对象进行处理,而不是在需要这些方法时强制转换它。
    请记住,booksData的全局 getter 如下所示:
    public ListModel<Book> getBooksData() {
        return booksData;
    }
    

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

    使用final的原因是,您将迫使自己或正在检查代码的其他人使用clear()方法,而不是制作新的ListModelList
    只是不需要创建它的新实例。

    使用2个viewmodel的

    您使自己难以使用2个VM。
    但是尽管有时这样做是个好主意,但我会帮助您解决问题。
    您的第一个问题是命名之一。
  • Viewmodel 1 =>在zul中称为vm。
  • Viewmodel 2 =>在zul中称为vm。

  • 你看到了吗?当我哭泣时,谁会听?
    让我们调用详细信息的viewmodel detailVM
    viewModel="@id('detailVM') @init('detail.DetailViewModel')"
    

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

    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>
    

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

    还有一些小事情要说。

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

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

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

    10-06 04:28