- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
普通的 SplitMenuButton 看起来像这样: Standard SplitMenuButton
我想更改 JavaFX SplitMenuButton 中箭头的位置,但无法确定是否有一个配置可以给我这样的东西: SplitMenuButton with arrow on bottom
这可能吗?或者我需要创建拆分菜单按钮的定制版本?
最佳答案
使用 JavaFX SplitMenuButton 后,我找不到任何方法来轻松重现我需要的内容(菜单箭头位于默认右侧以外的侧面)。我创建了一个按钮类,允许将箭头按钮放置在主按钮的任何一侧(甚至隐藏)。该类虽然不完善,但已经完成了工作。该示例类的伟大之处在于可以动态更改箭头侧。
类代码:
public class MyButton extends Group {
private ButtonBase label;
private ButtonBase arrowButton;
protected ContextMenu popup;
private ObjectProperty<SplitMode> splitMode;
private DoubleProperty sizeBinding;
private DoubleProperty layoutBinding;
private double oldSizeValue;
private double oldLayoutValue;
private PseudoClass layoutClass;
//
private static PseudoClass TOP_PSEUDO_CLASS = PseudoClass.getPseudoClass("top");
private static PseudoClass BOTTOM_PSEUDO_CLASS = PseudoClass.getPseudoClass("bottom");
private static PseudoClass LEFT_PSEUDO_CLASS = PseudoClass.getPseudoClass("left");
private static PseudoClass RIGHT_PSEUDO_CLASS = PseudoClass.getPseudoClass("right");
private static PseudoClass HIDDEN_PSEUDO_CLASS = PseudoClass.getPseudoClass("hidden");
public static enum SplitMode {
SPLIT_TOP, // put arrow buton on top
SPLIT_RIGHT, // put arrow button on right
SPLIT_BOTTOM, // bottom
SPLIT_LEFT, // left
HIDDEN // hides the arrow button regardless of visibility
}
private void changeToPseudoClass(PseudoClass newClass) {
pseudoClassStateChanged(layoutClass, false);
pseudoClassStateChanged(newClass, true);
layoutClass = newClass;
}
private void bindHidden() {
if (sizeBinding != null) {
sizeBinding.unbind();
sizeBinding.set(oldSizeValue);
}
if (layoutBinding != null) {
layoutBinding.unbind();
layoutBinding.set(oldLayoutValue);
}
arrowButton.setVisible(false);
changeToPseudoClass(HIDDEN_PSEUDO_CLASS);
}
private void bindSizeAndLayout(DoubleProperty sizeFrom, ReadOnlyDoubleProperty sizeTo,
DoubleProperty layoutFrom, ReadOnlyDoubleProperty layoutTo,
PseudoClass newPseudoClass) {
if (sizeBinding != null) {
sizeBinding.unbind();
sizeBinding.set(oldSizeValue);
}
if (layoutBinding != null) {
layoutBinding.unbind();
layoutBinding.set(oldLayoutValue);
}
oldSizeValue = sizeFrom.get();
sizeBinding = sizeFrom;
oldLayoutValue = layoutFrom.get();
layoutBinding = layoutFrom;
sizeFrom.bind(sizeTo);
layoutFrom.bind(layoutTo);
changeToPseudoClass(newPseudoClass);
arrowButton.setVisible(true);
}
public void setSplitMode(SplitMode mode) {
if (splitMode == null) {
splitMode = new SimpleObjectProperty();
}
if (splitMode.get() == mode) {
return;
} // no changes needed
splitMode.set(mode);
// set up new bindings
switch (mode) {
case SPLIT_BOTTOM:
// bind arrowbutton width to label width
// bind arrowbutton starting position to bottom of label
bindSizeAndLayout(arrowButton.prefWidthProperty(), label.widthProperty(),
arrowButton.layoutYProperty(), label.heightProperty(),
BOTTOM_PSEUDO_CLASS);
break;
case SPLIT_RIGHT:
// bind arrowbutton height to label height
bindSizeAndLayout(arrowButton.prefHeightProperty(), label.heightProperty(),
arrowButton.layoutXProperty(), label.widthProperty(),
RIGHT_PSEUDO_CLASS);
break;
case SPLIT_LEFT:
// bind arrowbutton height to label height
bindSizeAndLayout(arrowButton.prefHeightProperty(), label.heightProperty(),
label.layoutXProperty(), arrowButton.widthProperty(),
LEFT_PSEUDO_CLASS);
break;
case SPLIT_TOP:
// bind arrowbutton width to label height
bindSizeAndLayout(arrowButton.prefWidthProperty(), label.widthProperty(),
label.layoutYProperty(), arrowButton.heightProperty(),
TOP_PSEUDO_CLASS);
break;
case HIDDEN:
// unbind all and hide button
bindHidden();
break;
}
}
public SplitMode getSplitMode() {
return (splitMode == null) ? SplitMode.HIDDEN : splitMode.get();
}
public ObjectProperty splitModeProperty() {
return splitMode;
}
public ButtonBase getButton() {
return label;
}
public ButtonBase getArrowButton() {
return arrowButton;
}
// Test suite
public MyButton() {
this("");
}
public MyButton(String text) {
this(text, SplitMode.SPLIT_RIGHT);
}
@SuppressWarnings("OverridableMethodCallInConstructor")
public MyButton(String text, SplitMode mode) {
label = new Button(text);
label.getStyleClass().setAll("label");
arrowButton = new Button();
// bind the managed property to visibility.
// we dont want to manage an invisible button.
arrowButton.managedProperty().bind(arrowButton.visibleProperty());
arrowButton.getStyleClass().setAll("arrow-button");
getStyleClass().setAll("split-menu-button");
getChildren().clear();
getChildren().addAll(label, arrowButton);
setSplitMode(mode);
}
}// end of class
MyButton 类创建额外的伪类以启用每一侧的特殊格式。
CSS 示例:
.split-menu-button > .label {
-fx-background-color: -fx-outer-border, -fx-inner-border, -fx-body-color;
-fx-background-insets: 0, 1 0 1 1, 2 1 2 2;
-fx-background-radius: 5 0 0 5, 4 0 0 4, 3 0 0 3;
-fx-padding: 0.166667em 0.667em 0.25em 0.833333em; /* 2 8 3 10 */
/* -fx-graphic:url("./icon_32.png"); */
-fx-content-display: top;
-fx-alignment: center;
}
.split-menu-button:top > .label {
-fx-background-insets: 0, 1 0 1 1, 2 1 2 2;
-fx-background-radius: 0 0 5 5, 0 0 4 4, 0 0 3 3;
}
.split-menu-button:right > .label {
-fx-background-insets: 0, 1 0 1 1, 2 1 2 2;
-fx-background-radius: 5 0 0 5, 4 0 0 4, 3 0 0 3;
}
.split-menu-button:bottom > .label {
-fx-background-insets: 0, 1 0 1 1, 2 1 2 2;
-fx-background-radius: 5 5 0 0, 4 4 0 0, 3 3 0 0;
}
.split-menu-button:left > .label {
-fx-background-insets: 0, 1 0 1 1, 2 1 2 2;
-fx-background-radius: 0 5 5 0, 0 4 4 0, 0 3 3 0;
}
.split-menu-button:hidden > .label {
-fx-background-insets: 0, 1 0 1 1, 2 1 2 2;
-fx-background-radius: 5 5 5 5, 4 4 4 4, 3 3 3 3;
}
.split-menu-button > .arrow-button {
-fx-background-color: -fx-outer-border, -fx-inner-border, -fx-body-color;
-fx-background-insets: 0, 1, 2;
-fx-background-radius: 0 5 5 0, 0 4 4 0, 0 3 3 0;
-fx-padding: 0; /* 0.5em 0.667em 0.5em 0.667em; /* 6 8 6 8 */
-fx-graphic:url("./arrow.png");
-fx-alignment:center;
}
.split-menu-button:top > .arrow-button {
-fx-background-insets: 0, 1, 2;
-fx-background-radius: 5 5 0 0, 4 4 0 0, 3 3 0 0;
}
.split-menu-button:right > .arrow-button {
-fx-background-insets: 0, 1, 2;
-fx-background-radius: 0 5 5 0, 0 4 4 0, 0 3 3 0;
}
.split-menu-button:bottom > .arrow-button {
-fx-background-insets: 0, 1, 2;
-fx-background-radius: 0 0 5 5, 0 0 4 4, 0 0 3 3;
}
.split-menu-button:left > .arrow-button {
-fx-background-insets: 0, 1, 2;
-fx-background-radius: 5 0 0 5, 4 0 0 4, 3 0 0 3;
}
测试按钮的示例应用程序。
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.event.ActionEvent;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import MyButton.SplitMode;
public class SimpleTest
extends Application {
Stage primaryStage;
protected ContextMenu popup;
@Override
public void start(final Stage stage) throws Exception {
primaryStage = stage;
primaryStage.setTitle("SimpleTest.");
Label label = new Label();
Button rotate = new Button("Rotate");
MyButton b = new MyButton("My Test", SplitMode.SPLIT_TOP);
label.setText(b.getSplitMode().toString());
StackPane sp = new StackPane();
sp.setPrefSize(200, 200);
sp.getStylesheets().add("test.css");
rotate.setOnAction((ActionEvent t) -> {
switch(b.getSplitMode()){
case SPLIT_TOP:
b.setSplitMode(SplitMode.SPLIT_RIGHT);
break;
case SPLIT_RIGHT:
b.setSplitMode(SplitMode.SPLIT_BOTTOM);
break;
case SPLIT_BOTTOM:
b.setSplitMode(SplitMode.SPLIT_LEFT);
break;
case SPLIT_LEFT:
b.setSplitMode(SplitMode.HIDDEN);
break;
case HIDDEN:
b.setSplitMode(SplitMode.SPLIT_TOP);
break;
}
label.setText(b.getSplitMode().toString());
});
StackPane.setAlignment(label, Pos.TOP_LEFT);
StackPane.setAlignment(rotate, Pos.TOP_RIGHT);
sp.getChildren().addAll(b, label, rotate);
primaryStage.setScene(new Scene(sp));
primaryStage.toFront();
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
关于JavaFX SplitMenuButton 设置箭头的位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37522801/
我正在尝试获取从过去的 startposition/location 到当前移动的 currentposition/location 的距离(以米为单位)。 我确实有工作正常的currentposit
所以我有一堆绝对覆盖的 div。用户通过在叠加层上拖动来创建方形 div。如果您要创建一个 div,然后放大和缩小,div 会保持在同一位置,因为它对叠加层是绝对的,如前所述。 然而问题就出在这里。您
我想找到 View 在显示屏幕上的位置。 为此,我使用了 view.getLeft() 、view.getBottom() 、view.getRight() 等方法> , view.getTop()。
我有一个看起来像这样的 View 层次结构(基于其他答案和 Apple 的使用 UIScrollView 的高级 AutoLayout 指南): ScrollView 所需的2 个步骤是: 为 Scr
所以我有一个名为 MARKS 的表,我有这些列 STUDENT_ID, CLASSFORM_NAME, ACADEMIC_YEAR, TERM, SUBJECT_NAME, TOTAL_MARKS
我有一个问题我无法理解,请帮助: 我开发了带有图像的 html 页面,并使用 jQuery UI 帮助使它们可拖动,我将这些图像位置设置为相对位置并给出了左侧和顶部像素,这是页面的链接 http://
我正在尝试创建一个 CSS 动画,它在 sprite 表中循环播放 16 个图像,给人一种幽灵“漂浮”的错觉。动画通过在 background-position 位置之间移动以显示不同状态的幽灵来实现
我正在创建这个网站的 WebView https://nearxt.com/打开时询问位置但是当我使用此链接在 flutter 中创建 webview 时那么它就无法定位我还在应用程序中定义了位置,但
我正在以编程方式创建一个需要跨越 2 个屏幕的窗口。正在创建的窗口的大小是正确的,但窗口大约从第一个屏幕的一半开始。我可以将它拖回第一个屏幕的开头,NSWindow 非常适合。 我只需要知道在窗口的起
位置“/”的匹配叶路由没有元素。这意味着默认情况下它将呈现一个空值,从而导致一个“空”页面 //App.js File import { BrowserRouter as Router, Routes
我有一个运行 Ubuntu 和 Apache 的 VPS 例如,假设地址是:5.5.5.5 在 VPS 上,我有一个名为 eggdrop 的用户(除了我的 root 用户)。 用户 eggdrop 有
我有一个 JLabel与 ImageIcon ,我使用 setIcon() JLabel中的函数. ImageIcon然后上来,坐在我的JLabel 的文字左侧.是否有可能拥有 ImageIcon在文
我的图中有节点,它们的 xlabels 位于它们的左上方。我怎样才能改变这个位置?我希望 xlabels 正好位于节点本身的旁边。 最佳答案 xlp是你想要的属性,但它没有做任何事情。 你不能改变位置
我对基本的 VIM 功能有疑问:(我尝试谷歌搜索但找不到答案) 如何列出所有自定义功能。(我做了 :function 并且不能找到我的自定义函数) 如何获得自定义函数列表中的函数(或它们的存储位置)。
我是 PHP 的新手,虽然我一直在搜索,但我不知道该怎么做。 我知道可以使用 Location("some page") 进行重定向。我还读到,只要没有向用户显示任何内容,它就可以工作。 我想做的是:
如果在 jgrowl.css 中位置更改为“center”,我如何将其覆盖为默认值,即“top-right” $.jGrowl(data, { header: 'data', an
我需要根据用户是否滑动屏幕顶部、屏幕中间或屏幕底部来触发不同的事件。我正在尝试找出最好/最简单的方法来做到这一点,因为我很确定没有办法从 UISwipeGestureRecognizer 获取位置。
我需要枚举用delphi编写的外部应用程序中使用的类 ,因此我需要访问VMT表以获取该信息,但是我找不到任何有关如何在exe(由delphi生成)文件中找到VMT(虚拟方法表)的位置(地址)的文档。
在 D2010 (unicode) 中是否有像 Pos 这样不区分大小写的类似函数? 我知道我可以使用 Pos(AnsiUpperCase(FindString), AnsiUpperCase(Sou
我正在尝试为我的reveal.js 演示文稿制作一个标题,该标题会粘贴在屏幕顶部。标题中的内容在每张幻灯片的基础上都是动态的,因此我必须将标记放在 section 标记中。 显然,如果标记在 sect
我是一名优秀的程序员,十分优秀!