Использование JavaFX PopOver для вкладки TabPanes для просмотра ее содержимого - PullRequest
0 голосов
/ 04 июня 2018

Я пытаюсь создать Peek Control для TabPane.Таким образом, если панель уже открыта, Snapshot сохраняется.Когда пользователь наводит курсор на Tab, он показывает PopOver.Это похоже на Windows Aero Peek.

Моя проблема в том, что PopOver скрывается, когда не должно ... потому что он получает событие hide() от Tabs Graphic.

Я создал небольшой исполняемый пример, чтобы продемонстрировать проблему:

import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

import org.controlsfx.control.PopOver;
import org.controlsfx.control.PopOver.ArrowLocation;

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.embed.swing.SwingFXUtils;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.control.Label;
import javafx.scene.control.SingleSelectionModel;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class Main extends Application {
    Peek peek;
    Tab lastPeek;
    boolean show = false;

    public static void main(String[] args) {
        System.out.println("WE HAVE PROBLEMS WITH FOCUS HERE");
        Application.launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        peek = new Peek();
        primaryStage.setTitle("Tabs");
        Group root = new Group();
        Scene scene = new Scene(root, 400, 250, Color.WHITE);

        TabPane tabPane = new TabPane();

        BorderPane borderPane = new BorderPane();

        final PopOver popOver = new PopOver();
        popOver.setArrowLocation(ArrowLocation.TOP_LEFT);
        final ImageView preview = new ImageView();
        preview.setFitHeight(100);
        preview.setSmooth(true);
        preview.setPreserveRatio(true);
        popOver.setContentNode(preview);

        for (int i = 0; i < 5; i++) {
            Tab tab = new Tab();
            HBox hbox = new HBox();
            hbox.getChildren().add(new Label("", new ImageView(new Image(Main.class.getResourceAsStream(i + ".jpg")))));
            hbox.setAlignment(Pos.CENTER);
            tab.setContent(hbox);
            tabPane.getTabs().add(tab);

            final Label decoration = new Label("Tab" + i);
            tab.setGraphic(decoration);
            System.out.println("tab.getGraphic() = " + tab.getGraphic());

            final int index = i;
            tab.getGraphic().setOnMouseEntered(mouseEvent -> {
                boolean show = false;
                if (lastPeek != tab) {
                    // Show PopOver when mouse enters label
                    Image previewImage = peek.get(tab);
                    if (previewImage != null) {
                        show = true;
                    }
                    System.out.println("previewImage = " + previewImage);
                    preview.setImage(previewImage);
                    System.out.println("show() " + "Tab" + index);
                    lastPeek = tab;
                }
                if (!tab.isSelected() && !tab.isDisabled() && show) {
                    popOver.show((Node) mouseEvent.getSource(), -3);
                }
            });

            tab.getGraphic().setOnMouseExited(mouseEvent -> {
                // Hide PopOver when mouse exits label
                // how can we handle this correct??
                 popOver.hide();
                System.out.println("hide() " + "Tab" + index);
            });

        }

        tabPane.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>() {
            @Override
            public void changed(ObservableValue<? extends Tab> ov, Tab oldTab, Tab newTab) {
                Image preview = oldTab.getContent().snapshot(new SnapshotParameters(), null);
                peek.set(oldTab, preview);
            }
        });
        tabPane.selectionModelProperty().addListener(new ChangeListener<SingleSelectionModel<Tab>>() {

            @Override
            public void changed(ObservableValue<? extends SingleSelectionModel<Tab>> ov,
                    SingleSelectionModel<Tab> oldValue, SingleSelectionModel<Tab> newValue) {
            }
        });

        // bind to take available space
        borderPane.prefHeightProperty().bind(scene.heightProperty());
        borderPane.prefWidthProperty().bind(scene.widthProperty());

        borderPane.setCenter(tabPane);
        root.getChildren().add(borderPane);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

}

, и это класс Peek, который объединяет Snapshots

public class Peek {
    ObservableMap<Object, Image> peeks = FXCollections.observableHashMap();

    public void set(Object key, Image preview) {
        peeks.put(key, preview);
    }

    public Image get(Object key) {
        Image preview = peeks.get(key);
        return preview;
    }

}

