java fx 菜单_DOC-03-24 菜单(Menu)

DOC-03-24 菜单(Menu)

本章将介绍如何创建菜单(Menu)和菜单栏(Menu Bar),添加菜单项(Menu Item),将菜单分组,创建子菜单(Submenu),以及设置上下文菜单(Context Menu)。

你可以使用下面这些JavaFX API中的类来在你的应用程序中构建菜单。

· MenuBar

· MenuItem

· Menu

· CheckMenuItem

· RadioMenuItem

· Menu

· CustomMenuItem

· SeparatorMenuItem

· ContextMenu

图24-1显示了一个包含典型菜单栏的应用程序。

图24-1包含菜单栏和三个菜单分类的应用程序

4db4ac3ad26bb28f025f263e6ba66d33.png

在JavaFX应用程序中构建菜单

一个菜单是一系列可以根据用户的需要进行显示的可响应事件的菜单项。当一个菜单可见时,用户一次可以选择一个菜单项。当用户点击一个菜单项后,菜单就会回到隐藏模式。通过使用菜单,你将一些不需要始终显示的功能放在其中,这样可以节省你的应用程序UI空间。

菜单栏中的菜单通常会分组到不同类别中。编码模式是定义一个菜单栏,定义一些分类菜单,为分类菜单填充菜单项。当在你的JavaFX应用程序中构建菜单时,使用下面的菜单项类。

· MenuItem – 创建一个可响应事件的选项

· Menu – 创建一个子菜单

· RadioButtonItem – 创建一个相互排斥的选项

· CheckMenuItem – 创建一个可在选中和非选中状态切换的选项

在一个分类中对菜单项进行分隔,使用SeparatorMenuItem类。

对于分类组织在菜单栏中的菜单一般位于窗口的上方,scene中其余的空间留给那些重要的控件。基于某种原因,如果你不想在你的UI中为菜单栏分配任何可见空间,你可以使用上下文菜单,它通过用户点击鼠标打开。

创建菜单栏

尽管菜单栏可以被放置在UI的任何其他地方,但是菜单栏一般是位于UI的上方,而且它包含一个或者多个菜单。菜单栏会自动伸缩以适用应用程序窗口的宽度。默认情况下,每个添加到菜单栏的菜单是由带有文本的按钮表示的。

想象一个应用程序,它显示植物的参考信息,如名称,拉丁学名,图片,和简介。你可以创建三个分类菜单:File,Edit和View,然后为这些菜单填充菜单项。例24-1展示了这样一个带有菜单栏的应用程序的源代码。

例24-1 Menu Sample应用程序

Java

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[] 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

importjava.util.AbstractMap.SimpleEntry;

importjava.util.Map.Entry;

importjavafx.application.Application;

importjavafx.scene.Scene;

importjavafx.scene.control.*;

importjavafx.scene.effect.DropShadow;

importjavafx.scene.effect.Effect;

importjavafx.scene.effect.Glow;

importjavafx.scene.effect.SepiaTone;

importjavafx.scene.image.Image;

importjavafx.scene.image.ImageView;

importjavafx.scene.layout.VBox;

importjavafx.stage.Stage;

publicclassMenuSampleextendsApplication{

finalPageData[]pages=newPageData[]{

newPageData("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"),

newPageData("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"),

newPageData("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"),

newPageData("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")

};

finalString[]viewOptions=newString[]{

"Title",

"Binomial name",

"Picture",

"Description"

};

finalEntry[]effects=newEntry[]{

newSimpleEntry<>("Sepia Tone",newSepiaTone()),

newSimpleEntry<>("Glow",newGlow()),

newSimpleEntry<>("Shadow",newDropShadow())

};

finalImageViewpic=newImageView();

finalLabelname=newLabel();

finalLabelbinName=newLabel();

finalLabeldescription=newLabel();

publicstaticvoidmain(String[]args){

launch(args);

}

@Override

publicvoidstart(Stagestage){

stage.setTitle("Menu Sample");

Scenescene=newScene(newVBox(),400,350);

MenuBarmenuBar=newMenuBar();

// --- Menu File

MenumenuFile=newMenu("File");

// --- Menu Edit

MenumenuEdit=newMenu("Edit");

// --- Menu View

MenumenuView=newMenu("View");

menuBar.getMenus().addAll(menuFile,menuEdit,menuView);

((VBox)scene.getRoot()).getChildren().addAll(menuBar);

stage.setScene(scene);

stage.show();

}

privateclassPageData{

publicStringname;

publicStringdescription;

publicStringbinNames;

publicImageimage;

publicPageData(Stringname,Stringdescription,StringbinNames){

this.name=name;

this.description=description;

this.binNames=binNames;

image=newImage(getClass().getResourceAsStream(name+".jpg"));

}

}

}

