gpt4 book ai didi

JavaFX:显示时动态更新菜单

转载 作者:行者123 更新时间:2023-11-30 10:06:07 25 4
gpt4 key购买 nike

我想向 JavaFX 菜单添加一个选项列表。菜单显示时应修改选项的顺序(我将使用模糊匹配,但该方法与我的问题无关)。我可以使用分别包含 TextFieldListViewCustomMenuItem 来模仿这种行为:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.CustomMenuItem;
import javafx.scene.control.ListView;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuButton;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class MWE extends Application {

@Override
public void start(Stage primaryStage) {
final Menu menu = new Menu("MENU");

final List<String> options = Arrays.asList(
"AbC",
"dfjksdljf",
"skdlfj",
"stackoverflow");

final StringProperty currentSelection = new SimpleStringProperty(null);

final TextField fuzzySearchField = new TextField(null);
final CustomMenuItem fuzzySearchItem = new CustomMenuItem(fuzzySearchField, false);
// TODO unfortunately we seem to have to grab focus like this!
fuzzySearchField.addEventFilter(MouseEvent.MOUSE_MOVED, e->{fuzzySearchField.requestFocus(); fuzzySearchField.selectEnd();});
final ObservableList<String> currentMatches = FXCollections.observableArrayList();
// just some dummy matching here
fuzzySearchField.textProperty().addListener((obs, oldv, newv) -> currentMatches.setAll(options.stream().filter(s -> s.toLowerCase().contains(newv)).collect(Collectors.toList())));
final ListView<String> lv = new ListView<>(currentMatches);
lv.addEventFilter(MouseEvent.MOUSE_MOVED, e -> lv.requestFocus());
final CustomMenuItem lvItem = new CustomMenuItem(lv, false);
menu.getItems().setAll(fuzzySearchItem, lvItem);
fuzzySearchField.textProperty().addListener((obs, oldv, newv) -> currentSelection.setValue(currentMatches.size() > 0 ? currentMatches.get(0) : null));
fuzzySearchField.setText("");

menu.setOnShown(e -> fuzzySearchField.requestFocus());
final MenuButton button = new MenuButton("menu");
button.getItems().setAll(menu);

Platform.runLater(() -> {
final Scene scene = new Scene(button);
primaryStage.setScene(scene);
primaryStage.show();
});

}
}

但是在菜单结构中有一个 ListView 感觉很奇怪。这就是为什么我尝试使用 MenuItem 而不是 ListView 的原因:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.CustomMenuItem;
import javafx.scene.control.ListView;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuButton;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class MWE2 extends Application {

@Override
public void start(Stage primaryStage) {
final Menu menu = new Menu("MENU");

final List<String> options = Arrays.asList(
"AbC",
"dfjksdljf",
"skdlfj",
"stackoverflow");

final StringProperty currentSelection = new SimpleStringProperty(null);

final TextField fuzzySearchField = new TextField(null);
final CustomMenuItem fuzzySearchItem = new CustomMenuItem(fuzzySearchField, false);
// TODO unfortunately we seem to have to grab focus like this!
fuzzySearchField.addEventFilter(MouseEvent.MOUSE_MOVED, e->{fuzzySearchField.requestFocus(); fuzzySearchField.selectEnd();});
final ObservableList<String> currentMatches = FXCollections.observableArrayList();
// just some dummy matching here
fuzzySearchField.textProperty().addListener((obs, oldv, newv) -> currentMatches.setAll(options.stream().filter(s -> s.toLowerCase().contains(newv)).collect(Collectors.toList())));
currentMatches.addListener((ListChangeListener<String>)change -> {
List<MenuItem> items = new ArrayList<>();
items.add(fuzzySearchItem);
currentMatches.stream().map(MenuItem::new).forEach(items::add);
System.out.println("Updating menu items!");
menu.getItems().setAll(items);
});
fuzzySearchField.textProperty().addListener((obs, oldv, newv) -> currentSelection.setValue(currentMatches.size() > 0 ? currentMatches.get(0) : null));
fuzzySearchField.setText("");

menu.setOnShown(e -> fuzzySearchField.requestFocus());
final MenuButton button = new MenuButton("menu");
button.getItems().setAll(menu);

Platform.runLater(() -> {
final Scene scene = new Scene(button);
primaryStage.setScene(scene);
primaryStage.show();
});

}
}