1 Ответ

0 голосов
/ 04 июня 2018

Это на самом деле из-за всплывающего окна, которое вы показываете.Как только отображается popOver, он получает фокус, и событие MouseExit отправляется на изображение вашей вкладки.
Вы можете наблюдать это, добавив большее смещение к вашему всплывающему окну:

popOver.show((Node) mouseEvent.getSource(), -15);

Или просто введя указатель мыши вверху вкладки, а не снизу (проблема больше не появляется).

Кроме того, поскольку событие кажется недостаточно синхронизированным (при быстром перемещении мыши от вкладки к другой), я советую вам создать один PopOver по вкладке.

public class Main extends Application {

   Peek peek;

   Tab lastPeek;

   HashMap<Label, PopOver> popMap = new HashMap<>();

   boolean show = false;

   public static void main(String[] args) {
      System.out.println("WE HAVE PROBLEMS WITH FOCUS HERE");
      Application.launch(args);
   }

   @Override
   public void start(Stage primaryStage) {
      peek = new Peek();
      primaryStage.setTitle("Tabs");
      Group root = new Group();
      Scene scene = new Scene(root, 400, 250, Color.WHITE);

      TabPane tabPane = new TabPane();

      BorderPane borderPane = new BorderPane();

      for(int i = 0; i < 5; i++) {
         Tab tab = new Tab();
         HBox hbox = new HBox();
         hbox.getChildren()
               .add(new Label("", new ImageView(new Image(Main.class.getResourceAsStream(i + ".jpg")))));
         hbox.setAlignment(Pos.CENTER);
         tab.setContent(hbox);
         tabPane.getTabs().add(tab);

         final Label decoration = new Label("Tab" + i);
         tab.setGraphic(decoration);
         System.out.println("tab.getGraphic() = " + tab.getGraphic());
         final PopOver popOver = new PopOver();
         popOver.setArrowLocation(ArrowLocation.TOP_LEFT);
         final ImageView preview = new ImageView();
         preview.setFitHeight(100);
         preview.setSmooth(true);
         preview.setPreserveRatio(true);
         popOver.setContentNode(preview);

         popMap.put(decoration, popOver);
         final int index = i;
         decoration.setOnMouseEntered(mouseEvent -> {

            PopOver lPop = popMap.get((Label) mouseEvent.getSource());

            boolean show = false;
            if(lastPeek != tab) {
               // Show PopOver when mouse enters label
               Image previewImage = peek.get(tab);
               if(previewImage != null) {
                  show = true;
               }
               System.out.println("previewImage = " + previewImage);
               preview.setImage(previewImage);
               System.out.println("show() " + "Tab" + index);

            }
            if(!tab.isSelected() && !tab.isDisabled() && show) {
               lPop.show((Node) mouseEvent.getSource(), -decoration.getHeight() / 2);
            }
         });

         tab.getGraphic().setOnMouseExited(mouseEvent -> {
            // Hide PopOver when mouse exits label
            // how can we handle this correct??
            PopOver lPop = popMap.get((Label) mouseEvent.getSource());
            if(lPop.isShowing())
               lPop.hide();
            System.out.println("hide() " + "Tab" + index);
         });

      }

      tabPane.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>() {

         @Override
         public void changed(ObservableValue<? extends Tab> ov, Tab oldTab, Tab newTab) {
            Image preview = oldTab.getContent().snapshot(new SnapshotParameters(), null);
            peek.set(oldTab, preview);
         }
      });
      tabPane.selectionModelProperty().addListener(new ChangeListener<SingleSelectionModel<Tab>>() {

         @Override
         public void changed(ObservableValue<? extends SingleSelectionModel<Tab>> ov,
               SingleSelectionModel<Tab> oldValue, SingleSelectionModel<Tab> newValue) {
         }
      });

      // bind to take available space
      borderPane.prefHeightProperty().bind(scene.heightProperty());
      borderPane.prefWidthProperty().bind(scene.widthProperty());

      borderPane.setCenter(tabPane);
      root.getChildren().add(borderPane);
      primaryStage.setScene(scene);
      primaryStage.show();
   }
}
...