与其他UI控件不一样,Menu类和其他MenuItem的扩展类不是继承自Node类。他们不能直接添加到应用程序scene中,直到通过getMenus()方法添加到菜单栏中时才可见。

图24-2添加菜单栏到应用程序中

93676c13bd8956559943db4c57d3d6f6.png

你可以使用键盘上的箭头按键来浏览所有的菜单。但是,当你选择一个菜单时,没有动作被执行,因为菜单的行为还没有被定义。

添加菜单项

通过添加以下菜单项为File菜单设置功能:

· Shuffle – 加载植物的参考信息

· Clear – 移除参考信息并清除scene

· Separator – 分隔菜单项

· Exit – 退出应用程序

例24-2中粗体的行通过MenuItem类创建了一个Shuffle 菜单,并添加了一些图像组件到应用程序scene。MenuItem类允许使用文本和图像创建一个可响应事件的菜单项。在用户点击时执行的动作可以通过setOnAction方法来定义,这和Button类很相似。

例24-2添加带图像的Shuffle菜单项

Java

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[] 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

importjava.util.AbstractMap.SimpleEntry;

importjava.util.Map.Entry;

importjavafx.application.Application;

importjavafx.event.ActionEvent;

importjavafx.geometry.Insets;

importjavafx.geometry.Pos;

importjavafx.scene.Scene;

importjavafx.scene.control.*;

importjavafx.scene.effect.DropShadow;

importjavafx.scene.effect.Effect;

importjavafx.scene.effect.Glow;

importjavafx.scene.effect.SepiaTone;

importjavafx.scene.image.Image;

importjavafx.scene.image.ImageView;

importjavafx.scene.layout.VBox;

importjavafx.scene.paint.Color;

importjavafx.scene.text.Font;

importjavafx.scene.text.TextAlignment;

importjavafx.stage.Stage;

publicclassMenuSampleextendsApplication{

finalPageData[]pages=newPageData[]{

newPageData("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"),

newPageData("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"),

newPageData("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"),

newPageData("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")

};

finalString[]viewOptions=newString[]{

"Title",

"Binomial name",

"Picture",

"Description"

};

finalEntry[]effects=newEntry[]{

newSimpleEntry<>("Sepia Tone",newSepiaTone()),

newSimpleEntry<>("Glow",newGlow()),

newSimpleEntry<>("Shadow",newDropShadow())

};

finalImageViewpic=newImageView();

finalLabelname=newLabel();

finalLabelbinName=newLabel();

finalLabeldescription=newLabel();

privateintcurrentIndex=-1;

publicstaticvoidmain(String[]args){

launch(args);

}

@Override

publicvoidstart(Stagestage){

stage.setTitle("Menu Sample");

Scenescene=newScene(newVBox(),400,350);

scene.setFill(Color.OLDLACE);

name.setFont(newFont("Verdana Bold",22));

binName.setFont(newFont("Arial Italic",10));

pic.setFitHeight(150);

pic.setPreserveRatio(true);

description.setWrapText(true);

description.setTextAlignment(TextAlignment.JUSTIFY);

shuffle();

MenuBarmenuBar=newMenuBar();

finalVBoxvbox=newVBox();

vbox.setAlignment(Pos.CENTER);

vbox.setSpacing(10);

vbox.setPadding(newInsets(0,10,0,10));

vbox.getChildren().addAll(name,binName,pic,description);

// --- Menu File

MenumenuFile=newMenu("File");

MenuItemadd=newMenuItem("Shuffle",

newImageView(newImage("menusample/new.png")));

add.setOnAction((ActionEventt)->{

shuffle();

vbox.setVisible(true);

});

menuFile.getItems().addAll(add);

// --- Menu Edit

MenumenuEdit=newMenu("Edit");

// --- Menu View

MenumenuView=newMenu("View");

menuBar.getMenus().addAll(menuFile,menuEdit,menuView);

((VBox)scene.getRoot()).getChildren().addAll(menuBar,vbox);

stage.setScene(scene);

stage.show();

}

privatevoidshuffle(){

inti=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;

}

privateclassPageData{

publicStringname;

publicStringdescription;

publicStringbinNames;

publicImageimage;

publicPageData(Stringname,Stringdescription,StringbinNames){

this.name=name;

this.description=description;

this.binNames=binNames;

image=newImage(getClass().getResourceAsStream(name+".jpg"));

}

}

}