在那个例子中,菜单在显示时没有得到更新,即使我可以看到 "Updating menu items!" 打印到控制台,所以 menu 正在更新中。然而,屏幕上的菜单没有改变。

有没有办法请求重绘菜单?

相关问题:

最佳答案

我遵循了 @Enigo 的建议和 @Jesse_mw并使用了自定义节点。我决定使用仅包含 LabelListView 而不是 ListView,因为我只需要基本功能,不想拥有额外的混淆处理程序或突出显示。另请注意 @kleopatra指出,dynamic updates of items works out of the box for ContextMenu (and a potential bug in Menu) ,不幸的是,这对于我的用例来说不是一个合适的选择。

这是我的最低工作示例代码:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.CustomMenuItem;
import javafx.scene.control.Label;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuButton;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class MWE extends Application {

private static Label label(final String text) {
final Label label = new Label(text);
label.addEventFilter(MouseEvent.MOUSE_MOVED, e -> label.requestFocus());
label.setMaxWidth(200);
final Background background = label.getBackground();
label.setOnMouseEntered(e -> label.setBackground(new Background(new BackgroundFill(Color.GRAY.brighter(), CornerRadii.EMPTY, Insets.EMPTY))));
label.setOnMouseExited(e -> label.setBackground(background));
// Do something on mouse press; in real world scenario, also hide menu
label.setOnMousePressed(e -> {
if (e.isPrimaryButtonDown()) {
System.out.println(label.getText());
e.consume();
}
});
return label;
}

@Override
public void start(Stage primaryStage) {
final Menu menu = new Menu("MENU");

final List<String> options = Arrays.asList(
"AbC",
"dfjksdljf",
"skdlfj",
"stackoverflow","ssldkfjsdaf", "sjsdlf", "apple juice", "banana", "mango", "sdlfkjasdlfjsadlfj", "lkjsdflsdfj",
"stackoverflow","ssldkfjsdaf", "sjsdlf", "apple juice", "banana", "mango", "sdlfkjasdlfjsadlfj", "lkjsdflsdfj",
"stackoverflowstackoverflowstackoverflowstackoverflowstackoverflowstackoverflow","ssldkfjsdaf", "sjsdlf", "apple juice", "banana", "mango", "sdlfkjasdlfjsadlfj", "lkjsdflsdfj");

final StringProperty currentSelection = new SimpleStringProperty(null);

final TextField fuzzySearchField = new TextField(null);
final CustomMenuItem fuzzySearchItem = new CustomMenuItem(fuzzySearchField, false);
fuzzySearchItem.setDisable(true);
// TODO unfortunately we seem to have to grab focus like this!
fuzzySearchField.addEventFilter(MouseEvent.MOUSE_MOVED, e->{fuzzySearchField.requestFocus(); fuzzySearchField.selectEnd();});
final ObservableList<String> currentMatches = FXCollections.observableArrayList();
// just some dummy matching here
fuzzySearchField.textProperty().addListener((obs, oldv, newv) -> currentMatches.setAll(options.stream().filter(s -> s.toLowerCase().contains(newv)).collect(Collectors.toList())));
final VBox labels = new VBox();
currentMatches.addListener((ListChangeListener<String>) change -> labels.getChildren().setAll(currentMatches.stream().map(MWE::label).collect(Collectors.toList())));
final CustomMenuItem labelItem = new CustomMenuItem(labels, false);
menu.getItems().setAll(fuzzySearchItem, labelItem);
fuzzySearchField.textProperty().addListener((obs, oldv, newv) -> currentSelection.setValue(currentMatches.size() > 0 ? currentMatches.get(0) : null));
fuzzySearchField.setText("");

menu.setOnShown(e -> fuzzySearchField.requestFocus());
final MenuButton button = new MenuButton("menu");
button.getItems().setAll(menu);

Platform.runLater(() -> {
final Scene scene = new Scene(button);
primaryStage.setScene(scene);
primaryStage.show();
});

}
}

关于JavaFX:显示时动态更新菜单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54834206/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com