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
来源:oschina
链接:https://my.oschina.net/u/2963604/blog/4298960