当用户选中Shuffle菜单项时,setOnAction方法中指定的shuffle()方法就会被调用,它计算出的元素位置,然后从对应的数组中取值并设置标题,拉丁学名,植物图片和描述。

Clear菜单项用于清除应用程序scene的内容。你可以通过将包含GUI元素的VBox容器设置为不可见来实现此效果,见例24-3。

例24-3创建带快捷键的Clear菜单项

Java

MenuItem clear = new MenuItem("Clear");

clear.setAccelerator(KeyCombination.keyCombination("Ctrl+X"));

clear.setOnAction((ActionEvent t) -> {

vbox.setVisible(false);

});

1

2

3

4

5

MenuItemclear=newMenuItem("Clear");

clear.setAccelerator(KeyCombination.keyCombination("Ctrl+X"));

clear.setOnAction((ActionEventt)->{

vbox.setVisible(false);

});

MenuItem类的实现允许开发者设置一个菜单快捷键,这是一个组合键,能够执行和点击菜单项一样的动作。对于Clear菜单项,用户可以从File菜单中选择动作,也可以同时按下Ctrl和X键。

Exit菜单关闭应用程序窗口。例24-4中展示了为该菜单项设置System.exit(0)响应动作。

例24-4创建Exit菜单项

Java

MenuItem exit = new MenuItem("Exit");

exit.setOnAction((ActionEvent t) -> {

System.exit(0);

});

1

2

3

4

MenuItemexit=newMenuItem("Exit");

exit.setOnAction((ActionEventt)->{

System.exit(0);

});

使用getItems()方法来向File菜单中新增菜单项,见例24-5。你可以创建一个分隔菜单项,并通过getItems()方法将其添加进去,以将Exit菜单隔离开。

例24-5添加菜单项

Java

menuFile.getItems().addAll(add, clear, new SeparatorMenuItem(), exit);

1

menuFile.getItems().addAll(add,clear,newSeparatorMenuItem(),exit);

将例24-2,24-3,24-4,24-5添加到Menu Sample应用程序中,编译并运行之。选择Shuffle菜单项来加载不同植物的参考信息。然后清除scene(Clear菜单项),并关闭应用程序(Close菜单项)。图24-3显示了选中Clear菜单项的效果。

图24-3带三个菜单项的File菜单

9785564629e89598811c0e2da72b9fc8.png

有了View菜单,你可以隐藏和显示参考信息中的某些元素。实现createMenuItem()方法,并在start()方法中调用以创建四个CheckMenuItem对象。然后添加这些新创建的CheckMenuItem到View菜单中,这些菜单项可以控制标题,拉丁学名,图片和描述的显示与否。例24-6显示了实现了这些功能的两段代码。

例24-6使用CheckMenuItem类来创建开关选项

Java

//在start方法中创建四个Check Menu Item

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);

...

//createMenuItem方法

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

//在start方法中创建四个Check Menu Item

CheckMenuItemtitleView=createMenuItem("Title",name);

CheckMenuItembinNameView=createMenuItem("Binomial name",binName);

CheckMenuItempicView=createMenuItem("Picture",pic);

CheckMenuItemdescriptionView=createMenuItem("Description",description);

menuView.getItems().addAll(titleView,binNameView,picView,descriptionView);

...

