Хорошо, это становится немного сложнее со всеми задействованными узлами.Не стесняйтесь давать советы по упрощению, если это возможно.
Я пытаюсь заполнить JavaFX ListView пользовательскими объектами, отформатированными с помощью пользовательских узлов.
У меня есть пользовательский объект с именем 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 для стекирования пары.писемТелефоны и электронные письма помещаются в VBox через узлы ContactCellField (я объясню это чуть ниже.)
Вот fxml для ContactCell:
<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 узлами ContactCellField. Вот как должен выглядеть отдельный ContactCellField.
Вот текстовый файл для ContactCellField:
<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>
Как вы видите, ContactCellField содержит DetailField, который является другим пользовательскимузел, который я создал, я не думаю, что этот узел вообще связан с этой проблемой, поэтому я не буду вдаваться в подробности, но в основном это TextField с кнопкой копирования.
Так что это все FXML, теперь для некоторой Java.
Вот код для ContactListCell, который является расширением ListCell и также содержит определение узла ContactCell:
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);
}
}
}
Я опущу java ContactCellField, если не будет запрошено, потому что я тоже не думаю, что в этом проблема.
Итак, в другом месте контроллера для сцены, в которой живет 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 как ContactListCells, который я хотел бы содержать в формате ContactCell.Затем ячейка контакта должна принимать телефоны и электронные письма от объекта контакта, помещать их информацию в ContactCellFields, а затем помещать эти ContactCellFields (составленные) в соответствующий VBox (vbox_phones / vbox_emails).
После тонны проб и ошибок и расплывчатых сообщений StackOverflow я ПОЧТИ добился желаемого эффекта.В этот момент код не содержит ошибок и заполняет LV правильным количеством объектов Contact, переданных ему, но он визуализируется очень неправильно.
Вот поведение при запуске программы.Он ничего не показывает, пока я не нажму на ячейку, а затем он будет отображаться совершенно неправильно. Метка для имени контакта показывает только подчеркнутые эллипсы, а VBox для телефонов и VBox для электронной почты, кажется, сложены сверхудруг друга, в результате чего куча ContactCellFields складываются друг на друга.
О, я почти забыл упомянуть, когда я впервые запустил все, что показывало, что это были подчеркнутые эллипсы, затем я случайно перешел к определению fxml ListView и изменил fixedCellSize на 100.0, это сделало ячейку выше и открылосложенные vboxes.
Мне не хватает какой-то простой вещи, которая мешает ListView правильно отображать эти узлы?Я сделал что-то действительно глупое и нужно переформатировать, как все это работает?Любая помощь приветствуется.
РЕДАКТИРОВАНИЕ / ОБНОВЛЕНИЕ: я изменил строку в ContactListCell с получения / установки дочерних элементов для ContactCell на setGraphic (contactCell), и теперь загружается следующим образом. Это НАМНОГОближе к конечной цели, но не совсем.Я буду продолжать пытаться что-то делать, но все же буду открыта для советов, которые помогут мне преодолеть финишную черту или сделать вещи лучше / легче развиваться в конечном итоге.