2016-07-22 77 views
0

對於我的JavaFX GUI,我必須使用一些拆分窗格。但是會出現一個問題:當用戶單擊拆分窗格上的一個按鈕時,我必須做到這一點,此拆分窗格隱藏了這些側窗格中的一個,並且需要再次點擊才能將此側窗格重置爲可見。在JavaFX上設置OneTouchExpandable按鈕SplitPane

我在這裏發現了另外一個像我這樣的問題:Can we add OneTouchExpansable button on Javafx SplitPane like swing JSplitPane,但是除了「No you can not」之外,其他問題沒有答案。

我希望有人對如何使這成爲可能,或如何做出類似的任何想法。

謝謝大家!

+1

你可以嘗試類似於James_D介紹[這裏]的方法(http://stackoverflow.com/questions/38209981/value-into-slider-thumb-in-javafx)。你應該瞄準'水平抓取器'或'垂直抓取器'(或者兩者都可以)。請參閱[CSS參考](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/doc-files/cssref.html#splitpane) – Itai

+0

嗡..問題是,一個'Divider' (在JavaFx'SplitPane'中分離窗格的東西)不會擴展'Pane'。但我認爲有可能重寫'SplitPane.Divider'和maky我自己的分頻器。 **編輯:** Arf不可能......'SplitPane.Divider'有他所有的方法最後:'( – NatNgs

回答

1

我無法抗拒給這個嘗試。這不是一個好的解決方案,因爲它忽略了NodeOrientation,並且不支持可訪問性(意味着除其他外,沒有鍵盤控制)。另外,擴展按鈕非常小,因此很難點擊。

但至少是這樣。也許有更多時間的人可以進一步改進。

import java.util.Collection; 
import java.util.Objects; 

import javafx.application.Application; 
import javafx.application.Platform; 

import javafx.beans.binding.Bindings; 
import javafx.beans.binding.DoubleBinding; 
import javafx.beans.binding.DoubleExpression; 

import javafx.geometry.Insets; 
import javafx.geometry.Orientation; 
import javafx.geometry.Pos; 

import javafx.scene.Cursor; 
import javafx.scene.Group; 
import javafx.scene.Node; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.control.Label; 
import javafx.scene.control.SplitPane; 
import javafx.scene.effect.ColorAdjust; 
import javafx.scene.layout.BorderPane; 
import javafx.scene.layout.StackPane; 
import javafx.scene.shape.Polygon; 

import javafx.stage.Stage; 

public class OneTouchExpandable 
extends Application { 

    /** 
    * Node properties key whose value is the saved divider position 
    * just before user's one-touch-expand action is executed. 
    */ 
    private static final Object ORIGINAL_POSITION = 
     OneTouchExpandable.class.getName() + ".originalPosition"; 

    /** 
    * Percentage of divider thickness which one-touch button takes up, 
    * as a value from 0.0 to 1.0. 
    */ 
    private static final double ARROW_THICKNESS = 0.60; 

    /** 
    * Delta for comparing divider position (a double) with the min and max 
    * divider values, which in practice do not reach 0.0 or 1.0. 
    */ 
    private static final double END_TOLERANCE = 0.01; 

    /** 
    * Adds one-touch-expand buttons to a SplitPane's first divider. 
    */ 
    public static void addOneTouchExpansion(SplitPane pane) { 

     StackPane divider = (StackPane) pane.lookup(".split-pane-divider"); 
     Objects.requireNonNull(divider, "SplitPane's divider not present!" 
      + " (you probably need to call this method from within" 
      + " Platform.runLater)"); 

     DoubleBinding dividerPosition = Bindings.selectDouble(
      Bindings.valueAt(pane.getDividers(), 0), "position"); 

     Button colorSource = new Button(); 
     ColorAdjust disabledColor = new ColorAdjust(0, 0, 0.5, 0); 

     BorderPane expander = new BorderPane(); 
     if (pane.getOrientation() == Orientation.VERTICAL) { 
      DoubleExpression scale = 
       divider.heightProperty().multiply(ARROW_THICKNESS); 
      DoubleExpression indent = 
       divider.heightProperty().multiply((1 - ARROW_THICKNESS)/2); 

      Polygon upArrow = new Polygon(1, 0, 0, 1, 2, 1); 
      upArrow.setCursor(Cursor.DEFAULT); 
      upArrow.fillProperty().bind(colorSource.textFillProperty()); 
      upArrow.scaleXProperty().bind(scale); 
      upArrow.scaleYProperty().bind(scale); 
      upArrow.disableProperty().bind(
       dividerPosition.isEqualTo(0, END_TOLERANCE)); 
      upArrow.effectProperty().bind(
       Bindings.when(upArrow.disabledProperty()) 
        .then(disabledColor).otherwise((ColorAdjust) null)); 
      upArrow.setOnMouseClicked(e -> setDividerPosition(pane, 0)); 

      Polygon downArrow = new Polygon(1, 1, 0, 0, 2, 0); 
      downArrow.setCursor(Cursor.DEFAULT); 
      downArrow.fillProperty().bind(colorSource.textFillProperty()); 
      downArrow.scaleXProperty().bind(scale); 
      downArrow.scaleYProperty().bind(scale); 
      downArrow.translateXProperty().bind(scale.multiply(2).add(3)); 
      downArrow.disableProperty().bind(
       dividerPosition.isEqualTo(1, END_TOLERANCE)); 
      downArrow.effectProperty().bind(
       Bindings.when(downArrow.disabledProperty()) 
        .then(disabledColor).otherwise((ColorAdjust) null)); 
      downArrow.setOnMouseClicked(e -> setDividerPosition(pane, 1)); 

      Group expandButtonsPane = new Group(upArrow, downArrow); 
      expandButtonsPane.translateYProperty().bind(indent); 

      expander.setLeft(expandButtonsPane); 
     } else { 
      DoubleExpression scale = 
       divider.widthProperty().multiply(ARROW_THICKNESS); 
      DoubleExpression indent = 
       divider.widthProperty().multiply((1 - ARROW_THICKNESS)/2); 

      Polygon leftArrow = new Polygon(0, 1, 1, 0, 1, 2); 
      leftArrow.setCursor(Cursor.DEFAULT); 
      leftArrow.fillProperty().bind(colorSource.textFillProperty()); 
      leftArrow.scaleXProperty().bind(scale); 
      leftArrow.scaleYProperty().bind(scale); 
      leftArrow.disableProperty().bind(
       dividerPosition.isEqualTo(0, END_TOLERANCE)); 
      leftArrow.effectProperty().bind(
       Bindings.when(leftArrow.disabledProperty()) 
        .then(disabledColor).otherwise((ColorAdjust) null)); 
      leftArrow.setOnMouseClicked(e -> setDividerPosition(pane, 0)); 

      Polygon rightArrow = new Polygon(1, 1, 0, 0, 0, 2); 
      rightArrow.setCursor(Cursor.DEFAULT); 
      rightArrow.fillProperty().bind(colorSource.textFillProperty()); 
      rightArrow.scaleXProperty().bind(scale); 
      rightArrow.scaleYProperty().bind(scale); 
      rightArrow.translateYProperty().bind(scale.multiply(2).add(3)); 
      rightArrow.disableProperty().bind(
       dividerPosition.isEqualTo(1, END_TOLERANCE)); 
      rightArrow.effectProperty().bind(
       Bindings.when(rightArrow.disabledProperty()) 
        .then(disabledColor).otherwise((ColorAdjust) null)); 
      rightArrow.setOnMouseClicked(e -> setDividerPosition(pane, 1)); 

      Group expandButtonsPane = new Group(leftArrow, rightArrow); 
      expandButtonsPane.translateXProperty().bind(indent); 

      expander.setTop(expandButtonsPane); 
     } 

     divider.getChildren().add(expander); 
    } 

    /** 
    * Checks whether double values are nearly equal. 
    */ 
    private static boolean isNearly(double value, 
            double target) { 
     return (Math.abs(target - value) < END_TOLERANCE); 
    } 

    /** 
    * Executes a one-touch expansion/contraction. 
    * 
    * @param pane SplitPane to perform expansion on 
    * @param end farthest divider position in direction of expansion, 
    *   either 0 or 1 
    */ 
    private static void setDividerPosition(SplitPane pane, 
              double end) { 
     double oldPosition = pane.getDividers().get(0).getPosition(); 
     double start = 1 - end; 
     if (isNearly(oldPosition, start)) { 
      Object savedPosition = pane.getProperties().get(ORIGINAL_POSITION); 
      if (savedPosition instanceof Number) { 
       pane.setDividerPosition(0, 
        ((Number) savedPosition).doubleValue()); 
      } else { 
       pane.setDividerPosition(0, 0.5); 
      } 
     } else if (!isNearly(oldPosition, end)) { 
      pane.getProperties().put(ORIGINAL_POSITION, oldPosition); 
      pane.setDividerPosition(0, end); 
     } 
    } 

    /** 
    * Displays test window. Invoke application with 'vertical' as first 
    * command-line argument to use a vertical SplitPane. 
    */ 
    @Override 
    public void start(Stage stage) { 
     Node child1 = createChild("Child 1"); 
     Node child2 = createChild("Child 2"); 

     SplitPane pane = new SplitPane(child1, child2); 

     Collection<String> params = getParameters().getUnnamed(); 
     if (params.stream().anyMatch(s -> s.matches("[Vv].*"))) { 
      pane.setOrientation(Orientation.VERTICAL); 
     } 

     Platform.runLater(() -> addOneTouchExpansion(pane)); 

     stage.setTitle("One-Touch Expandable Demo"); 
     stage.setScene(new Scene(pane)); 
     stage.show(); 
    } 

    /** 
    * Creates a SplitPane child for test window. 
    * 
    * @param text text to show in node 
    */ 
    private static Node createChild(String text) { 
     Label label = new Label(text); 
     label.setAlignment(Pos.CENTER); 

     label.setMinWidth(0); 
     label.setMinHeight(0); 
     label.setMaxWidth(10000); 
     label.setMaxHeight(10000); 

     Label sizer = new Label(text); 
     sizer.setVisible(false); 
     sizer.setPadding(new Insets(100)); 

     sizer.setMinWidth(0); 
     sizer.setMinHeight(0); 
     sizer.setMaxWidth(10000); 
     sizer.setMaxHeight(10000); 

     StackPane pane = new StackPane(label, sizer); 

     return pane; 
    } 
} 
+0

哦,我的天啊,它很醜xD但是一個好主意!對於我的項目,我重新制作了一個MySplitPane '使用3個窗格,其中窗格的大小可以通過在MySplitPane的第二個窗格上拖放來改變;但是比你的解決方案更醜陋!(+1!我沒有設置答案現在解決了,我會再等一會兒;如果沒有更好的答案出現,我會接受你的答案作爲答案:P) – NatNgs