JavaFX初探(菜单)
< 返回列表时间: 2020-06-03来源:OSCHINA
JavaFX初探(菜单)
本节我们介绍如何创建菜单、菜单栏、增加菜单项、为菜单分类,创建子菜单、设置菜单上下文。你可以使用下面的类来创建菜单。 MenuBar MenuItem Menu CheckMenuItem RadioMenuItem CustomMenuItem SeparatorMenuItem ContextMenu
下图是一个典型的菜单的使用:

在应用中构建菜单
一个菜单就是一系列可操作的项目,可以根据用户的需要来表现。当一个菜单可见的时候,用户可以在某一时刻选中其中一个,在用户选中某一项时,这个菜单变成隐藏模式。通过使用菜单,我们可以节省用户界面的空间,因为有一些功能某些时间并不是总要现实出来的。
菜单在菜单栏中被分组,你需要使用下面的菜单项类,当你构建一个菜单的时候。 MenuItem 创建可选项 Menu 创建子菜单 RadioButtonItem 创建一个单选项 CheckMenuItem 这个菜单项可以在选择被无选择之间转换。
为了给菜单分类,可以使用SeparatorMenuItem 类。
菜单通常在窗口的顶部,并且这些菜单是隐藏的,我们可以通过鼠标点击上下文来打开菜单。
创建菜单栏
尽管菜单栏可以放在用户界面的任何地方,但是一般情况我们放到窗口的顶部。并且菜单栏可已自动的改变自己的大小。默认情况下,每一个菜单栏中的菜单像一个按钮一样呈现出来。
想想一个这样的一个应用,他显示植物的名称,图片,以及简单的描述信息。我们创建3个菜单项,:File,Edit,View.并给这三项添加菜单项。代码如下所示: import java.util.AbstractMap.SimpleEntry; import java.util.Map.Entry; import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.*; import javafx.scene.effect.DropShadow; import javafx.scene.effect.Effect; import javafx.scene.effect.Glow; import javafx.scene.effect.SepiaTone; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.VBox; import javafx.stage.Stage; public class MenuSample extends Application { final PageData[] pages = new PageData[] { new PageData( "Apple" , "The apple is the pomaceous fruit of the apple tree, species Malus " + "domestica in the rose family (Rosaceae). It is one of the most " + "widely cultivated tree fruits, and the most widely known of " + "the many members of genus Malus that are used by humans. " + "The tree originated in Western Asia, where its wild ancestor, " + "the Alma, is still found today." , "Malus domestica" ), new PageData( "Hawthorn" , "The hawthorn is a large genus of shrubs and trees in the rose " + "family, Rosaceae, native to temperate regions of the Northern " + "Hemisphere in Europe, Asia and North America. " + "The name hawthorn was " + "originally applied to the species native to northern Europe, " + "especially the Common Hawthorn C. monogyna, and the unmodified " + "name is often so used in Britain and Ireland." , "Crataegus monogyna" ), new PageData( "Ivy" , "The ivy is a flowering plant in the grape family (Vitaceae) native to" + " eastern Asia in Japan, Korea, and northern and eastern China. " + "It is a deciduous woody vine growing to 30 m tall or more given " + "suitable support, attaching itself by means of numerous small " + "branched tendrils tipped with sticky disks." , "Parthenocissus tricuspidata" ), new PageData( "Quince" , "The quince is the sole member of the genus Cydonia and is native to " + "warm-temperate southwest Asia in the Caucasus region. The " + "immature fruit is green with dense grey-white pubescence, most " + "of which rubs off before maturity in late autumn when the fruit " + "changes color to yellow with hard, strongly perfumed flesh." , "Cydonia oblonga" ) }; final String[] viewOptions = new String[] { "Title" , "Binomial name" , "Picture" , "Description" }; final Entry<String, Effect>[] effects = new Entry[] { new SimpleEntry<>( "Sepia Tone" , new SepiaTone()), new SimpleEntry<>( "Glow" , new Glow()), new SimpleEntry<>( "Shadow" , new DropShadow()) }; final ImageView pic = new ImageView(); final Label name = new Label(); final Label binName = new Label(); final Label description = new Label(); public static void main (String[] args) { launch(args); } @Override public void start (Stage stage) { stage.setTitle( "Menu Sample" ); Scene scene = new Scene( new VBox(), 400 , 350 ); MenuBar menuBar = new MenuBar(); // --- Menu File Menu menuFile = new Menu( "File" ); // --- Menu Edit Menu menuEdit = new Menu( "Edit" ); // --- Menu View Menu menuView = new Menu( "View" ); menuBar.getMenus().addAll(menuFile, menuEdit, menuView); ((VBox) scene.getRoot()).getChildren().addAll(menuBar); stage.setScene(scene); stage.show(); } private class PageData { public String name; public String description; public String binNames; public Image image; public PageData (String name, String description, String binNames) { this .name = name; this .description = description; this .binNames = binNames; image = new Image(getClass().getResourceAsStream(name + ".jpg" )); } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
和其他的UI控件不同,Menu类和其他的扩展MenuItem的类都不是扩展自Node类。所以他们不能直接添加到场景中,需要先添加到MenuBar中然后在添加到场景中。运行如下图所示:

你可以使用键盘的方向键来浏览菜单,然而当你选中一个菜单的时候,什么都没有发生,那是因为我们还没有指定行为。
添加菜单项
为文件菜单添加功能。 Shuffle 加载植物的参考信息 Clear 删除参考信息并清空场景 Separator 分离菜单项 Exit 退出应用
使用MenuItem创建了一个Shuffle菜单,并添加了一个图片组件。我们可以为MenuItem指定文本和图片。我们可以通过setAction方法来指定该菜单被点击时候的事件,这个Button是一样的。代码如下: import java.util.AbstractMap.SimpleEntry; import java.util.Map.Entry; import javafx.application.Application; import javafx.event.ActionEvent; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Scene; import javafx.scene.control.*; import javafx.scene.effect.DropShadow; import javafx.scene.effect.Effect; import javafx.scene.effect.Glow; import javafx.scene.effect.SepiaTone; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.scene.text.Font; import javafx.scene.text.TextAlignment; import javafx.stage.Stage; public class MenuSample extends Application { final PageData[] pages = new PageData[] { new PageData( "Apple" , "The apple is the pomaceous fruit of the apple tree, species Malus " + "domestica in the rose family (Rosaceae). It is one of the most " + "widely cultivated tree fruits, and the most widely known of " + "the many members of genus Malus that are used by humans. " + "The tree originated in Western Asia, where its wild ancestor, " + "the Alma, is still found today." , "Malus domestica" ), new PageData( "Hawthorn" , "The hawthorn is a large genus of shrubs and trees in the rose " + "family, Rosaceae, native to temperate regions of the Northern " + "Hemisphere in Europe, Asia and North America. " + "The name hawthorn was " + "originally applied to the species native to northern Europe, " + "especially the Common Hawthorn C. monogyna, and the unmodified " + "name is often so used in Britain and Ireland." , "Crataegus monogyna" ), new PageData( "Ivy" , "The ivy is a flowering plant in the grape family (Vitaceae) native" + " to eastern Asia in Japan, Korea, and northern and eastern China." + " It is a deciduous woody vine growing to 30 m tall or more given " + "suitable support, attaching itself by means of numerous small " + "branched tendrils tipped with sticky disks." , "Parthenocissus tricuspidata" ), new PageData( "Quince" , "The quince is the sole member of the genus Cydonia and is native" + " to warm-temperate southwest Asia in the Caucasus region. The " + "immature fruit is green with dense grey-white pubescence, most " + "of which rubs off before maturity in late autumn when the fruit " + "changes color to yellow with hard, strongly perfumed flesh." , "Cydonia oblonga" ) }; final String[] viewOptions = new String[] { "Title" , "Binomial name" , "Picture" , "Description" }; final Entry<String, Effect>[] effects = new Entry[] { new SimpleEntry<>( "Sepia Tone" , new SepiaTone()), new SimpleEntry<>( "Glow" , new Glow()), new SimpleEntry<>( "Shadow" , new DropShadow()) }; final ImageView pic = new ImageView(); final Label name = new Label(); final Label binName = new Label(); final Label description = new Label(); private int currentIndex = - 1 ; public static void main (String[] args) { launch(args); } @Override public void start (Stage stage) { stage.setTitle( "Menu Sample" ); Scene scene = new Scene( new VBox(), 400 , 350 ); scene.setFill(Color.OLDLACE); name.setFont( new Font( "Verdana Bold" , 22 )); binName.setFont( new Font( "Arial Italic" , 10 )); pic.setFitHeight( 150 ); pic.setPreserveRatio( true ); description.setWrapText( true ); description.setTextAlignment(TextAlignment.JUSTIFY); shuffle(); MenuBar menuBar = new MenuBar(); final VBox vbox = new VBox(); vbox.setAlignment(Pos.CENTER); vbox.setSpacing( 10 ); vbox.setPadding( new Insets( 0 , 10 , 0 , 10 )); vbox.getChildren().addAll(name, binName, pic, description); // --- Menu File Menu menuFile = new Menu( "File" ); MenuItem add = new MenuItem( "Shuffle" , new ImageView( new Image( "menusample/new.png" ))); add.setOnAction((ActionEvent t) -> { shuffle(); vbox.setVisible( true ); }); menuFile.getItems().addAll(add); // --- Menu Edit Menu menuEdit = new Menu( "Edit" ); // --- Menu View Menu menuView = new Menu( "View" ); menuBar.getMenus().addAll(menuFile, menuEdit, menuView); ((VBox) scene.getRoot()).getChildren().addAll(menuBar, vbox); stage.setScene(scene); stage.show(); } private void shuffle () { int i = currentIndex; while (i == currentIndex) { i = ( int ) (Math.random() * pages.length); } pic.setImage(pages[i].image); name.setText(pages[i].name); binName.setText( "(" + pages[i].binNames + ")" ); description.setText(pages[i].description); currentIndex = i; } private class PageData { public String name; public String description; public String binNames; public Image image; public PageData (String name, String description, String binNames) { this .name = name; this .description = description; this .binNames = binNames; image = new Image(getClass().getResourceAsStream(name + ".jpg" )); } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
当用户选择Shuffle菜单的时候,会就调用我们指定的setOnAction方法,显示出植物的名字、图片和简单描述。
Clear菜单用来抹除场景中的内容。我们可以使用下面的方法: MenuItem clear = new MenuItem( "Clear" ); clear.setAccelerator(KeyCombination.keyCombination( "Ctrl+X" )); clear.setOnAction ((ActionEvent t) -> { vbox.setVisible( false ); }) ; 1 2 3 4 5 6
Exit菜单实现如下: MenuItem exit = new MenuItem( "Exit" ); exit.setOnAction ((ActionEvent t) -> { System.exit( 0 ); }) ; 1 2 3 4 5
我们使用getItems方法来添加这些菜单项,如下: menuFile .getItems () .addAll ( add , clear, new SeparatorMenuItem(), exit) ; 1 2
编译运行应用,如下图所示:

View菜单可以来用指定,显示植物的部分信息, // --- Creating four check menu items within the start method CheckMenuItem titleView = createMenuItem ( "Title" , name); CheckMenuItem binNameView = createMenuItem ( "Binomial name" , binName); CheckMenuItem picView = createMenuItem ( "Picture" , pic); CheckMenuItem descriptionView = createMenuItem ( "Description" , description); menuView.getItems().addAll(titleView, binNameView, picView, descriptionView); ... // The createMenuItem method private static CheckMenuItem createMenuItem (String title, final Node node){ CheckMenuItem cmi = new CheckMenuItem(title); cmi.setSelected(true); cmi.selectedProperty().addListener( (ObservableValue<? extends Boolean> ov, Boolean old_val, Boolean new_val) -> { node.setVisible(new_val); }); return cmi; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
CheckMenuItem 是MenuItem类的扩展,他可以选中和非选中,如果被选中了,会显示出一个标记。编译运行如下图所示:

创建子菜单
Edit菜单中定义了两个菜单项:图片效果和无效果。图片效果菜单项有子菜单项。
使用RadioMenuItem 来创建子菜单,代码如下: // Picture Effect menu Menu menuEffect = new Menu( "Picture Effect" ); final ToggleGroup groupEffect = new ToggleGroup(); for (Entry<String, Effect> effect : effects) { RadioMenuItem itemEffect = new RadioMenuItem(effect.getKey()); itemEffect.setUserData(effect.getValue()); itemEffect.setToggleGroup(groupEffect); menuEffect.getItems().add(itemEffect); } // No Effects menu final MenuItem noEffects = new MenuItem( "No Effects" ); noEffects.setOnAction ((ActionEvent t) -> { pic.setEffect( null ); groupEffect.getSelectedToggle().setSelected( false ); }) ; // Processing menu item selection groupEffect . selectedToggleProperty () . addListener ( new ChangeListener<Toggle>() { public void changed(ObservableValue<? extends Toggle> ov, Toggle old_toggle, Toggle new_toggle) { if (groupEffect.getSelectedToggle() != null ) { Effect effect = (Effect) groupEffect.getSelectedToggle().getUserData(); pic.setEffect(effect); } } }) ; groupEffect . selectedToggleProperty () . addListener ( (ObservableValue<? extends Toggle> ov, Toggle old_toggle, Toggle new_toggle) -> { if (groupEffect.getSelectedToggle() != null ) { Effect effect = (Effect) groupEffect.getSelectedToggle().getUserData(); pic.setEffect(effect); } }) ; // Adding items to the Edit menu menuEdit . getItems () . addAll (menuEffect, noEffects) ; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
如下所示:

我们可以使用setDisable来禁用某一个菜单。 Menu menuEffect = new Menu( "Picture Effect" ); final ToggleGroup groupEffect = new ToggleGroup(); for (Entry<String, Effect> effect : effects) { RadioMenuItem itemEffect = new RadioMenuItem(effect.getKey()); itemEffect.setUserData(effect.getValue()); itemEffect.setToggleGroup(groupEffect); menuEffect.getItems().add(itemEffect); } final MenuItem noEffects = new MenuItem( "No Effects" ); noEffects.setDisable( true ); noEffects.setOnAction ((ActionEvent t) -> { pic.setEffect( null ); groupEffect.getSelectedToggle().setSelected( false ); noEffects.setDisable( true ); }) ; groupEffect . selectedToggleProperty () . addListener ( (ObservableValue<? extends Toggle> ov, Toggle old_toggle, Toggle new_toggle) -> { if (groupEffect.getSelectedToggle() != null ) { Effect effect = (Effect) groupEffect.getSelectedToggle().getUserData(); pic.setEffect(effect); noEffects.setDisable( false ); } else { noEffects.setDisable( true ); } }) ; menuEdit . getItems () . addAll (menuEffect, noEffects) ; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

添加上下文菜单
如果你的界面中没有为菜单的控件,那么你可以使用上下文菜单。当点击鼠标的时候,弹出上下文菜单。 final ContextMenu cm = new ContextMenu(); MenuItem cmItem1 = new MenuItem( "Copy Image" ); cmItem1.setOnAction ((ActionEvent e) -> { Clipboard clipboard = Clipboard.getSystemClipboard(); ClipboardContent content = new ClipboardContent(); content.putImage(pic.getImage()); clipboard.setContent(content); }) ; cm . getItems () . add (cmItem1) ; pic . addEventHandler (MouseEvent.MOUSE_CLICKED, (MouseEvent e) -> { if (e.getButton() == MouseButton.SECONDARY) cm.show(pic, e.getScreenX(), e.getScreenY()); }) ; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
热门排行