Есть много вариантов для этого;но, вероятно, лучше всего использовать ListView
, как предлагают комментарии.
Пример приложения ниже продемонстрирует один из способов сделать это.Однако я не сделал никакой работы по стилю ListView
.Главным образом потому, что я сам не очень хорошо разбираюсь в CSS (я приветствую правки и предложения), а также потому, что это выходит за рамки этого довольно расплывчатого вопроса.
Объединение ListView
с пользовательским CellFactory
вы можете создать макет для каждой "полки" в вашей библиотеке;ListView
будет отображать каждую строку с использованием этого макета.
В приведенном ниже коде имеются дополнительные комментарии.
Пример библиотеки MCVE:
LibraryExample.java:
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.Separator;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;
import java.util.List;
public class LibraryExample extends Application {
// Our list of shelves that will be displayed in the ListView
private final ObservableList<Shelf> shelves = FXCollections.observableArrayList();
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
// Simple interface
VBox root = new VBox(5);
root.setPadding(new Insets(10));
root.setAlignment(Pos.CENTER);
// Build a list of 100 sample books. This list could come from a database or other outside source, of course
List<Book> books = FXCollections.observableArrayList();
for (int i = 0; i < 100; i++) {
books.add(new Book("Book #" + i, new ImageView("sample/generic-cover.png")));
}
// We will now create our shelves for the books. We will limit the number of books to 6 per shelf. This uses
// the subList method of our List to grab every 6 books until we run out.
int index = 0;
while (index < books.size()) {
// Make sure there are at least 6 books remaining, otherwise, we need to get the subList up to the size of
// the original list.
final int numToAdd = (index + 6 <= books.size() ? index + 6 : books.size());
shelves.addAll(new Shelf(books.subList(index, numToAdd)));
index += 6;
}
// Now, let's create our ListView that will hold our shelves.
ListView<Shelf> listView = new ListView<>();
VBox.setVgrow(listView, Priority.ALWAYS);
// Now for the magic. We will override the CellFactory for the ListView so we can provide our own layout
// for each row
listView.setCellFactory(new Callback<ListView<Shelf>, ListCell<Shelf>>() {
@Override
public ListCell<Shelf> call(ListView<Shelf> param) {
return new ShelfListCell();
}
});
listView.setItems(shelves);
root.getChildren().add(listView);
// Show the Stage
primaryStage.setWidth(700);
primaryStage.setHeight(600);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
class ShelfListCell extends ListCell<Shelf> {
@Override
protected void updateItem(Shelf shelf, boolean empty) {
super.updateItem(shelf, empty);
if (shelf == null || empty) {
setGraphic(null);
} else {
// Here, we will build our layout for each shelf
VBox root = new VBox(5);
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(5));
HBox hBox = new HBox(20);
hBox.setAlignment(Pos.CENTER);
hBox.setPadding(new Insets(5));
// Add image for each each book on this shelf to the layout
for (Book book : shelf.getBooks()) {
// Get the image of the book and add a simple click listener
ImageView cover = book.getCoverImage();
cover.setPreserveRatio(true);
cover.setFitHeight(100);
cover.setOnMouseClicked(event -> System.out.println("Clicked " + book.getTitle()));
hBox.getChildren().add(book.getCoverImage());
}
root.getChildren().addAll(hBox, new Separator(Orientation.HORIZONTAL));
// Set the cell to display our layout
setGraphic(root);
}
}
}
Book.java:
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.image.ImageView;
public class Book {
private final StringProperty title = new SimpleStringProperty();
private final ObjectProperty<ImageView> coverImage = new SimpleObjectProperty<>();
public Book(String title, ImageView coverImage) {
this.title.set(title);
this.coverImage.set(coverImage);
}
public String getTitle() {
return title.get();
}
public StringProperty titleProperty() {
return title;
}
public void setTitle(String title) {
this.title.set(title);
}
public ImageView getCoverImage() {
return coverImage.get();
}
public ObjectProperty<ImageView> coverImageProperty() {
return coverImage;
}
public void setCoverImage(ImageView coverImage) {
this.coverImage.set(coverImage);
}
}
Shelf.java:
import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import java.util.List;
public class Shelf {
// Set max number of books per shelf
private final static int MAX_BOOKS = 6;
// Our observable list of books
private final ListProperty<Book> books = new SimpleListProperty<>(FXCollections.observableArrayList());
public Shelf(List<Book> books) {
this.books.addAll(books);
}
public void addBooks(Book... books) {
this.books.addAll(books);
}
public static int getMaxBooks() {
return MAX_BOOKS;
}
public ObservableList<Book> getBooks() {
return books.get();
}
public ListProperty<Book> booksProperty() {
return books;
}
public void setBooks(ObservableList<Book> books) {
this.books.set(books);
}
}
Результат: