在JavaFX上设置OneTouchExpandable按钮SplitPane
对于我的JavaFX GUI,我必须使用一些拆分窗格。但是会出现一个问题:当用户单击拆分窗格上的一个按钮时,我必须做到这一点,此拆分窗格隐藏了这些侧窗格中的一个,并且需要再次点击才能将此侧窗格重置为可见。在JavaFX上设置OneTouchExpandable按钮SplitPane
我在这里发现了另外一个像我这样的问题:Can we add OneTouchExpansable button on Javafx SplitPane like swing JSplitPane,但是除了“No you can not”之外,其他问题没有答案。
我希望有人对如何使这成为可能,或如何做出类似的任何想法。
谢谢大家!
我无法抗拒给这个尝试。这不是一个好的解决方案,因为它忽略了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;
}
}
哦,我的天啊,它很丑xD但是一个好主意!对于我的项目,我重新制作了一个MySplitPane '使用3个窗格,其中窗格的大小可以通过在MySplitPane的第二个窗格上拖放来改变;但是比你的解决方案更丑陋!(+1!我没有设置答案现在解决了,我会再等一会儿;如果没有更好的答案出现,我会接受你的答案作为答案:P) – NatNgs
你可以尝试类似于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
嗡..问题是,一个'Divider' (在JavaFx'SplitPane'中分离窗格的东西)不会扩展'Pane'。但我认为有可能重写'SplitPane.Divider'和maky我自己的分频器。 **编辑:** Arf不可能......'SplitPane.Divider'有他所有的方法最后:'( – NatNgs