好吧,这变得有点复杂,涉及到所有不同的节点。如有可能,请随时提供简化建议。
我试图用自定义对象填充JavaFXListView,并用自定义节点格式化。
我有一个名为Contact的自定义对象,它的定义如下:
public class Contact {
private int id;
private int clientID;
private String firstName;
private String middleInitial;
private String lastName;
private Date birthdate;
private String ssn;
private Address address;
private List<Phone> phones;
private List<Email> emails;
private int listPosition;
private ContactTitle title;
}
下面是我希望ListView中的每个联系人显示为的示例。
此自定义节点(ContactCell)由一个VBox根节点(顶部有一个用于联系人姓名的标签)和一个用于堆叠两部电话的VBox以及一个用于堆叠两封电子邮件的VBox组成。手机和电子邮件通过ContactCellField节点放入VBox(我将在下面进一步解释)
以下是ContactCell的fxml:
<fx:root type="VBox" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Separator prefWidth="200.0" />
<Label fx:id="lbl_printName" underline="true">
<VBox.margin>
<Insets left="10.0" />
</VBox.margin>
</Label>
<VBox fx:id="vbox_phones" />
<VBox fx:id="vbox_emails" />
</children>
</fx:root>
因此,vbox_phones应该以编程方式填充0-2个ConrectCellField节点。以下是单独的ConrectCellField应该是什么样子。
以下是ContactCellField的fxml:
<fx:root type="Pane" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children>
<VBox>
<children>
<Label fx:id="lbl_fieldLabel" text="Mobile" textFill="#616161" underline="true">
<font>
<Font size="8.0" />
</font>
<padding>
<Insets left="3.0" />
</padding>
</Label>
<DetailField fx:id="df_fieldContent" text="(817)-555-5555" />
</children>
</VBox>
</children>
</fx:root>
正如你所看到的ConrectCellField包含一个DetailField,这是我制作的另一个自定义节点,我不认为这个节点与这个问题有关,所以我不会深入讨论,但基本上它是一个带有复制按钮的文本字段。
这就是所有的FXML,现在是一些java。
以下是ConrectListCell的代码,它是ListCell的扩展,也包含ConrectCell节点定义:
public class ContactListCell extends ListCell<Contact> {
private ContactCell contactCell;
public ContactListCell() {
contactCell = new ContactCell();
}
@Override
protected void updateItem(Contact contact, boolean empty) {
super.updateItem(contact, empty);
if (contact != null) {
contactCell.updateContact(contact);
getChildren().setAll(contactCell);
}
}
/**
* the ContactListCell basically just takes the contact it gets
* and visualizes it using the ContactCell node
*/
private class ContactCell extends VBox {
@FXML Label lbl_printName;
@FXML VBox vbox_phones;
@FXML VBox vbox_emails;
public ContactCell() {
super();
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("contactcell.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
fxmlLoader.setClassLoader(getClass().getClassLoader());
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
public void updateContact(Contact contact) {
String printName = String.join(" ", contact.getFirstName(), contact.getLastName());
lbl_printName.setText(printName);
// Takes a list of phone objects and turns them into a list of ContactCellField objects
// Then fills the phones list box with those objects
List<ContactCellField> phones = contact.getPhones().stream().map(p -> new ContactCellField(p.getName(), p.getNumber())).collect(Collectors.toList());
vbox_phones.getChildren().setAll(phones);
// Same thing that phones do but for emails
List<ContactCellField> emails = contact.getEmails().stream().map(e -> new ContactCellField(e.getName(), e.getAddress())).collect(Collectors.toList());
vbox_emails.getChildren().setAll(emails);
}
}
}
除非有人要求,否则我将省略ContactCellField的java,因为我认为这也不是问题所在。
因此,在ListView所在场景的控制器的其他地方,我就是这样填充LV并设置单元工厂的:
public void initContactsLV(List<Contact> contacts) {
// sorts the contacts by their list position and then passes that ordered list through to the list view
contacts.sort(Comparator.comparing(Contact::getListPosition));
ObservableList<Contact> contactList = FXCollections.observableArrayList(contacts);
lv_contacts.setPlaceholder(new Label("No contacts found."));
lv_contacts.setCellFactory(lv -> new ContactListCell());
lv_contacts.setItems(contactList);
}
因此,细胞工厂的目标是将LV的格式设置为接触列表细胞,我想包含接触细胞的格式。然后,联系人单元应该接收来自联系人对象的电话和电子邮件,将其信息放入联系人字段,然后将这些联系人字段(堆叠)放入适当的VBox(vbox_phones/vbox_emails)。
经过大量的反复试验和模糊的StackOverflow帖子,我几乎达到了预期的效果。此时此刻,代码是无错误的,并且用传递给它的正确数量的联系人对象填充LV,但是它的可视化非常错误。
这是我运行程序时的行为。直到我点击单元格,它才显示任何内容,然后它的可视化完全错误。联系人名称的标签只显示一个带下划线的省略号,手机的VBox和电子邮件的VBox似乎堆叠在一起,导致一堆联系人字段堆叠在一起。
哦,我差点忘了提到,当我第一次运行它时,它显示的是带下划线的省略号,然后我随机转到ListView的fxml定义,将fixedCellSize更改为100.0,这使单元格更高,并显示了堆叠的VBox。
我是否缺少一些简单的东西,阻止ListView正确显示这些节点?我是不是做了一些非常愚蠢的事情,需要重新设计这一切的运作方式?谢谢你的帮助。
编辑/更新:我更改了ConrectListCell中的行,从获取/设置子元素到ConrectCell到setGrapic(接触细胞),现在它像这样加载。这离最终目标更近了,但还不完全是。我会继续尝试,但仍然愿意接受建议,让我越过终点线,或者从长远来看让事情变得更好/更容易发展。
更新我放在OP:
编辑/更新:我更改了ConrectListCell中的行,从获取/设置子元素到ConrectCell到setGrapic(接触细胞),现在它像这样加载。这离最终目标更近了,但还不完全是。我会继续尝试,但仍然愿意接受建议,让我越过终点线,或者从长远来看让事情变得更好/更容易发展。
以下是修复方法:
@Override
protected void updateItem(Contact contact, boolean empty) {
super.updateItem(contact, empty);
if (contact != null) {
contactCell.updateContact(contact);
setGraphic(contactCell);
} else {
setGraphic(null);
}
}
完全从ListView中删除固定单元格大小首选项会导致自定义节点的ListView工作。有点恼人,我花时间写了整个问题描述,只是为了自己弄明白,但嘿,有时候就是这样。希望其他人在尝试像我在这里做的那样在ListView中创建更复杂的嵌套节点时可以从中学习。
我试图找出如何使用一个与一个在,但没有运气,我已经查了,我能找到的都是不完整的教程和问题。下面是我的FXML 还有我的模特 和我不完整的 还有我的控制器 请不要告诉我找不到。我现在迷路了,我不知道在我的FXML中更新图像视图和标签的正确方法。任何人来帮助或与一个教程的链接,我可以遵循,我将不胜感激。
我正在尝试为JavaFX创建一个非常简单的自定义。运行应用程序时,
问题内容: 我尝试使用自定义ListCell在ListView中查看自定义对象。为了说明这个问题,我选择了一个例子。同样出于演示目的,我在渲染时直接禁用了ListCell。这些项目是由线程模拟的外部过程添加的。一切看起来都很不错,直到我为禁用的ListCell应用CSS着色为止。现在看来,有些虚幻项与创建它们的ListCell一起被禁用。 我该如何解决? App.java app.css 问题答案
问题的核心是,我不能刷新或更改一个场景的节点的内容(这里是TablesMain)从另一个类(这里是NamePriceCell)。 我正在使用主StackPane(TableMainController扩展StackPane)构建和应用程序,其中包含其他节点,其中一些节点是ListView。在一个特定的ListView(比如“readitemslistview”)中,我创建了一个自定义ListCel
我正在开发一个应用程序,有必要将节点布置在彼此之外(或彼此顶部等)。但是,此布局只是初始布局,用户可以任意移动这些节点。在JavaFX中,如何以正确的方式实现这一点?我将用一个简单的例子来解释我的问题: 假设我有两个矩形,想把矩形2放在矩形1的右边。 在这种情况下,JavaFX还没有确定rect1的宽度,它将为零。直观地说,我会执行一个调用,让JavaFX绘制rect1,从而确定其宽度,然后添加r
问题内容: 单击按钮后,它会更改其位置。 但是当我移动鼠标时,按钮又回到场景的中心,为什么呢? 我有以下代码: 问题答案: 建议的方法 对于您的特定代码段,也许使用Pane而不是StackPane是最好的方法。 为什么您的代码无法满足您的要求 如果要手动设置布局值,请不要使用会自动为您设置布局值的布局窗格(例如StackPane)。如果使用布局窗格,则下次布局窗格执行布局传递时(例如,调整其大小或