//createMenuItem方法

privatestaticCheckMenuItemcreateMenuItem(Stringtitle,finalNodenode){

CheckMenuItemcmi=newCheckMenuItem(title);

cmi.setSelected(true);

cmi.selectedProperty().addListener(

(ObservableValue<?extendsBoolean>ov,Booleanold_val,

Booleannew_val)->{

node.setVisible(new_val);

});

returncmi;

}

CheckMenuItem类是MenuItem类的扩展。它可以在选中和非选中状态之间切换。当选中时,Check Menu Item会显示一个对钩标志。

例24-6创建了四个CheckMenuItem对象,并处理了他们的selectedProperty属性变化事件。例如,当用户取消选中picView菜单项,setVisible()方法会被赋以false,然后植物的图片就变得不可见了。当你添加这段代码到应用程序,编译并运行之,你可以尝试选中和取消选中这些菜单项。图24-4显示了标题和图片可见,而拉丁学名和描述不可见时的应用程序效果。

图24-4使用Check Menu Item

988036fc32f80ed7bfcdb77b6a3ddac1.png

创建子菜单

对于Edit菜单,定义两个菜单项:Picture Effect和No Effects。Picture Effect菜单项被设计为包含三个菜单项的子菜单,用于控制三种可用的视觉特效。No Effects 菜单项会移除选中的特效,将图片重置到初始状态。

使用RadioMenuItem来创建子菜单的菜单项。将Radio Menu Item添加到Toggle Group中,使各个菜单项的选中是相互排斥的。例24-7实现了这些功能。

例24-7创建带有Radio Menu Item的子菜单

Java

//Picture Effect菜单

Menu menuEffect = new Menu("Picture Effect");

final ToggleGroup groupEffect = new ToggleGroup();

for (Entry effect : effects) {

RadioMenuItem itemEffect = new RadioMenuItem(effect.getKey());

itemEffect.setUserData(effect.getValue());

itemEffect.setToggleGroup(groupEffect);

menuEffect.getItems().add(itemEffect);

}

//No Effects菜单

final MenuItem noEffects = new MenuItem("No Effects");

noEffects.setOnAction((ActionEvent t) -> {

pic.setEffect(null);

groupEffect.getSelectedToggle().setSelected(false);

});

//处理菜单项的选中事件

groupEffect.selectedToggleProperty().addListener(new ChangeListener() {

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);

}

});

//向Edit菜单添加菜单项

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

//Picture Effect菜单

MenumenuEffect=newMenu("Picture Effect");

finalToggleGroupgroupEffect=newToggleGroup();

for(Entryeffect:effects){

RadioMenuItemitemEffect=newRadioMenuItem(effect.getKey());

itemEffect.setUserData(effect.getValue());

itemEffect.setToggleGroup(groupEffect);

menuEffect.getItems().add(itemEffect);

}

//No Effects菜单

finalMenuItemnoEffects=newMenuItem("No Effects");

noEffects.setOnAction((ActionEventt)->{

pic.setEffect(null);

groupEffect.getSelectedToggle().setSelected(false);

});

//处理菜单项的选中事件

groupEffect.selectedToggleProperty().addListener(newChangeListener(){

publicvoidchanged(ObservableValue<?extendsToggle>ov,

Toggleold_toggle,Togglenew_toggle){

if(groupEffect.getSelectedToggle()!=null){

Effecteffect=

(Effect)groupEffect.getSelectedToggle().getUserData();

pic.setEffect(effect);

}

}

});

groupEffect.selectedToggleProperty().addListener(

(ObservableValue<?extendsToggle>ov,Toggleold_toggle,

Togglenew_toggle)->{

if(groupEffect.getSelectedToggle()!=null){

Effecteffect=

(Effect)groupEffect.getSelectedToggle().getUserData();

pic.setEffect(effect);

}

});

//向Edit菜单添加菜单项

menuEdit.getItems().addAll(menuEffect,noEffects);

通过setUserData()为每个Radio Menu Item定义了一个视觉特效。当Toggle Group中的菜单项被选中时,对应的特效就会被应用在图片上。当No Effects菜单项被选中时,setEffect()方法被赋值为null,没有特效应用在图片上。

