I want to fix the position of pop-up menu in QML. When I click on a setting button,I want the pop-up menu will display at the fixed position. I did it by a day but can't. How can I do it in QML. Also, I want to change the size of menu item(width and Height).
Hope your help!
That depends on QtQuick.Controls version.
In 2.0 you can define size and position(and even more - you must do)
import QtQuick 2.7
import QtQuick.Controls 2.0
//import QtQuick.Controls 1.4
import QtQuick.Window 2.0
Window
{
id: window
width: 500
height: 500
visible: true
MouseArea {
anchors.fill: parent
onClicked: {
menu.x = (window.width - menu.width) / 2
menu.y = (window.height - menu.height) / 2
//menu.__popup(Qt.rect(200,200,100,100),0,0);
menu.open();
}
}
Menu {
id: menu
MenuItem { text: "item1" }
MenuItem { text: "item2"; }
MenuItem { text: "item3"; height: 100 }
}
}
In 1.4 (see commented lines) you can try Menu.__popup() but this function is private and the behavior is unpredictable.
Related
I made a note app. Some user reports me a bug. When typing with Chinese Pinyin input source, character picker panel will covers characters in UITextView.
Xcode 12.4 MacOS 11.2.3
Wrong
Expectant
class ViewController: UIViewController {
let tv: UITextView = UITextView(frame: CGRect(x: 50, y: 50, width: 600, height: 200))
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(tv)
}
}
How to have the blue underline to appear at the TOP of the text (Tab name) instead of the bottom?
I am using Vaadin 14
Create file frontend/styles/tab-theme.css with content
:host::before,
:host::after {
top: 0;
}
Import it in your view with #CssImport(value = "./styles/tab-theme.css", themeFor = "vaadin-tab"), for example:
#Route
#CssImport(value = "./styles/tab-theme.css", themeFor = "vaadin-tab")
public class MainView extends VerticalLayout {
public MainView() {
Tabs tabs = new Tabs();
tabs.add(new Tab("Tab1"));
tabs.add(new Tab("Tab2"));
tabs.add(new Tab("Tab3"));
add(tabs);
}
}
and that's it.
Tested with Vaadin 14.2.1
I am trying to implement a menu. This is my code :
Menu menuFile1 = new Menu("ADD");
Menu menuFile2 = new Menu("EDIT");
Menu menuFile3 = new Menu("VIEW");
Menu menuFile4 = new Menu("HELP");
How can I put some space between each menu (that is between ADD,EDIT,VIEW and HELP) ?
Answer
Space around menus is controlled by padding (see the Region css guide).
For example:
menu.setStyle("-fx-padding: 5 10 8 10;");
sets the padding around the menu to 5 pixels on the top, 10 pixels on the right, 8 pixels on the bottom and 10 pixels on the left.
Sample
The following is a bit overcomplicated for a code sample to demonstrate this effect, but you could run it to see the effect of varying padding values.
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.StringExpression;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class SpacedOut extends Application {
#Override
public void start(final Stage stage) {
MenuBar menuBar = createMenuBar();
VBox controlPane = createControlPane(menuBar);
VBox layout = new VBox(10,
menuBar,
controlPane
);
VBox.setVgrow(controlPane, Priority.ALWAYS);
stage.setScene(new Scene(layout, 400, 200));
stage.show();
}
private MenuBar createMenuBar() {
MenuBar menuBar = new MenuBar();
menuBar.getMenus().addAll(
new Menu("ADD"),
new Menu("EDIT"),
new Menu("VIEW"),
new Menu("HELP")
);
return menuBar;
}
private VBox createControlPane(MenuBar menuBar) {
CheckBox useCustomPadding = new CheckBox("Use Custom Padding");
useCustomPadding.setSelected(false);
Slider padAmount = new Slider(0, 30, 15);
padAmount.setShowTickMarks(true);
padAmount.setShowTickLabels(true);
padAmount.setMajorTickUnit(10);
padAmount.setMaxWidth(200);
padAmount.disableProperty().bind(
useCustomPadding.selectedProperty().not()
);
VBox contentPane = new VBox(10,
useCustomPadding,
padAmount
);
contentPane.setPadding(new Insets(10));
StringExpression paddingExpression = Bindings.concat(
"-fx-padding: ", padAmount.valueProperty(), "px;"
);
menuBar.getMenus().forEach(
menu -> menu.styleProperty().bind(
Bindings
.when(useCustomPadding.selectedProperty())
.then(paddingExpression)
.otherwise("")
)
);
return contentPane;
}
public static void main(String[] args) {
launch(args);
}
}
With the setStyle() Method you can pass one or more css styles in one string.
Like menuFile1.setStyle("-fx-border-color: red; -fx-effect: dropshadow( one-pass-box , red , 10,0.5,0,0 );");
Alternatively you could put your style information inside a css file and add it to the Scene through.
Scene somescene = new Scene(root)
somescene.getStylesheets().add("your.css");
See the css reference of Java FX 2 or this tutorial.
Goal: Create a round button that has multiple text fonts.
Example: See RoundButtonWithMultipleFonts.java and RoundButtonWithMultipleFonts.css
RoundButtonWithMultipleFonts.java:
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Control;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class RoundButtonWithMultipleFonts extends Application {
public static void main(String... args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
stage.setTitle("Button with multiple fonts?");
stage.setScene(new Scene(getRoot(), 400, 400));
stage.getScene().getStylesheets().addAll(getClass().getResource("RoundButtonWithMultipleFonts.css").toExternalForm());
stage.sizeToScene();
stage.show();
}
private Parent getRoot() {
Button button = new Button(""); // The labels should be the buttons text
button.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
System.out.println("Button clicked");
}
});
Label header = new Label("A Prideful Header"); // Label for big font on button
header.getStyleClass().addAll("header");
Label footer = new Label("a humble footer"); // Label for small font on button
footer.getStyleClass().addAll("footer");
// Since the labels are on top of the button, pass any events they capture to the button
configurePassThroughEvents(button, header, footer);
StackPane stack = new StackPane();
stack.getChildren().addAll(button, header, footer);
return stack;
}
private void configurePassThroughEvents(Control targetControl, Control... sourceControls) {
MouseEventPassThrough passThroughEvent = new MouseEventPassThrough(targetControl);
for(Control sourceControl : sourceControls) {
sourceControl.setOnMouseClicked(passThroughEvent);
sourceControl.setOnMouseDragged(passThroughEvent);
sourceControl.setOnMouseDragEntered(passThroughEvent);
sourceControl.setOnMouseDragExited(passThroughEvent);
sourceControl.setOnMouseDragOver(passThroughEvent);
sourceControl.setOnMouseDragReleased(passThroughEvent);
sourceControl.setOnMouseEntered(passThroughEvent);
sourceControl.setOnMouseExited(passThroughEvent);
sourceControl.setOnMouseMoved(passThroughEvent);
sourceControl.setOnMousePressed(passThroughEvent);
sourceControl.setOnMouseReleased(passThroughEvent);
}
}
private static class MouseEventPassThrough implements EventHandler<MouseEvent> {
private final Control targetControl;
private MouseEventPassThrough(Control targetControl) { this.targetControl = targetControl; }
#Override public void handle(MouseEvent mouseEvent) { targetControl.fireEvent(mouseEvent); }
}
}
RoundButtonWithMultipleFonts.css:
.button {
-fx-border-width: 1px;
-fx-border-color: #000000;
-fx-border-radius: 45;
-fx-background-color: linear-gradient(#ffffff 0%, #cccccc 100%);
-fx-background-radius: 45;
-fx-padding: 50 100;
}
.button:hover {
-fx-background-color: linear-gradient(#ffffff 0%, coral 100%);
}
.label {
-fx-padding: 10;
-fx-background-color: cornflowerblue;
}
.header {
-fx-font-size: 110%;
-fx-font-weight: bold;
-fx-translate-y: -20;
}
.footer {
-fx-font-size: 80%;
-fx-translate-y: 20;
}
Runtime Results:
Problem:
When the mouse scrolls over one of the button's corners, the button enters the hovered state, but the mouse is still outside the visual bounds of the button indicated by the button's border and background. (See image.)
This example uses a stack pane, multiple labels, an event pass through mechanism, and css trickery to give the appearance of a button containing text with multiple fonts.
Questions:
How can I specify that the button should enter the hovered state only if the mouse collides with the buttons visual boundary as specified in the css with the border or background properties?
Is there a simpler way to specify multiple fonts (with general text layout) for a button than what is done in this example? Ideally I would want to just use a Button with a nested Node as the text. That would allow me to put anything I wanted inside the buttons textual area without needing the event pass through mechanism, the StackPane, and the css trickery.
You can use setGraphic(Node node); method of Button class to set your custom labels on button. Here is an example,
Label header = new Label("A Prideful Header");
header.getStyleClass().addAll("header");
Label footer = new Label("a humble footer");
footer.getStyleClass().addAll("footer");
VBox box = new VBox();
box.getChildren().addAll(header,footer);
Button button = new Button();
button.setGraphic(box);
I'm making a MenuBar, and I wan't the functionality to press a Menu like: "File" and then execute a action. Such like opening an other fxml, or an example where some output is written.
I want the functionality of a MenuItem (lie "About") in a Menu like "File".
package model;
import static java.lang.System.out;
import javafx.application.Application;
import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.geometry.Side;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
/**
* Example of creating menus in JavaFX.
*
* #author Dustin
*/
public class JavaFxMenus extends Application
{
/**
* Build menu bar with included menus for this demonstration.
*
* #param menuWidthProperty Width to be bound to menu bar width.
* #return Menu Bar with menus included.
*/
private MenuBar buildMenuBarWithMenus(final ReadOnlyDoubleProperty menuWidthProperty)
{
final MenuBar menuBar = new MenuBar();
// Prepare left-most 'File' drop-down menu
final Menu fileMenu = new Menu("File");
menuBar.getMenus().add(fileMenu);
//menuBar.getOnMouseClicked().handle(this);
// Prepare 'Examples' drop-down menu
final Menu examplesMenu = new Menu("JavaFX 2.0 Examples");
examplesMenu.getItems().add(new MenuItem("Text Example"));
examplesMenu.getItems().add(new MenuItem("Objects Example"));
examplesMenu.getItems().add(new MenuItem("Animation Example"));
menuBar.getMenus().add(examplesMenu);
// Prepare 'Help' drop-down menu
final Menu helpMenu = new Menu("Help");
helpMenu.setOnAction(null);
final MenuItem searchMenuItem = new MenuItem("Search");
searchMenuItem.setDisable(true);
helpMenu.getItems().add(searchMenuItem);
final MenuItem onlineManualMenuItem = new MenuItem("Online Manual");
onlineManualMenuItem.setVisible(false);
helpMenu.getItems().add(onlineManualMenuItem);
helpMenu.getItems().add(new SeparatorMenuItem());
final MenuItem aboutMenuItem =
MenuItemBuilder.create()
.text("About")
.onAction(
new EventHandler<ActionEvent>()
{
#Override public void handle(ActionEvent e)
{
out.println("You clicked on About!");
}
})
.accelerator(
new KeyCodeCombination(
KeyCode.A, KeyCombination.CONTROL_DOWN))
.build();
helpMenu.getItems().add(aboutMenuItem);
menuBar.getMenus().add(helpMenu);
// bind width of menu bar to width of associated stage
menuBar.prefWidthProperty().bind(menuWidthProperty);
return menuBar;
}
/**
* Start of JavaFX application demonstrating menu support.
*
* #param stage Primary stage.
*/
#Override
public void start(final Stage stage)
{
stage.setTitle("Creating Menus with JavaFX 2.0");
final Group rootGroup = new Group();
final Scene scene = new Scene(rootGroup, 800, 400, Color.WHEAT);
final MenuBar menuBar = buildMenuBarWithMenus(stage.widthProperty());
rootGroup.getChildren().add(menuBar);
stage.setScene(scene);
stage.show();
}
/**
* Main executable function for running examples.
*
* #param arguments Command-line arguments: none expected.
*/
public static void main(final String[] arguments)
{
Application.launch(arguments);
}
}
AFAIK, A Menu, if has not any added submenu or Menuitems, does not fire events neither on click, on shown nor on hide. However the workaround is to set its graphic where this graphic node will handle mouse clicks for example,
Label menuLabel = new Label("File");
menuLabel.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
Stage myDialog = new Stage();
myDialog.initModality(Modality.WINDOW_MODAL);
Scene myDialogScene = new Scene(VBoxBuilder.create()
.children(new Text("Hello! it's My Dialog."))
.alignment(Pos.CENTER)
.padding(new Insets(10))
.build());
myDialog.setScene(myDialogScene);
myDialog.show();
}
});
Menu fileMenuButton = new Menu();
fileMenuButton.setGraphic(menuLabel);
menuBar.getMenus().add(fileMenuButton);
A drawback of this approach is that the label do not cover all spaces of the menu resulting clicking on edges of menu is not triggering the mouse event. See this by uncommenting menuLabel.setStyle line above. But this can be resolved by playing with CSS styles I think.
Code is partially taken from Create Dialog using Stage. You can also load an FXML file into the myDialog stage using the FXMLLoader. There are lots of examples about it on the net.
Recently i had the same problem, this is what i did
#FXML private Menu myMenu;
#Override
public void initialize(URL url, ResourceBundle rb) {
myMenu.setGraphic(
ButtonBuilder.create()
.text("btnText")
.onAction(new EventHandler<ActionEvent>(){
#Override public void handle(ActionEvent t) {
//TODO
} })
.build()
);
}
Combining with the answer from our friend #Dota2, i built a helper class to trigger the Menu's onAction(Menu menu) event even if it does not have any MenuItem inside. Here is the static helper method:
public static void onAction(Menu menu)
{
final MenuItem menuItem = new MenuItem();
menu.getItems().add(menuItem);
menu.addEventHandler(Menu.ON_SHOWN, event -> menu.hide());
menu.addEventHandler(Menu.ON_SHOWING, event -> menu.fire());
}
Then you call:
YourHelperClass.onAction(myMenu);
And ready! I hope this helps.
Recently I faced the same issue, this was my way out:
I had a menuItem in the menu, which was to behave as if the menuItem is clicked (in your case File menu). So what you can do is have a menuItem Dummy_menuItem
final Menu fileMenu = new Menu("File");
fileMenu.getItems().add(new MenuItem("Dummy_menuItem"));
menuBar.getMenus().add(fileMenu);
and then on click of File menu, fire the Dummy_menuItem menuItem or any functionality you wish to have. To identify which menu should have this property, I used numberOfMenuItems to get the number of menuItems in the menus in menubar
if (numberOfMenuItems == 1) {
menu.showingProperty().addListener(
(observableValue, oldValue, newValue) -> {
if (newValue) {
// the first menuItem is triggered
menu.getItems().get(0).fire();
}
}
);
}
the outcome is that the Dummy_menuItem is triggered without the context displaying the menuItem on click of File menu or any menu that has one menuItem. So it appears as if you clicked the File menu and were redirected to another page or whatever.
Hope this helps!!
I think you can't allow any action on the main Menu label.
However, you can create a stackpane, and fill it with text and a menu bar.