All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javafx.scene.control.MenuItem Maven / Gradle / Ivy

There is a newer version: 24-ea+15
Show newest version
/*
 * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package javafx.scene.control;

import com.sun.javafx.beans.IDProperty;
import javafx.collections.ObservableSet;
import javafx.css.PseudoClass;
import javafx.css.Styleable;
import javafx.css.CssMetaData;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ObjectPropertyBase;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventDispatchChain;
import javafx.event.EventHandler;
import javafx.event.EventTarget;
import javafx.event.EventType;
import javafx.scene.Node;
import javafx.scene.input.KeyCombination;

import com.sun.javafx.event.EventHandlerManager;
import com.sun.javafx.scene.control.ContextMenuContent;
import javafx.scene.control.skin.ContextMenuSkin;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.collections.ObservableMap;
import javafx.scene.Parent;

/**
 * 

* MenuItem is intended to be used in conjunction with {@link Menu} to provide * options to users. MenuItem serves as the base class for the bulk of JavaFX menus * API. * It has a display {@link #getText() text} property, as well as an optional {@link #getGraphic() graphic} node * that can be set on it. * The {@link #getAccelerator() accelerator} property enables accessing the * associated action in one keystroke. Also, as with the {@link Button} control, * by using the {@link #setOnAction} method, you can have an instance of MenuItem * perform any action you wish. *

* Note: Whilst any size of graphic can be inserted into a MenuItem, the most * commonly used size in most applications is 16x16 pixels. This is * the recommended graphic dimension to use if you're using the default style provided by * JavaFX. *

* To create a MenuItem is simple:

MenuItem menuItem = new MenuItem("Open");
menuItem.setOnAction(e {@literal ->} System.out.println("Opening Database Connection..."));
Circle graphic = new Circle(8);
graphic.setFill(Color.GREEN);
menuItem.setGraphic(graphic);

Menu menu = new Menu("File");
menu.getItems().add(menuItem);
MenuBar menuBar = new MenuBar(menu);
* * Image of the MenuItem control * * @see Menu * @since JavaFX 2.0 */ @IDProperty("id") public class MenuItem implements EventTarget, Styleable { /* ************************************************************************* * * * Constructors * * * **************************************************************************/ /** * Constructs a MenuItem with no display text. */ public MenuItem() { this(null,null); } /** * Constructs a MenuItem and sets the display text with the specified text * @param text the display text * @see #setText */ public MenuItem(String text) { this(text,null); } /** * Constructor s MenuItem and sets the display text with the specified text * and sets the graphic {@link Node} to the given node. * @param text the display text * @param graphic the graphic node * @see #setText * @see #setGraphic */ public MenuItem(String text, Node graphic) { setText(text); setGraphic(graphic); styleClass.add(DEFAULT_STYLE_CLASS); } /* ************************************************************************* * * * Instance Variables * * * **************************************************************************/ private final ObservableList styleClass = FXCollections.observableArrayList(); final EventHandlerManager eventHandlerManager = new EventHandlerManager(this); private Object userData; private ObservableMap properties; /* ************************************************************************* * * * Properties * * * **************************************************************************/ /** * The id of this MenuItem. This simple string identifier is useful for finding * a specific MenuItem within the scene graph. */ private StringProperty id; public final void setId(String value) { idProperty().set(value); } @Override public final String getId() { return id == null ? null : id.get(); } public final StringProperty idProperty() { if (id == null) { id = new SimpleStringProperty(this, "id"); } return id; } /** * A string representation of the CSS style associated with this specific MenuItem. * This is analogous to the "style" attribute of an HTML element. Note that, * like the HTML style attribute, this variable contains style properties and * values and not the selector portion of a style rule. */ private StringProperty style; public final void setStyle(String value) { styleProperty().set(value); } @Override public final String getStyle() { return style == null ? null : style.get(); } public final StringProperty styleProperty() { if (style == null) { style = new SimpleStringProperty(this, "style"); } return style; } // --- Parent Menu (useful for submenus) /** * This is the {@link Menu} in which this {@code MenuItem} exists. It is * possible for an instance of this class to not have a {@code parentMenu} - * this means that this instance is either: *
    *
  • Not yet associated with its {@code parentMenu}. *
  • A 'root' {@link Menu} (i.e. it is a context menu, attached directly to a * {@link MenuBar}, {@link MenuButton}, or any of the other controls that use * {@link Menu} internally. *
*/ private ReadOnlyObjectWrapper
parentMenu; protected final void setParentMenu(Menu value) { parentMenuPropertyImpl().set(value); } public final Menu getParentMenu() { return parentMenu == null ? null : parentMenu.get(); } public final ReadOnlyObjectProperty parentMenuProperty() { return parentMenuPropertyImpl().getReadOnlyProperty(); } private ReadOnlyObjectWrapper parentMenuPropertyImpl() { if (parentMenu == null) { parentMenu = new ReadOnlyObjectWrapper<>(this, "parentMenu"); } return parentMenu; } // --- Parent Popup /** * This is the {@link ContextMenu} in which this {@code MenuItem} exists. */ private ReadOnlyObjectWrapper parentPopup; protected final void setParentPopup(ContextMenu value) { parentPopupPropertyImpl().set(value); } public final ContextMenu getParentPopup() { return parentPopup == null ? null : parentPopup.get(); } public final ReadOnlyObjectProperty parentPopupProperty() { return parentPopupPropertyImpl().getReadOnlyProperty(); } private ReadOnlyObjectWrapper parentPopupPropertyImpl() { if (parentPopup == null) { parentPopup = new ReadOnlyObjectWrapper<>(this, "parentPopup"); } return parentPopup; } // --- Text /** * The text to display in the {@code MenuItem}. */ private StringProperty text; public final void setText(String value) { textProperty().set(value); } public final String getText() { return text == null ? null : text.get(); } public final StringProperty textProperty() { if (text == null) { text = new SimpleStringProperty(this, "text"); } return text; } // --- Graphic /** * An optional graphic for the {@code MenuItem}. This will normally be * an {@link javafx.scene.image.ImageView} node, but there is no requirement for this to be * the case. */ private ObjectProperty graphic; public final void setGraphic(Node value) { graphicProperty().set(value); } public final Node getGraphic() { return graphic == null ? null : graphic.get(); } public final ObjectProperty graphicProperty() { if (graphic == null) { graphic = new SimpleObjectProperty<>(this, "graphic"); } return graphic; } // --- OnAction /** * The action, which is invoked whenever the MenuItem is fired. This * may be due to the user clicking on the button with the mouse, or by * a touch event, or by a key press, or if the developer programmatically * invokes the {@link #fire()} method. */ private ObjectProperty> onAction; public final void setOnAction(EventHandler value) { onActionProperty().set( value); } public final EventHandler getOnAction() { return onAction == null ? null : onAction.get(); } public final ObjectProperty> onActionProperty() { if (onAction == null) { onAction = new ObjectPropertyBase<>() { @Override protected void invalidated() { eventHandlerManager.setEventHandler(ActionEvent.ACTION, get()); } @Override public Object getBean() { return MenuItem.this; } @Override public String getName() { return "onAction"; } }; } return onAction; } /** *

Called when a accelerator for the Menuitem is invoked

* @since JavaFX 2.2 */ public static final EventType MENU_VALIDATION_EVENT = new EventType<> (Event.ANY, "MENU_VALIDATION_EVENT"); /** * The event handler that is associated with invocation of an accelerator for a MenuItem. This * can happen when a key sequence for an accelerator is pressed. The event handler is also * invoked when onShowing event handler is called. * @since JavaFX 2.2 */ private ObjectProperty> onMenuValidation; public final void setOnMenuValidation(EventHandler value) { onMenuValidationProperty().set( value); } public final EventHandler getOnMenuValidation() { return onMenuValidation == null ? null : onMenuValidation.get(); } public final ObjectProperty> onMenuValidationProperty() { if (onMenuValidation == null) { onMenuValidation = new ObjectPropertyBase<>() { @Override protected void invalidated() { eventHandlerManager.setEventHandler(MENU_VALIDATION_EVENT, get()); } @Override public Object getBean() { return MenuItem.this; } @Override public String getName() { return "onMenuValidation"; } }; } return onMenuValidation; } // --- Disable /** * Sets the individual disabled state of this MenuItem. * Setting disable to true will cause this MenuItem to become disabled. */ private BooleanProperty disable; public final void setDisable(boolean value) { disableProperty().set(value); } public final boolean isDisable() { return disable == null ? false : disable.get(); } public final BooleanProperty disableProperty() { if (disable == null) { disable = new SimpleBooleanProperty(this, "disable"); } return disable; } // --- Visible /** * Specifies whether this MenuItem should be rendered as part of the scene graph. */ private BooleanProperty visible; public final void setVisible(boolean value) { visibleProperty().set(value); } public final boolean isVisible() { return visible == null ? true : visible.get(); } public final BooleanProperty visibleProperty() { if (visible == null) { visible = new SimpleBooleanProperty(this, "visible", true); } return visible; } /** * The accelerator property enables accessing the associated action in one keystroke. * It is a convenience offered to perform quickly a given action. */ private ObjectProperty accelerator; public final void setAccelerator(KeyCombination value) { acceleratorProperty().set(value); } public final KeyCombination getAccelerator() { return accelerator == null ? null : accelerator.get(); } public final ObjectProperty acceleratorProperty() { if (accelerator == null) { accelerator = new SimpleObjectProperty<>(this, "accelerator"); } return accelerator; } /** * MnemonicParsing property to enable/disable text parsing. * If this is set to true, then the MenuItem text will be * parsed to see if it contains the mnemonic parsing character '_'. * When a mnemonic is detected the key combination will * be determined based on the succeeding character, and the mnemonic * added. * *

* The default value for MenuItem is true. *

*/ private BooleanProperty mnemonicParsing; public final void setMnemonicParsing(boolean value) { mnemonicParsingProperty().set(value); } public final boolean isMnemonicParsing() { return mnemonicParsing == null ? true : mnemonicParsing.get(); } public final BooleanProperty mnemonicParsingProperty() { if (mnemonicParsing == null) { mnemonicParsing = new SimpleBooleanProperty(this, "mnemonicParsing", true); } return mnemonicParsing; } /* ************************************************************************* * * * Public API * * * **************************************************************************/ @Override public ObservableList getStyleClass() { return styleClass; } /** * Fires a new ActionEvent. */ public void fire() { Event.fireEvent(this, new ActionEvent(this, this)); } @Override public EventDispatchChain buildEventDispatchChain(EventDispatchChain tail) { // FIXME review that these are configure properly if (getParentPopup() != null) { getParentPopup().buildEventDispatchChain(tail); } if (getParentMenu() != null) { getParentMenu().buildEventDispatchChain(tail); } return tail.prepend(eventHandlerManager); } @Override public void addEventHandler(EventType eventType, EventHandler eventHandler) { eventHandlerManager.addEventHandler(eventType, eventHandler); } @Override public void removeEventHandler(EventType eventType, EventHandler eventHandler) { eventHandlerManager.removeEventHandler(eventType, eventHandler); } @Override public void addEventFilter(EventType eventType, EventHandler eventFilter) { eventHandlerManager.addEventFilter(eventType, eventFilter); } @Override public void removeEventFilter(EventType eventType, EventHandler eventFilter) { eventHandlerManager.removeEventFilter(eventType, eventFilter); } /** * Returns the {@code Object} that was set by {@link #setUserData(Object)}, or {@code null} if no object has been * set. * * @return the user object that was stored (including {@code null}), or {@code null} if no object has been set */ public Object getUserData() { return userData; } /** * Stores a user object that contains data at their discretion. It can later be retrieved by calling * {@link #getUserData()}. * * @param value the user object to be stored */ public void setUserData(Object value) { this.userData = value; } /** * Returns an observable map of properties on this menu item for use primarily * by application developers. * * @return an observable map of properties on this menu item for use primarily * by application developers */ public ObservableMap getProperties() { if (properties == null) { properties = FXCollections.observableMap(new HashMap<>()); } return properties; } /* ************************************************************************* * * * Stylesheet Handling * * * **************************************************************************/ private static final String DEFAULT_STYLE_CLASS = "menu-item"; /** * {@inheritDoc} * @return "MenuItem" * @since JavaFX 8.0 */ @Override public String getTypeSelector() { return "MenuItem"; } /** * {@inheritDoc} * @return {@code getParentMenu()}, or {@code getParentPopup()} * if {@code parentMenu} is null * @since JavaFX 8.0 */ @Override public Styleable getStyleableParent() { if(getParentMenu() == null) { return getParentPopup(); } else { return getParentMenu(); } } /** * {@inheritDoc} * @since JavaFX 8.0 */ @Override public final ObservableSet getPseudoClassStates() { return FXCollections.emptyObservableSet(); } @Override public List> getCssMetaData() { return Collections.emptyList(); } /** {@inheritDoc} */ @Override public Node getStyleableNode() { // Fix for RT-20582. We dive into the visual representation // of this MenuItem so that we may return it to the caller. ContextMenu parentPopup = MenuItem.this.getParentPopup(); if (parentPopup == null || ! (parentPopup.getSkin() instanceof ContextMenuSkin)) return null; ContextMenuSkin skin = (ContextMenuSkin) parentPopup.getSkin(); if (! (skin.getNode() instanceof ContextMenuContent)) return null; ContextMenuContent content = (ContextMenuContent) skin.getNode(); Parent nodes = content.getItemsContainer(); MenuItem desiredMenuItem = MenuItem.this; List childrenNodes = nodes.getChildrenUnmodifiable(); for (int i = 0; i < childrenNodes.size(); i++) { if (! (childrenNodes.get(i) instanceof ContextMenuContent.MenuItemContainer)) continue; ContextMenuContent.MenuItemContainer MenuRow = (ContextMenuContent.MenuItemContainer) childrenNodes.get(i); if (desiredMenuItem.equals(MenuRow.getItem())) { return MenuRow; } } return null; } @Override public String toString() { StringBuilder sbuf = new StringBuilder(getClass().getSimpleName()); boolean hasId = id != null && !"".equals(getId()); boolean hasStyleClass = !getStyleClass().isEmpty(); if (!hasId) { sbuf.append('@'); sbuf.append(Integer.toHexString(hashCode())); } else { sbuf.append("[id="); sbuf.append(getId()); if (!hasStyleClass) sbuf.append("]"); } if (hasStyleClass) { if (!hasId) sbuf.append('['); else sbuf.append(", "); sbuf.append("styleClass="); sbuf.append(getStyleClass()); sbuf.append("]"); } return sbuf.toString(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy