从列表中的 select 项创建另一个列表框 ZK
From an select item in the list, create another listbox 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;
}
Class 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);
}
}
}
Class BookViewModel:列表框的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;
}
}
Class 详细信息:所选书籍的详细模型
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 + "]";
}
}
Class 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;
}
}
Class: DetailViewModel:ViewModel 第二个 ListBox
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;
}
}
这是 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>
我尝试在第二个列表框中(开始必须为空),每次在第一个列表框中选择一本书时显示这本书的详细信息。我得到正确的信息。当我选择一本书时,我得到了该书的正确详细信息,但我的第二个列表框没有显示任何内容。我会感谢所有的帮助。 PD:对不起英语
好吧,这段代码要说的比你想象的要多。
切勿对 user/session 变量使用静态。
在您的 VM 中,您有以下代码:
private static Book selectedBook;
假设我 select 第一本书 和你 select 2 秒后 第二本书.
因为它是静态的,所以我也有 Book 2 selected,而我的观点并没有意识到它。
这意味着 GUI 和服务器端不同步 => 从来都不是一件好事。
如果您能够将视图与 selected 项目同步,这意味着您 select book 2 对我来说,我将搜索该号码捉鬼敢死队的成员。
使用 ZK,始终使用 ListModel 接口将集合提供给 GUI。
虽然返回 List<Book>
效果很好,但您需要了解此操作的后果。
List
或 Grid
期望 ListModel
的实现,如果你不给它,每次你通知列表更改时都会创建一个。
虽然这是一个很高兴拥有的功能,但它也删除了列表模型的智能,并且 GUI 呈现会更多。
一个例子总是更清楚:
我们有一个 Collection
的 9 项,我们将向其追加 1。
向List
添加1个Object
并通知它意味着Listbox
渲染的所有内容将被移除,然后重新添加所有内容Listbox
.
这意味着我们将删除和添加 9 行未更改的行。
将 1 Object
添加到 ListModel,即使 没有 通知 ListModel 更改也会导致只有 1 项的操作附加到 Listbox
。这是 ListModel 的智能 => 添加和删除项目将在没有开销的情况下持久保存到 GUI。
因此您的代码应该如下所示:
private Book selectedBook;
private final ListModelList<Book> booksData = new ListModelList<Book>(new BookData().getBooks()); // Armo los libros
为什么不在接口上工作,为什么是最终的?
所以我刚刚告诉你接口 ListModel
然而,我正在将 ListModel
的实现设置为代码,即使我们正在学习针对接口工作。
原因很简单,ListModel
没有添加和删除项目的方法,而实现却有。
因此,我决定在需要这些方法时针对该对象进行操作,而不是强制转换它。
请记住,booksData
的全局 getter 可能如下所示:
public ListModel<Book> getBooksData() {
return booksData;
}
所以这里我们把ListModelList
的实现隐藏到外面
final
的原因是你会强迫自己或其他正在检查代码的人使用 clear() 方法,而不是创建一个新的 ListModelList
。
只是不需要创建它的新实例。
使用 2 个视图模型
你让自己难以使用 2 个虚拟机。
虽然有时这样做是个好主意,但我会帮助您解决问题。
您的第一个问题是 命名 类问题之一。
- Viewmodel 1 => 在 zul 中调用了 vm。
- Viewmodel 2 => 在 zul 中调用了 vm。
你看到了吗?我对着vm哭谁会听?
让我们调用细节的视图模型 detailVM
viewModel="@id('detailVM') @init('detail.DetailViewModel')"
第二个问题是您的详细视图模型对第一个列表框没有任何线索。
我想说的是,您的第二个视图模型应该包含第一个列表框 selected 项的正确信息。
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,现在由您来修改视图模型了。
请记住,我在 detailVM 中设置了 selectedBook,因此现在第一个视图模型中不需要它。
我不会把所有的东西都写给你,否则你也学不会
还有一些小事要说。
你看我将列表框模型更改为 @init
而不是 @bind
。
模型始终是只读的,因此请永远不要使用 @bind
.
@load
是您可以使用的最高注释,只有当您将为 ListModel
创建新实例时才会出现这种情况,几乎不需要 。
标签在您的 GUI 中也不可更新。
再次 @bind
超出了顶部, @load
应该在正常情况下使用(当值可以更改时,最常见的情况下)或 @init
当值永远不会更改时,但是如果您使用@load
我已经很开心了。
希望这可以为您指明正确的方向。
如果您还有其他问题,请在下方评论。
这让我很头疼。我想从第一个列表中选择一本书,然后用该书创建第二个列表以显示该书的详细信息(标题、页数)
代码如下:
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;
}
Class 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);
}
}
}
Class BookViewModel:列表框的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;
}
}
Class 详细信息:所选书籍的详细模型
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 + "]";
}
}
Class 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;
}
}
Class: DetailViewModel:ViewModel 第二个 ListBox
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;
}
}
这是 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>
我尝试在第二个列表框中(开始必须为空),每次在第一个列表框中选择一本书时显示这本书的详细信息。我得到正确的信息。当我选择一本书时,我得到了该书的正确详细信息,但我的第二个列表框没有显示任何内容。我会感谢所有的帮助。 PD:对不起英语
好吧,这段代码要说的比你想象的要多。
切勿对 user/session 变量使用静态。
在您的 VM 中,您有以下代码:
private static Book selectedBook;
假设我 select 第一本书 和你 select 2 秒后 第二本书.
因为它是静态的,所以我也有 Book 2 selected,而我的观点并没有意识到它。
这意味着 GUI 和服务器端不同步 => 从来都不是一件好事。
如果您能够将视图与 selected 项目同步,这意味着您 select book 2 对我来说,我将搜索该号码捉鬼敢死队的成员。
使用 ZK,始终使用 ListModel 接口将集合提供给 GUI。
虽然返回 List<Book>
效果很好,但您需要了解此操作的后果。
List
或 Grid
期望 ListModel
的实现,如果你不给它,每次你通知列表更改时都会创建一个。
虽然这是一个很高兴拥有的功能,但它也删除了列表模型的智能,并且 GUI 呈现会更多。
一个例子总是更清楚:
我们有一个 Collection
的 9 项,我们将向其追加 1。
向
List
添加1个Object
并通知它意味着Listbox
渲染的所有内容将被移除,然后重新添加所有内容Listbox
.
这意味着我们将删除和添加 9 行未更改的行。将 1
Object
添加到 ListModel,即使 没有 通知 ListModel 更改也会导致只有 1 项的操作附加到Listbox
。这是 ListModel 的智能 => 添加和删除项目将在没有开销的情况下持久保存到 GUI。
因此您的代码应该如下所示:
private Book selectedBook;
private final ListModelList<Book> booksData = new ListModelList<Book>(new BookData().getBooks()); // Armo los libros
为什么不在接口上工作,为什么是最终的?
所以我刚刚告诉你接口 ListModel
然而,我正在将 ListModel
的实现设置为代码,即使我们正在学习针对接口工作。
原因很简单,ListModel
没有添加和删除项目的方法,而实现却有。
因此,我决定在需要这些方法时针对该对象进行操作,而不是强制转换它。
请记住,booksData
的全局 getter 可能如下所示:
public ListModel<Book> getBooksData() {
return booksData;
}
所以这里我们把ListModelList
的实现隐藏到外面
final
的原因是你会强迫自己或其他正在检查代码的人使用 clear() 方法,而不是创建一个新的 ListModelList
。
只是不需要创建它的新实例。
使用 2 个视图模型
你让自己难以使用 2 个虚拟机。
虽然有时这样做是个好主意,但我会帮助您解决问题。
您的第一个问题是 命名 类问题之一。
- Viewmodel 1 => 在 zul 中调用了 vm。
- Viewmodel 2 => 在 zul 中调用了 vm。
你看到了吗?我对着vm哭谁会听?
让我们调用细节的视图模型 detailVM
viewModel="@id('detailVM') @init('detail.DetailViewModel')"
第二个问题是您的详细视图模型对第一个列表框没有任何线索。
我想说的是,您的第二个视图模型应该包含第一个列表框 selected 项的正确信息。
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,现在由您来修改视图模型了。
请记住,我在 detailVM 中设置了 selectedBook,因此现在第一个视图模型中不需要它。
我不会把所有的东西都写给你,否则你也学不会
还有一些小事要说。
你看我将列表框模型更改为 @init
而不是 @bind
。
模型始终是只读的,因此请永远不要使用 @bind
.
@load
是您可以使用的最高注释,只有当您将为 ListModel
创建新实例时才会出现这种情况,几乎不需要 。
标签在您的 GUI 中也不可更新。
再次 @bind
超出了顶部, @load
应该在正常情况下使用(当值可以更改时,最常见的情况下)或 @init
当值永远不会更改时,但是如果您使用@load
我已经很开心了。
希望这可以为您指明正确的方向。
如果您还有其他问题,请在下方评论。