图24-5显示了当用户正在选择Shadow菜单项时的运行效果。

图24-5带有三个Radio Menu Item的子菜单

8d0d298b215062efbcb2d08ac96e9339.png

当DropShadow特效被应用在图片上后,其效果如图24-6所示。

图24-6应用了DropShadow特效的Quince的Picture

f468f2c044e13b95248ecaf1fd809d79.png

你可以使用MenuItem类的setDisable()方法在没有Picture Effect子菜单中的特效被选中时禁用No Effects菜单项。将例24-7按照例24-8进行修改。

例24-8禁用菜单项

Java

Menu menuEffect = new Menu("Picture Effect");

final ToggleGroup groupEffect = new ToggleGroup();

for (Entry 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

MenumenuEffect=newMenu("Picture Effect");

finalToggleGroupgroupEffect=newToggleGroup();

for(Entryeffect:effects){

RadioMenuItemitemEffect=newRadioMenuItem(effect.getKey());

itemEffect.setUserData(effect.getValue());

itemEffect.setToggleGroup(groupEffect);

menuEffect.getItems().add(itemEffect);

}

finalMenuItemnoEffects=newMenuItem("No Effects");

noEffects.setDisable(true);

noEffects.setOnAction((ActionEventt)->{

pic.setEffect(null);

groupEffect.getSelectedToggle().setSelected(false);

noEffects.setDisable(true);

});

groupEffect.selectedToggleProperty().addListener(

(ObservableValue<?extendsToggle>ov,Toggleold_toggle,

Togglenew_toggle)->{

if(groupEffect.getSelectedToggle()!=null){

Effecteffect=

(Effect)groupEffect.getSelectedToggle().getUserData();

pic.setEffect(effect);

noEffects.setDisable(false);

}else{

noEffects.setDisable(true);

}

});

menuEdit.getItems().addAll(menuEffect,noEffects);

当没有RadioMenuItem选项被选中时,No Effects菜单项是被禁用的,如图24-7。当用户选择一个视觉特效,No Effects菜单项就会变得可用。

图24-7 No Effects菜单项被禁用

e3d76d0fe5fdc66972a280f0efc8c7b0.png

添加上下文菜单

当你无法分配任何UI空间给一个需要的功能时,你可以使用上下文菜单。上下文菜单是一个弹出窗口,会由一次鼠标点击事件触发显示出来。一个上下文菜单可以包含一个或者多个菜单项。

在Menu Sample应用程序中,为植物的图片设置一个上下文菜单,使得用户可以复制图像。

使用ContextMenu类来创建上下文菜单,见例24-9。

例24-9定义Context Menu

Java

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

finalContextMenucm=newContextMenu();

MenuItemcmItem1=newMenuItem("Copy Image");

cmItem1.setOnAction((ActionEvente)->{

Clipboardclipboard=Clipboard.getSystemClipboard();

ClipboardContentcontent=newClipboardContent();

content.putImage(pic.getImage());

clipboard.setContent(content);

});

cm.getItems().add(cmItem1);

pic.addEventHandler(MouseEvent.MOUSE_CLICKED,(MouseEvente)->{

if(e.getButton()==MouseButton.SECONDARY)

cm.show(pic,e.getScreenX(),e.getScreenY());

});

当用户右击ImageView对象,上下文菜单的show()方法就会被调用使其显示。

为上下文菜单的Copy菜单项定义的setOnAction()方法创建了一个ClipBoard并添加图像作为其内容。图24-8显示了用户正在选择Copy Image上下文菜单项的瞬间。

图24-8使用Context Menu

你可以尝试复制那个图像然后粘贴到一个图像编辑器中。

为了进一步改进,你可以添加更多的菜单项到上下文菜单中并指定不同的动作。你可以使用CustomMenuItem来创建自定义的菜单。通过这个类,你可以将任何Node作为菜单项添加到一个菜单中,比如Button或者Slider等。

相关API文档

· Menu

· MenuItem

· RadioMenuItem

· CheckMenuItem

· ContextMenu

· SeparatorMenuItem

· CustomMenuItem

打赏一下

支付宝

微信

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值