Я пытаюсь получить текущие видимые индексы ячеек/строк GridView, заполненные изображениями.
Я нашел способ извлечь идентификатор из слушателя, но когда я начал добавлять текст/метки поверх изображения и помещать его как StackPane
в GridView
вместо Images
, он перестал работать (исключение приведения класса с IndexedCell
).
Вот основной класс:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class MainApp extends Application {
public MyGridView myGridView;
@Override
public void start(final Stage primaryStage) {
myGridView = new MyGridView();
HBox row1 = new HBox(myGridView);
HBox.setHgrow(myGridView, Priority.ALWAYS);
Scene scene = new Scene(row1, 1200, 800, Color.BLACK);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Вот MyGridView
класс:
import javafx.embed.swing.SwingFXUtils;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.IndexedCell;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
import org.controlsfx.control.GridCell;
import org.controlsfx.control.GridView;
import org.controlsfx.control.cell.ImageGridCell;
import java.awt.*;
import java.awt.image.BufferedImage;
public class MyGridView extends GridView {
public static final int GRID_CELL_WIDTH = 512;
public static final int GRID_CELL_HEIGHT = 360;
public static final int GRID_CELL_SPACING_HORIZONTAL = 5;
public static final int GRID_CELL_SPACING_VERTICAL = 5;
public MyGridView() {
setCellWidth(GRID_CELL_WIDTH);
setCellHeight(GRID_CELL_HEIGHT);
setHorizontalCellSpacing(GRID_CELL_SPACING_HORIZONTAL);
setVerticalCellSpacing(GRID_CELL_SPACING_VERTICAL);
addEventHandler(MouseEvent.MOUSE_CLICKED, e -> {
Node clickedNode = e.getPickResult().getIntersectedNode();
IndexedCell index = ((IndexedCell) clickedNode);
int clickedItemId = index.getIndex();
System.out.println("Clicked id = " + clickedItemId);
});
addEventFilter(ScrollEvent.ANY, e -> {
Node clickedNode = e.getPickResult().getIntersectedNode();
System.out.println(clickedNode.getClass());
IndexedCell index = ((IndexedCell) clickedNode);
int clickedItemId = index.getIndex();
System.out.println("Scrolled id = " + clickedItemId);
});
//scroll/click cells is working with this, comment it and uncomment next one
setCellFactoryWorking();
// setCellFactoryNotWorking();
addImagesToGrid(this);
}
private void setCellFactoryWorking() {
setCellFactory(gv -> new GridCell<Image>() {
private final ImageView imageView = new ImageView();
{
imageView.setFitHeight(GRID_CELL_HEIGHT);
imageView.setPreserveRatio(true);
}
@Override
protected void updateItem(Image image, boolean empty) {
super.updateItem(image, empty);
imageView.setImage(image);
setGraphic(imageView);
}
});
}
private void setCellFactoryNotWorking() {
setCellFactory(gv -> new GridCell<Image>() {
private final ImageView imageView = new ImageView();
{
imageView.setFitHeight(GRID_CELL_HEIGHT);
imageView.setPreserveRatio(true);
}
@Override
protected void updateItem(Image image, boolean empty) {
super.updateItem(image, empty);
imageView.setImage(image);
Text text = new Text(" Lorem Ipsum");
text.setFill(javafx.scene.paint.Color.rgb(255, 255, 255));
StackPane pane = new StackPane();
pane.getChildren().add(imageView);
pane.getChildren().add(text);
pane.setAlignment(Pos.TOP_LEFT);
setGraphic(pane);
}
});
}
private void addImagesToGrid(GridView<Image> gridView) {
for (int i = 1; i < 200; i++) {
final Image image = createFakeImage(i, GRID_CELL_WIDTH, GRID_CELL_HEIGHT);
gridView.getItems().add(image);
}
}
private static Image createFakeImage(int imageIndex, int width, int height) {
BufferedImage image = new BufferedImage(width, width, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
for (int i = 1; i < width; i++) {
g.setColor(new Color(i * imageIndex % 256, i * 2 * (imageIndex + 40) % 256, i * 3 * (imageIndex + 60) % 256));
double proportion = width / height;
g.drawRect(i, i, width - i * 2, (int) ((width - i * 2) * proportion));
}
return SwingFXUtils.toFXImage(image, null);
}
}
Если вы переключите функцию setCellFactoryWorking()
на setCellFactoryNotWorking()
, вы увидите, что ссылочный класс, на который наведена мышь, изменился, и больше не существует IndexedCell
с идентификаторами. На самом деле это плохой метод обнаружения реальных видимых элементов GridView
. Есть ли что-нибудь более общее, что не зависит от типов классов элементов ячейки и просто может сказать:
видимые идентификаторы строк
видимые идентификаторы ячеек
если щелкнуть ячейку мышью, то это тоже идентификатор
также было бы неплохо узнать идентификатор ячейки, просто наведя на нее курсор мыши
Я не знаком с controlfx , но такие элементы управления часто виртуализируются в том смысле, что небольшое количество ячеек повторно используется в легковесном шаблоне ; индексы могут иметь отношение только к рендерингу. Альтернативно, вы можете пересмотреть примеры, приведенные ранее.
Почему вы регистрируете обработчики событий в самом представлении сетки? Почему бы просто не зарегистрировать обработчики событий в ячейках? Затем вы можете легко получить данные, отображаемые в ячейке.
Я пытался сделать одну простую функцию прокрутки вместо трех (одну для ячеек, другую между ячейками и третью — полосу прокрутки), чтобы упростить код и избежать каскадного воссоздания множества прослушивателей для каждой ячейки при событиях прокрутки. Также в моих ячейках будет несколько разных объектов, таких как текст и символы — и это еще один слушатель? Этот предпочитает более общие решения.
Во время поиска я не нашел ничего, что указывало бы на то, что вы можете получить идентификатор строки или идентификатор столбца. Как вы знаете, вы можете получить индекс. Я не понимаю, почему у вас возникли ошибки при добавлении Labels
и Images
\ImageViews
к StackPane
. Вот пример, который выдает идентификатор и индекс ячейки при входе, выходе или щелчке. У вас есть модель, представляющая одну ячейку? В этом примере используется модель с изображением и строкой для представления ячейки.
Основной
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.paint.Color;
import org.controlsfx.control.GridCell;
import org.controlsfx.control.GridView;
public class App extends Application {
public static void main(String[] args) {
launch(args);
}
public static final int GRID_CELL_WIDTH = 50;
public static final int GRID_CELL_HEIGHT = 50;
public static final int GRID_CELL_SPACING_HORIZONTAL = 5;
public static final int GRID_CELL_SPACING_VERTICAL = 5;
List<Color> defaultColors = getAllDefaultColors();
@Override
public void start(Stage primaryStage) {
ObservableList<ImageModel> modelList = FXCollections.observableArrayList();
for(int i = 1; i <= 1000; i++)
{
modelList.add(new ImageModel(i, createFakeImage(GRID_CELL_WIDTH, GRID_CELL_HEIGHT)));
}
GridView<ImageModel> gridView = new GridView();
gridView.setCellWidth(GRID_CELL_WIDTH);
gridView.setCellHeight(GRID_CELL_HEIGHT);
gridView.setHorizontalCellSpacing(GRID_CELL_SPACING_HORIZONTAL);
gridView.setVerticalCellSpacing(GRID_CELL_SPACING_VERTICAL);
gridView.setItems(modelList);
gridView.setCellFactory((GridView<ImageModel> param) -> {
GridCell<ImageModel> cell = new GridCell<ImageModel>() {
ImageView imageView = new ImageView();
Label label = new Label();
StackPane spRoot = new StackPane(imageView, label);
@Override
protected void updateItem(ImageModel item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
label.setText(Integer.toString(item.getId()));
imageView.setImage(item.getImage());
setOnMouseClicked((mouseEvent) -> {
System.out.println("Clicked: index-" + getIndex() + "\tID-" + item.getId());
mouseEvent.consume();
});
setOnMouseEntered((mouseEvent) -> {
System.out.println("Entered: index-" + getIndex() + "\tID-" + item.getId());
mouseEvent.consume();
});
setOnMouseExited((mouseEvent) -> {
System.out.println("Exited: index-" + getIndex() + "\tID-" + item.getId());
mouseEvent.consume();
});
setGraphic(spRoot);
} else {
setText("");
setGraphic(null);
}
}
};
return cell;
});
StackPane root = new StackPane(gridView);
Scene scene = new Scene(root, 1080, 720);
primaryStage.setScene(scene);
primaryStage.setTitle("JavaFX App");
primaryStage.show();
}
private Image createFakeImage(int width, int height) {
Color currentColor = defaultColors.get(ThreadLocalRandom.current().nextInt(defaultColors.size()));
WritableImage writableImage = new WritableImage(width, height);
PixelWriter pixelWriter = writableImage.getPixelWriter();
for(int x = 0; x < width; x++)
{
for(int y = 0; y < height; y++)
{
pixelWriter.setColor(x, y, currentColor);
}
}
return writableImage;
}
private List<Color> getAllDefaultColors(){
List<Color> colors = new ArrayList<>();
try
{
Class clazz = Class.forName("javafx.scene.paint.Color");
if (clazz != null) {
Field[] field = clazz.getFields();
for (Field f : field) {
Object obj = f.get(null);
if (obj instanceof Color){
colors.add((Color) obj);
}
}
}
} catch (ClassNotFoundException | IllegalArgumentException | IllegalAccessException ex) {
System.out.println(ex.toString());
}
return colors;
}
}
Модель изображения
import javafx.scene.image.Image;
/**
*
* @author sedj601
*/
public class ImageModel {
private int id;
private Image image;
public ImageModel(int id, Image image) {
this.id = id;
this.image = image;
}
public Image getImage() {
return image;
}
public void setImage(Image image) {
this.image = image;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
Выход
Я не опубликовал выходной GIF-файл, потому что StackOverflow уменьшил принятый размер изображения до 50 мегапикселей.
Это хорошо, решает многие вещи, которые мне не хватает. Я не знал, что вы можете получить идентификатор ячейки из события с помощью getIndex. На самом деле я использую BorderPane в своих ячейках, чтобы добавить текст и графику сверху и снизу, а изображение становится фоном. Также я нашел способ получить первые/последние строки без событий, я делаю это с помощью этого кода: VirtualFlow<?> flow = (VirtualFlow<?>) ((GridViewSkin<?>)gridView.getSkin()).getChildren ().получить(0); flow.getFirstVisibleCell().getIndex(); //возвращает первый видимый GridRow, то же самое для последнего видимого.
Есть обходной путь для сканирования родителей, но я думаю, что у него есть более элегантное решение?