++ Swing程序设计 ++ 菜单与工具栏的使用与介绍 12-1:使用JMenuBar组件: JMenuBar的类层次结构图: java.lang.Object --java.awt.Component --java.awt.Container --javax.swing.JComponent --javax.swing.JMenuBar 在介绍JMenu组件前,我们先介绍JMenuBar组件,JMenuBar组件的功能是用来摆入JMenu组件.当我们建立完许多的JMenu组件后, 需要通过JMenuBar组件来将JMenu组件加入到窗口中.虽然我们由下表中看出JMenuBar组件只有一种构造方式,但是它对于构造一个菜 单来说是个不可缺少的组件. JMenuBar构造函数: JMenuBar():建立一个新的JMenuBar; 由于构造一个空的JMenuBar然后设置到窗口上对于窗口来说是没有意义的,因此JMenuBar需要结合至少一个以上的JMenu组件才 会在画面上显现出视觉的效果,所以JMenuBar的构造方法及范例我们留到JMenu的第一个范例中再加以说明. 12-1:使用JMenu组件: JMenu的类层次结构图: java.lang.Object --java.awt.Component --java.awt.Container --javax.swing.JComponent --javax.swing.AbstractButton --javax.swing.JMenuItem --javax.swing.JMenu JMenu组件是用来存放和整合JMenuItem的组件,这个组件也是在构成一个菜单中不可或缺的组件之一.JMenu可以是单一层次的结 构也可以是一个层次式的结构,要使用何种形式的结构取决于界面设计上的需要而定,如下表所示: JMenu构造函数: JMenu():建立一个新的JMenu. JMenu(Action a):建立一个支持Action的新的JMenu. JMenu(String s):以指定的字符串名称建立一个新的JMenu. JMenu(String,Boolean b):以指定的字符串名称建立一个新的JMenu并决定这个菜单是否可以下拉式的属性. 12-1-2:构造JMenu组件: 在看过JMenu的构造函数之后,我们先来看一个具有图标菜单的范例: import javax.swing.*; import java.awt.event.*; import java.awt.*; import java.util.*; import com.incors.plaf.alloy.*; import com.incors.plaf.alloy.themes.glass.*; public class JMenu1 extends JFrame{ JTextArea theArea = null; public JMenu1(){ super("JMenu1"); theArea = new JTextArea(); theArea.setEditable(false); getContentPane().add(new JScrollPane(theArea)); JMenuBar MBar = new JMenuBar(); //调用自行编写的buildFileMenu()方法来构造JMenu. JMenu mfile = buildFileMenu(); MBar.add(mfile); //将JMenu加入JMenuBar中. setJMenuBar(MBar);//将JMenuBar设置到窗口中. }//end of JMenu1() public JMenu buildFileMenu() { JMenu thefile = new JMenu("File"); thefile.setIcon(new ImageIcon("icons/file.gif")); return thefile; }//end of buildFileMenu() public static void main(String[] args){ SwingUtil.setLookAndFeel(); JFrame F = new JMenu1(); F.setSize(400,200); F.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } });//end of addWindowListener F.setVisible(true); } // end of main }//end of class JMenu1 class SwingUtil{ public static final void setLookAndFeel() { try{ Font font = new Font("JFrame", Font.PLAIN, 12); Enumeration keys = UIManager.getLookAndFeelDefaults().keys(); while (keys.hasMoreElements()) { Object key = keys.nextElement(); if (UIManager.get(key) instanceof Font) { UIManager.put(key, font); } } AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true"); AlloyTheme theme = new GlassTheme(); LookAndFeel alloyLnF = new AlloyLookAndFeel(theme); UIManager.setLookAndFeel(alloyLnF); }catch(UnsupportedLookAndFeelException ex){ ex.printStackTrace(); } } } 12-3:使用JMenuItem组件: JMenuItem组件的类层次结构图: java.lang.Object --java.awt.Component --java.awt.Container --javax.swing.JComponent --javax.swing.AbstractButton --javax.swing.JMenuItem JMenuItem继承AbstractButton类,因此JMenuItem具有许多AbstractButton的特性,也可以说JMenuItem是一种特殊的Button,所 以JMenuItem支持许多在Button中好用的功能,例如加入图标文件或是当我们在菜单中选择某一项JMenuItem时就如同按下按钮的操作 一样触发ActionEvent,通过ActionEvent的机制我们就能针对不同的JMenuItem编写其对应的程序区段,我们来看看JMenuItem的构造 方式有哪些: JMenuItem构造函数: JMenuItem():建立一个新的JMenuItem. JMenuItem(Action a):建立一个支持Action的新的JMenuItem. JMenuItem(Icon icon):建立一个有图标的JMenuItem. JMenuItem(String text):建立一个有文字的JMenuItem. JMenuItem(String text,Icon icon):建立一个有图标和文字的JMenuItem. JMenuItem(String text,int mnemonic):建立一个有文字和键盘设置快捷键的JMenuItem. 12-3-1:构造JMenuItem组件: 在看过JMenuItem的构造方式之后,我们来看一个例子了解JMenuItem是如何运作的.这个例子延伸自JMenu1.java,改写 buileFileMenu()方法部份. import javax.swing.*; import java.awt.event.*; import java.awt.*; import java.util.*; import com.incors.plaf.alloy.*; import com.incors.plaf.alloy.themes.glass.*; public class JMenuItem1 extends JFrame{ JTextArea theArea = null; public JMenuItem1(){ super("JMenu1"); theArea = new JTextArea(); theArea.setEditable(true); getContentPane().add(new JScrollPane(theArea)); JMenuBar MBar = new JMenuBar(); JMenu mfile = buildFileMenu(); MBar.add(mfile); setJMenuBar(MBar); }//end of JMenu1() public JMenu buildFileMenu() { JMenu thefile = new JMenu("文件"); JMenuItem newf=new JMenuItem("新建"); JMenuItem open=new JMenuItem("打开"); JMenuItem close=new JMenuItem("关闭"); JMenuItem exit=new JMenuItem("退出"); thefile.add(newf); thefile.add(open); thefile.add(close); thefile.addSeparator();//分隔线 thefile.add(exit); return thefile; }//end of buildFileMenu() public static void main(String[] args){ SwingUtil.setLookAndFeel(); JFrame F = new JMenuItem1(); F.setSize(400,200); F.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } });//end of addWindowListener F.setVisible(true); } // end of main }//end of class JMenu1 class SwingUtil{ public static final void setLookAndFeel() { try{ Font font = new Font("JFrame", Font.PLAIN, 12); Enumeration keys = UIManager.getLookAndFeelDefaults().keys(); while (keys.hasMoreElements()) { Object key = keys.nextElement(); if (UIManager.get(key) instanceof Font) { UIManager.put(key, font); } } AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true"); AlloyTheme theme = new GlassTheme(); LookAndFeel alloyLnF = new AlloyLookAndFeel(theme); UIManager.setLookAndFeel(alloyLnF); }catch(UnsupportedLookAndFeelException ex){ ex.printStackTrace(); } } } 我们在一开始就提到JMenuItem是一个特殊的Button组件,因此我们可以在JMenuItem中加入图标文件来美化界面的显示状态,我 们来看下面这个范例: import javax.swing.*; import java.awt.event.*; import java.awt.*; import java.util.*; import com.incors.plaf.alloy.*; import com.incors.plaf.alloy.themes.glass.*; public class JMenuItem2 extends JFrame{ JTextArea theArea = null; public JMenuItem2(){ super("JMenuItem2"); theArea = new JTextArea(); theArea.setEditable(false); getContentPane().add(new JScrollPane(theArea)); JMenuBar MBar = new JMenuBar(); MBar.setOpaque(true); JMenu mfile = buildFileMenu(); MBar.add(mfile); setJMenuBar(MBar); }//end of JMenuItem2() public JMenu buildFileMenu() { JMenu thefile = new JMenu("File"); JMenuItem newf = new JMenuItem("New",new ImageIcon("icons/new24.gif")); JMenuItem open = new JMenuItem("Open",new ImageIcon("icons/open24.gif")); JMenuItem close= new JMenuItem("Close",new ImageIcon("icons/close24.gif")); JMenuItem quit = new JMenuItem("Exit",new ImageIcon("icons/exit24.gif")); thefile.add(newf); thefile.add(open); thefile.add(close); thefile.addSeparator(); thefile.add(quit); return thefile; }//end of buildFileMenu() public static void main(String[] args){ SwingUtil.setLookAndFeel(); JFrame F = new JMenuItem2(); F.setSize(400,200); F.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } });//end of addWindowListener F.setVisible(true); } // end of main }//end of class JMenuItem2 class SwingUtil{ public static final void setLookAndFeel() { try{ Font font = new Font("JFrame", Font.PLAIN, 12); Enumeration keys = UIManager.getLookAndFeelDefaults().keys(); while (keys.hasMoreElements()) { Object key = keys.nextElement(); if (UIManager.get(key) instanceof Font) { UIManager.put(key, font); } } AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true"); AlloyTheme theme = new GlassTheme(); LookAndFeel alloyLnF = new AlloyLookAndFeel(theme); UIManager.setLookAndFeel(alloyLnF); }catch(UnsupportedLookAndFeelException ex){ ex.printStackTrace(); } } } 运行程序我们可看到在文字左边出现了我们所指定的图标文件.这时我们又会有疑问了,图标文件一定要摆在文字的左边吗?答案 是不一定的!图标在这里会出现在文字左边是因为JMenuItem默认值的关系,我们可以利用setHorizontalTextPosition()方法改变文 字的位置.我们将上面程序的buildFileMenu()方法改写如下: public JMenu buildFileMenu() { JMenu thefile = new JMenu("File"); JMenuItem newf = new JMenuItem("New",new ImageIcon("icons/new24.gif")); JMenuItem open = new JMenuItem("Open",new ImageIcon("icons/open24.gif")); JMenuItem close= new JMenuItem("Close",new ImageIcon("icons/close24.gif")); JMenuItem quit = new JMenuItem("Exit",new ImageIcon("icons/exit24.gif")); //定义文字位置 //在这里我们使用了SwingConstants这个interface,这个interface定义了许多在Swing中常用的数值,由于AbstractButton //类实作了SwingConstants interface,所以我们可以直接使用SwingConstants.LEFT代表JMenuItem组件的最左边界值. newf.setHorizontalTextPosition(SwingConstants.LEFT); open.setHorizontalTextPosition(SwingConstants.LEFT); close.setHorizontalTextPosition(SwingConstants.LEFT); quit.setHorizontalTextPosition(SwingConstants.LEFT); thefile.add(newf); thefile.add(open); thefile.add(close); thefile.addSeparator(); thefile.add(quit); return thefile; }//end of buildFileMenu() 到目前为止我们已经能将一个菜单的外观构造起来,不过我们还少了一个小小的功能,那就是快捷键的设置.快捷键是让我们能使 用键盘来控制菜单并方便操作之用.那么怎么将它加入到菜单中呢?我们来看看下面的范例是怎么实现的. 在JMenuItem2.jav中修改buildFileMenu()方法:操作方式->:[Alt]+快捷键 public JMenu buildFileMenu() { JMenu thefile = new JMenu("File"); thefile.setMnemonic('F'); JMenuItem newf = new JMenuItem("New",new ImageIcon("icons/new24.gif")); JMenuItem open = new JMenuItem("Open",new ImageIcon("icons/open24.gif")); JMenuItem close= new JMenuItem("Close",new ImageIcon("icons/close24.gif")); JMenuItem quit = new JMenuItem("Exit",new ImageIcon("icons/exit24.gif")); newf.setMnemonic('N'); open.setMnemonic('O'); close.setMnemonic('C'); quit.setMnemonic('X'); thefile.add(newf); thefile.add(open); thefile.add(close); thefile.addSeparator(); thefile.add(quit); return thefile; }//end of buildFileMenu() 上面的方法是以[Alt+快捷键]操作,一般的快捷键会设置为[Ctrl]加上某个字符,来直接运行某项功能,要在菜单中加入快捷键很 简单,只需要使用setAccelerator()方法即可,我们来看下面的范例: public JMenu buildFileMenu() { JMenu thefile = new JMenu("File"); thefile.setMnemonic('F'); JMenuItem newf = new JMenuItem("New",new ImageIcon("icons/new24.gif")); JMenuItem open = new JMenuItem("Open",new ImageIcon("icons/open24.gif")); JMenuItem close= new JMenuItem("Close",new ImageIcon("icons/close24.gif")); JMenuItem quit = new JMenuItem("Exit",new ImageIcon("icons/exit24.gif")); newf.setMnemonic('N'); open.setMnemonic('O'); close.setMnemonic('L'); quit.setMnemonic('X'); newf.setAccelerator( KeyStroke.getKeyStroke('N', java.awt.Event.CTRL_MASK, false) ); open.setAccelerator( KeyStroke.getKeyStroke('O', java.awt.Event.CTRL_MASK, false) ); close.setAccelerator( KeyStroke.getKeyStroke('L', java.awt.Event.CTRL_MASK, false) ); quit.setAccelerator( KeyStroke.getKeyStroke('X', java.awt.Event.CTRL_MASK, false) ); thefile.add(newf); thefile.add(open); thefile.add(close); thefile.addSeparator(); thefile.add(quit); return thefile; }//end of buildFileMenu() 说明:利用setAccelerator()方法,分别设置各个JMenuItem的快捷键值.在setAccelerator()方法中使用了KeyStroke类,这个类是 用来管理键盘上的各种信息,我们利用getKeyStroke()方法来指定快捷键的键值.getKeyStroke()方法的三个字段值分别代表键值, 屏蔽键值各放开按键时是否触发事件.在这个范例里我们设置[Ctrl+英文字符]来运行JMenuItem的选项功能. 当然,快捷键的屏蔽键值不一定要是[Ctrl],也可以是[Alt],[Shift]. newf.setAccelerator( KeyStroke.getKeyStroke('N', java.awt.Event.SHIFT_MASK, false) ); open.setAccelerator( KeyStroke.getKeyStroke('O', java.awt.Event.SHIFT_MASK, false) ); close.setAccelerator( KeyStroke.getKeyStroke('L', java.awt.Event.SHIFT_MASK, false) ); quit.setAccelerator( KeyStroke.getKeyStroke('X', java.awt.Event.SHIFT_MASK, false) ); 现在我们已经能够完整的建立一个菜单了,但是我们现在看到的菜单都是单一层次的,如何来建立具有层次式的菜单呢?我们来看 下面的范例: 由于这支程序修改自JMenuItem3.java,由于只修改了bulidMenu()方法,所以在这里我们只列出bulidMenu()方法的程序部份: public JMenu buildFileMenu() { JMenu thefile = new JMenu("File"); thefile.setMnemonic('F'); JMenuItem newf = new JMenuItem("New",new ImageIcon("icons/new24.gif")); JMenuItem open = new JMenuItem("Open",new ImageIcon("icons/open24.gif")); JMenuItem close= new JMenuItem("Close",new ImageIcon("icons/close24.gif")); JMenuItem quit = new JMenuItem("Exit",new ImageIcon("icons/exit24.gif")); newf.setMnemonic('N'); open.setMnemonic('O'); close.setMnemonic('L'); quit.setMnemonic('X'); newf.setAccelerator( KeyStroke.getKeyStroke('N', java.awt.Event.CTRL_MASK, false) ); open.setAccelerator( KeyStroke.getKeyStroke('O', java.awt.Event.CTRL_MASK, false) ); close.setAccelerator( KeyStroke.getKeyStroke('L', java.awt.Event.CTRL_MASK, false) ); quit.setAccelerator( KeyStroke.getKeyStroke('X', java.awt.Event.CTRL_MASK, false) ); JMenu prefMenu = new JMenu("Preferences.."); prefMenu.setMnemonic('P'); JMenuItem setPage = new JMenuItem("setPage",new ImageIcon("icons/setpage24.gif")); JMenuItem setImport = new JMenuItem("Import",new ImageIcon("icons/import24.gif")); JMenuItem setExport = new JMenuItem("Export",new ImageIcon("icons/export24.gif")); setPage.setMnemonic('S'); setImport.setMnemonic('I'); setExport.setMnemonic('E'); setPage.setAccelerator( KeyStroke.getKeyStroke('S', java.awt.Event.CTRL_MASK, false) ); setImport.setAccelerator( KeyStroke.getKeyStroke('I', java.awt.Event.CTRL_MASK, false) ); setExport.setAccelerator( KeyStroke.getKeyStroke('E', java.awt.Event.CTRL_MASK, false) ); prefMenu.add(setPage); prefMenu.add(setImport); prefMenu.add(setExport); thefile.add(newf); thefile.add(open); thefile.add(close); thefile.addSeparator(); thefile.add(prefMenu); thefile.addSeparator(); thefile.add(quit); return thefile; }//end of buildFileMenu() 12-3-2:JMenuItem的事件处理: 由于JMenuItem继承AbstractButton类,因此JMenuItem也具备了许多AbstractButton的特性,当然也包含了事件处理的机制. JMenuItem的事件处理机制是类似JButton的事件处理模式,换名话说,当按下JMenuItem组件时就如同按下JButton组件一般,均会产生 ActionEvent事件,我们来看下面这一范例: JMenuItem5.java import javax.swing.*; import java.awt.event.*; public class JMenuItem5 extends JFrame{ JTextArea theArea=null; public JMenuItem5(){ super("JMenuItem5"); theArea=new JTextArea(); theArea.setEditable(false); getContentPane().add(new JScrollPane(theArea)); JMenuBar MBar=new JMenuBar(); MBar.setOpaque(true); JMenu mfile=buildFileMenu(); MBar.add(mfile); setJMenuBar(MBar); } public JMenu buildFileMenu() { JMenu thefile = new JMenu("File"); thefile.setMnemonic('F'); JMenuItem newf = new JMenuItem("New",new ImageIcon("icons/new24.gif")); JMenuItem open = new JMenuItem("Open",new ImageIcon("icons/open24.gif")); JMenuItem close= new JMenuItem("Close",new ImageIcon("icons/close24.gif")); JMenuItem quit = new JMenuItem("Exit",new ImageIcon("icons/exit24.gif")); newf.setMnemonic('N'); open.setMnemonic('O'); close.setMnemonic('L'); quit.setMnemonic('X'); newf.setAccelerator( KeyStroke.getKeyStroke('N', java.awt.Event.CTRL_MASK, false) ); open.setAccelerator( KeyStroke.getKeyStroke('O', java.awt.Event.CTRL_MASK, false) ); close.setAccelerator( KeyStroke.getKeyStroke('L', java.awt.Event.CTRL_MASK, false) ); quit.setAccelerator( KeyStroke.getKeyStroke('X', java.awt.Event.CTRL_MASK, false) ); newf.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { theArea.append("- MenuItem New Performed -\n"); }}); open.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { theArea.append("- MenuItem Open Performed -\n"); }}); close.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { theArea.append("- MenuItem Close Performed -\n"); }}); quit.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.exit(0); }}); thefile.add(newf); thefile.add(open); thefile.add(close); thefile.addSeparator(); thefile.add(quit); return thefile; }//end of buildFileMenu() public static void main(String[] args){ JFrame F = new JMenuItem5(); F.setSize(400,200); F.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } });//end of addWindowListener F.setVisible(true); } // end of main } 12-4:使用JCheckBoxMenuItem: JCheckBoxMenuItem的类层次结构图: java.lang.Object --java.awt.Component --java.awt.Container --javax.swing.JComponent --javax.swing.AbstractButton --javax.swing.JMenuItem --javax.swing.JCheckBoxMenuItem JCheckBoxMenuItem继承JMenuItem类,因此JCheckBoxMenuItem可以使用JMenuItem所提供的方法,而且JCheckBoxMenuItem也具有 AbstractButton的特性,而JChcekBoxMenuItem和JCheckBox的性质几乎是一样,两者间最大的差别在于JCheckBoxMenuItem是专用在 MenuItem上.我们来看看JCheckBoxMenuItem的构造方法: JCheckBoxMenuItem构造函数: JCheckBoxMenuItem():建立一个新的JCheckBoxMenuItem. JCheckBoxMenuItem(Action a):建立一个支持Action的新的JCheckBoxMenuItem. JCheckBoxMenuItem(Icon icon):建立一个有图标的JCheckBoxMenuItem. JCheckBoxMenuItem(String text):建立一个有文字的JCheckBoxMenuItem. JCheckBoxMenuItem(String text,Boolean b):建立一个有文字和设置选择状态的JCheckBoxMenuItem. JCheckBoxMenuItem(String text,Icon icon):建立一个有文字和图标的JCheckBoxMenuItem. JCheckBoxMenuItem(String text,Icon icon,Boolean b):建立一个有文字,图标和设置状态的JCheckBoxMenuItem. 12-4-1:构造JCheckBoxMenuItem组件: 由上表可以看出JCheckBoxMenuItem的构造方式与JMenuItem的构造方式几乎一模一样,唯一有差异的是JCheckBoxMenuItem的构 造方式中多了设置选择状况的构造方式,设置选择状态就是决定是否要将构造好的JCheckBoxMenuItem组件设置成默认值.我们来看下 面的范例: JCheckBoxMenuItem1.java import javax.swing.*; import java.awt.event.*; import java.util.*; import java.awt.*; import com.incors.plaf.alloy.*; import com.incors.plaf.alloy.themes.glass.*; public class JCheckBoxMenuItem1 extends JFrame implements ActionListener{//由于我们要处理ActionEvent事件,因此要实作 //ActionListener界面. JTextArea theArea = null; public JCheckBoxMenuItem1(){ super("JCheckBoxMenuItem1"); theArea = new JTextArea(); theArea.setEditable(false); getContentPane().add(new JScrollPane(theArea)); JMenuBar MBar = new JMenuBar(); MBar.setOpaque(true); JMenu mfile = buildFileMenu(); JMenu mstyle = buildStyleMenu();//调用buildStyleMenu()方法来建立包含JCheckBoxMenuItem的JMenu. MBar.add(mfile); MBar.add(mstyle); setJMenuBar(MBar); }//end of JCheckBoxMenuItem1() public JMenu buildFileMenu() { JMenu thefile = new JMenu("File"); thefile.setMnemonic('F'); JMenuItem newf = new JMenuItem("New",new ImageIcon("icons/new24.gif")); JMenuItem open = new JMenuItem("Open",new ImageIcon("icons/open24.gif")); JMenuItem close= new JMenuItem("Close",new ImageIcon("icons/close24.gif")); JMenuItem quit = new JMenuItem("Exit",new ImageIcon("icons/exit24.gif")); newf.setMnemonic('N'); open.setMnemonic('O'); close.setMnemonic('L'); quit.setMnemonic('X'); newf.setAccelerator( KeyStroke.getKeyStroke('N', java.awt.Event.CTRL_MASK, false) ); open.setAccelerator( KeyStroke.getKeyStroke('O', java.awt.Event.CTRL_MASK, false) ); close.setAccelerator( KeyStroke.getKeyStroke('L', java.awt.Event.CTRL_MASK, false) ); quit.setAccelerator( KeyStroke.getKeyStroke('X', java.awt.Event.CTRL_MASK, false) ); //将File Menu内的三个JMenuItem对象加入事件处理模式. newf.addActionListener(this); open.addActionListener(this); close.addActionListener(this); quit.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.exit(0); }}); thefile.add(newf); thefile.add(open); thefile.add(close); thefile.addSeparator(); thefile.add(quit); return thefile; }//end of buildFileMenu() public JMenu buildStyleMenu() { //建立新的JMenu组件 JMenu style = new JMenu("Style"); //设置其快捷键 style.setMnemonic('S'); JCheckBoxMenuItem Left = new JCheckBoxMenuItem("Left",new ImageIcon("icons/left24.gif")); JCheckBoxMenuItem Center = new JCheckBoxMenuItem("Center",new ImageIcon("icons/center24.gif")); JCheckBoxMenuItem Right = new JCheckBoxMenuItem("Right",new ImageIcon("icons/right24.gif")); JCheckBoxMenuItem Justify = new JCheckBoxMenuItem("Justify",new ImageIcon("icons/justify24.gif")); Left.setMnemonic('L'); Center.setMnemonic('E'); Right.setMnemonic('R'); Justify.setMnemonic('J'); Left.setAccelerator( KeyStroke.getKeyStroke('L', java.awt.Event.SHIFT_MASK, false) ); Center.setAccelerator( KeyStroke.getKeyStroke('E', java.awt.Event.SHIFT_MASK, false) ); Right.setAccelerator( KeyStroke.getKeyStroke('R', java.awt.Event.SHIFT_MASK, false) ); Justify.setAccelerator( KeyStroke.getKeyStroke('J', java.awt.Event.SHIFT_MASK, false) ); //分别将四个JCheckBoxMenuItem加入事件处理模式. Left.addActionListener(this); Center.addActionListener(this); Right.addActionListener(this); Justify.addActionListener(this); style.add(Left); style.add(Center); style.add(Right); style.add(Justify); return style; }//end of buildStyleMenu() public void actionPerformed(ActionEvent ae){ //为事件处理区段,在这里是将被点选的JMenuItem组件名称填入JTextArea中. try{ theArea.append("* action '"+ae.getActionCommand()+"' performed. *\n"); }catch(Exception e){ System.out.println("actionPerformed Exception:"+e); } } public static void main(String[] args){ SwingUtil.setLookAndFeel(); JFrame F = new JCheckBoxMenuItem1(); F.setSize(400,200); F.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } });//end of addWindowListener F.setVisible(true); } // end of main }//end of class JCheckBoxMenuItem1 class SwingUtil{ public static final void setLookAndFeel() { try{ Font font = new Font("JFrame", Font.PLAIN, 12); Enumeration keys = UIManager.getLookAndFeelDefaults().keys(); while (keys.hasMoreElements()) { Object key = keys.nextElement(); if (UIManager.get(key) instanceof Font) { UIManager.put(key, font); } } AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true"); AlloyTheme theme = new GlassTheme(); LookAndFeel alloyLnF = new AlloyLookAndFeel(theme); UIManager.setLookAndFeel(alloyLnF); }catch(UnsupportedLookAndFeelException ex){ ex.printStackTrace(); } } } 12-5:使用JRadioButtonMenuItem组件: JRadioButtonMenuItem的类层次结构图: java.lang.Object --java.awt.Component --java.awt.Container --javax.swing.JComponent --javax.swing.AbstractButton --javax.swing.JMenuItem --javax.swing.JRadioButtonMenuItem 与JCheckBoxMenuItem相同,JRadioButtonItem也是继承JMenuItem,因此JRadioButtonMenuItem也具备JMenuItem的许多特性.而 JRadioButtonMenuItem和JCheckBoxMenuItem一样也是一种特殊的JMenuItem.我们在前面也介绍过JRadioButton组件,而 JRadioButtonMenuItem是专用在MenuItem上.我们来看看JRadioButtonMenuItem的构造方法,如下表: JRadioButtonMenuItem的构造函数: JRadioButtonMenuItem():建立一个新的JRadioButtonMenuItem. JRadioButtonMenuItem(Action a):建立一个支持Action的新的JRadioButtonMenuItem. JRadioButtonMenuItem(Icon icon):建立一个有图标的JRadioButtonMenuItem. JRadioButtonMenuItem(Icon icon,Boolean selected):建立一个有图标和设置选择状态的JRadioButtonMenuItem. JRadioButtonMenuItem(String text):建立一个有文字的JRadioButtonMenuItem. JRadioButtonMenuItem(String text,Boolean selected):建立一个有文字和设置选择状态的JRadioButtonMenuItem. JRadioButtonMenuItem(String text,Icon icon):建立一个有文字和图标的JRadioButtonMenuItem. JRadioButtonMenuItem(String text,Icon icon,Boolean selected):建立一个有文字,图标和设置状态的JRadioButtonMenuItem. 12-5-1:构造JRadioButtonMenuItem组件: 由一表可以看出JRadioButtonMenuItem的构造方式与JCheckBoxMenuItem构造方式几乎相同,而且和JCheckBoxMenuItem的构造方 式一样都是比JMenuItem的构造方式多了设置选择状况的构造方式,设置选择状态就是决定是否要将构造好的JRadioButtonMenuItem 设置为默认值.我们来看下面这个范例: import javax.swing.*; import java.awt.event.*; public class JRadioButtonMenuItem1 extends JFrame implements ActionListener{ JTextArea theArea = null; public JRadioButtonMenuItem1(){ super("JRadioButtonMenuItem1"); theArea = new JTextArea(); theArea.setEditable(false); getContentPane().add(new JScrollPane(theArea)); JMenuBar MBar = new JMenuBar(); MBar.setOpaque(true); JMenu mfile = buildFileMenu(); JMenu mstyle = buildStyleMenu(); MBar.add(mfile); MBar.add(mstyle); setJMenuBar(MBar); }//end of JRadioButtonMenuItem1() public JMenu buildFileMenu() { JMenu thefile = new JMenu("File"); thefile.setMnemonic('F'); JMenuItem newf = new JMenuItem("New",new ImageIcon("icons/new24.gif")); JMenuItem open = new JMenuItem("Open",new ImageIcon("icons/open24.gif")); JMenuItem close= new JMenuItem("Close",new ImageIcon("icons/close24.gif")); JMenuItem quit = new JMenuItem("Exit",new ImageIcon("icons/exit24.gif")); newf.setMnemonic('N'); open.setMnemonic('O'); close.setMnemonic('L'); quit.setMnemonic('X'); newf.setAccelerator( KeyStroke.getKeyStroke('N', java.awt.Event.CTRL_MASK, false) ); open.setAccelerator( KeyStroke.getKeyStroke('O', java.awt.Event.CTRL_MASK, false) ); close.setAccelerator( KeyStroke.getKeyStroke('L', java.awt.Event.CTRL_MASK, false) ); quit.setAccelerator( KeyStroke.getKeyStroke('X', java.awt.Event.CTRL_MASK, false) ); newf.addActionListener(this); open.addActionListener(this); close.addActionListener(this); quit.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.exit(0); }}); thefile.add(newf); thefile.add(open); thefile.add(close); thefile.addSeparator(); thefile.add(quit); return thefile; }//end of buildFileMenu() public JMenu buildStyleMenu() { JMenu style = new JMenu("Style"); style.setMnemonic('S'); JRadioButtonMenuItem Left = new JRadioButtonMenuItem("Left",new ImageIcon("icons/left24.gif")); JRadioButtonMenuItem Center = new JRadioButtonMenuItem("Center",new ImageIcon("icons/center24.gif")); JRadioButtonMenuItem Right = new JRadioButtonMenuItem("Right",new ImageIcon("icons/right24.gif")); JRadioButtonMenuItem Justify = new JRadioButtonMenuItem("Justify",new ImageIcon("icons/justify24.gif")); Left.setMnemonic('L'); Center.setMnemonic('E'); Right.setMnemonic('R'); Justify.setMnemonic('J'); Left.setAccelerator( KeyStroke.getKeyStroke('L', java.awt.Event.SHIFT_MASK, false) ); Center.setAccelerator( KeyStroke.getKeyStroke('E', java.awt.Event.SHIFT_MASK, false) ); Right.setAccelerator( KeyStroke.getKeyStroke('R', java.awt.Event.SHIFT_MASK, false) ); Justify.setAccelerator( KeyStroke.getKeyStroke('J', java.awt.Event.SHIFT_MASK, false) ); Left.addActionListener(this); Center.addActionListener(this); Right.addActionListener(this); Justify.addActionListener(this); style.add(Left); style.add(Center); style.add(Right); style.add(Justify); return style; }//end of buildStyleMenu() public void actionPerformed(ActionEvent ae){ try{ theArea.append("* action '"+ae.getActionCommand()+"' performed. *\n"); }catch(Exception e){ System.out.println("actionPerformed Exception:"+e); } } public static void main(String[] args){ JFrame F = new JRadioButtonMenuItem1(); F.setSize(400,200); F.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } });//end of addWindowListener F.setVisible(true); } // end of main }//end of class JRadioButtonMenuItem1 在这个范例中我们遇到了与JRadioButton同样的问题,那就是选项的单、复选的问题.一般来说RadioButton组件是用来做单选 的情况时使用,而CheckBox则是多为复选情况时使用.那么我们该怎么来解决这个问题呢?还记得我们介绍JRadioButton时的解决方式 吗?没错,就是要利用ButtonGroup类来处理.我们在JRadioButtonMenuItem1.java的buildStyleMenu()方法中加下下列五行: ButtonGroup bg=new ButtonGroup(); bg.add(Left); bg.add(Center); bg.add(Right); bg.add(Justify); 运行程序我们可看到加入ButtonGroup后的JRadioButtonMenuItem变成只能被单选的菜单. 12-6:使用JToolBar组件: JToolBar的类层次结构图: java.lang.Object --java.awt.Component --java.awt.Container --javax.swing.JComponent --javax.swing.JToolBar ToolBar的功能是用来放置各种常用的功能或控制组件,这个功能在各类软件中都可以很轻易的看到.一般我们在设计软件时,会将 所有功能依类放置在菜单中(JMenu),但当功能数量相当多时,可能造成用户操作一个简单的操作就必须繁复的寻找菜单中相关的功能 ,这将造成用户操作上的负担.若我们能将一般常用的功能以工具栏方式呈现在菜单下,让用户很快得到他想要的功能,不仅增加用户 使用软件的意愿,也加速工作的运行效率.这就是使用ToolBar的好处.我们现在来看看JTooBar的构造方式. JToolBar构造函数: JToolBar():建立一个新的JToolBar,位置为默认的水平方向. JToolBar(int orientation):建立一个指定的JToolBar. JToolBar(String name):建立一个指定名称的JToolBar. JToolBar(String name,int orientation):建立一个指定名称和位置的JToolBar. 12-6-1:构造JToolBar组件: 在使用JToolBar时一般都采用水平方向的位置,因此我们在构造时多是采用上表中的第一种构造方式来建立JToolBar.如果需要 改变方向时再用JToolBar内的setOrientation()方法来改变设置,或是以鼠标拉动的方式来改变JToolBar的位置.我们来看下面的例 子: JToolBar1.java import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.*; import com.incors.plaf.alloy.*; import com.incors.plaf.alloy.themes.glass.*; public class JToolBar1 extends JFrame{ JTextArea theArea = null; static final String ComboStr[] = {"Times New Roman","Dialog","宋体","黑体","楷体"}; public JToolBar1(){ super("JToolBar1"); theArea = new JTextArea(); theArea.setEditable(false); getContentPane().add(new JScrollPane(theArea)); JMenuBar MBar = new JMenuBar(); MBar.setOpaque(true); JMenu mfile = buildFileMenu(); JToolBar theBar = buildToolBar(); this.getContentPane().add(theBar,BorderLayout.NORTH);//将构造好的JToolBar放置到窗口上. MBar.add(mfile);//将JMenu加入到JMenuBar中 setJMenuBar(MBar);//将JMenuBar设置到窗口中. }//end of JToolBar1() public JMenu buildFileMenu() { JMenu thefile = new JMenu("File"); thefile.setMnemonic('F'); JMenuItem newf = new JMenuItem("New",new ImageIcon("icons/new24.gif")); JMenuItem open = new JMenuItem("Open",new ImageIcon("icons/open24.gif")); JMenuItem close= new JMenuItem("Close",new ImageIcon("icons/close24.gif")); JMenuItem quit = new JMenuItem("Exit",new ImageIcon("icons/exit24.gif")); newf.setMnemonic('N'); open.setMnemonic('O'); close.setMnemonic('L'); quit.setMnemonic('X'); newf.setAccelerator( KeyStroke.getKeyStroke('N', java.awt.Event.CTRL_MASK, false) ); open.setAccelerator( KeyStroke.getKeyStroke('O', java.awt.Event.CTRL_MASK, false) ); close.setAccelerator( KeyStroke.getKeyStroke('L', java.awt.Event.CTRL_MASK, false) ); quit.setAccelerator( KeyStroke.getKeyStroke('X', java.awt.Event.CTRL_MASK, false) ); newf.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { theArea.append("- MenuItem New Performed -\n"); }}); open.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { theArea.append("- MenuItem Open Performed -\n"); }}); close.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { theArea.append("- MenuItem Close Performed -\n"); }}); quit.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.exit(0); }}); thefile.add(newf); thefile.add(open); thefile.add(close); thefile.addSeparator(); thefile.add(quit); return thefile; }//end of buildFileMenu() public JToolBar buildToolBar() { JToolBar toolBar = new JToolBar(); toolBar.setFloatable(true);//设置JToolBar可否浮动. //分别构造三个ToolBarAction的类组件,准备将这三个组件设置到JToolBar中.ToolBaarAction类是我们自己编写的inner // class,这个inner class在程序后半部份,这个类继承AbstractAction,AbstractAction是一个抽象类,实现Action //interface,而Action interface又继承ActionListener interface又继承AActionListener interface,因此可直接在 //AbstractAction中覆写actionPerformed()方法,处理ActionEvent事件.在JToolBar中有一个add(Action a)方法,只要传入 //Action参数就可以得到一个JButton对象,因此在程序中下面的98,100,102就是以这样的方式来构造出JToolBar上的按钮组 //件. ToolBarAction tba_new = new ToolBarAction("new",new ImageIcon("icons/new24.gif")); ToolBarAction tba_open = new ToolBarAction("open",new ImageIcon("icons/open24.gif")); ToolBarAction tba_close = new ToolBarAction("close",new ImageIcon("icons/close24.gif")); //99,101,103利用setActionCommand()方法分别设置各个组件被触发事件后所返回的字符串信息. JButton JB; 98 JB = toolBar.add(tba_new);//将ToolBarAction组件加入JToolBar中. 99 JB.setActionCommand("#TooBar_NEW performed!"); 100 JB = toolBar.add(tba_open);//将ToolBarAction组件加入JToolBar中. 101 JB.setActionCommand("#ToolBar_OPEN performed!"); 102 JB = toolBar.add(tba_close);//将ToolBarAction组件加入JToolBar中. 103 JB.setActionCommand("#ToolBar_CLOSE performed!"); toolBar.addSeparator();//在JToolBar加上分隔线,如同在JMenu上利用addSeparator()方法加上分隔线一样,不同的是在 //JMenu中分隔线是以灰色直线的样式表现,而在JToolBar中则是以一小段空来表示. ToolBarAction tba_B = new ToolBarAction("bold",new ImageIcon("icons/bold24.gif")); ToolBarAction tba_I = new ToolBarAction("italic",new ImageIcon("icons/italic24.gif")); ToolBarAction tba_U = new ToolBarAction("underline",new ImageIcon("icons/underline24.gif")); JB = toolBar.add(tba_B);//重复上面的操作 JB.setActionCommand("#ToolBar_Bold performed!"); JB = toolBar.add(tba_I); JB.setActionCommand("#ToolBar_Italic performed!"); JB = toolBar.add(tba_U); JB.setActionCommand("#ToolBar_Underline performed!"); toolBar.addSeparator(); //在JToolBar中加入一个JLabel组件. JLabel JLfont = new JLabel("Font Type"); toolBar.add(JLfont); toolBar.addSeparator(); //利用上面定义的ComboStr数建立一个JComboBox组件. JComboBox jcb = new JComboBox(ComboStr); //将JComboBar加入事件处理模式.这里是将所选到的组件名称填入JTextArea中. jcb.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { theArea.append("*Combobox "+((JComboBox)e.getSource()).getSelectedItem()+" performed!\n"); }}); //在JToolBar中加入一个JComboBox组件. toolBar.add(jcb); return toolBar; }//end of buildToolBar() public static void main(String[] args){ SwingUtil.setLookAndFeel(); JFrame F = new JToolBar1(); F.setSize(430,200); F.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } });//end of addWindowListener F.setVisible(true); } // end of main class ToolBarAction extends AbstractAction{ public ToolBarAction(String name,Icon icon){ super(name,icon); } //对于JToolBar上按钮的事件处理是将组件的ActionCommand返回值字符串加入JTextArea中. public void actionPerformed(ActionEvent e){ try{ theArea.append(e.getActionCommand()+"\n"); }catch(Exception ex){} } }//end of inner class ToolBarAction }//end of class JToolBar1 class SwingUtil{ public static final void setLookAndFeel() { try{ Font font = new Font("JFrame", Font.PLAIN, 12); Enumeration keys = UIManager.getLookAndFeelDefaults().keys(); while (keys.hasMoreElements()) { Object key = keys.nextElement(); if (UIManager.get(key) instanceof Font) { UIManager.put(key, font); } } AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true"); AlloyTheme theme = new GlassTheme(); LookAndFeel alloyLnF = new AlloyLookAndFeel(theme); UIManager.setLookAndFeel(alloyLnF); }catch(UnsupportedLookAndFeelException ex){ ex.printStackTrace(); } } } 在上面这个程序中,我们利用AbstractAction抽象类来构造JToolBar上的JButton组件,这个做法看起来较为陌生,下面我们详细 探讨其中隐含的意义.我们曾提到AbstractAction是一个抽象类,实现Action界面,而Action界面又继承ActionListener界面,因此 AbstractAction类具有侦听ActionEvent的功能,我们可以覆写actionPerformed()方法来处理ActionEvent事件.然而使用 AbstractAction抽象类有什么好处呢?通常一个软件在设计时会因用户习惯,产生不同的操作方式却能达到相同的功能,例如文书编辑 器中,copy功能可能在菜单中出现,也可能在工具栏上出现,甚至在快显菜单(Popup Menu)中出现,虽然出现的方式不一样,但均能达到 copy的功能.若以我们之前的事件处理方法,我们必须为每种出现方式实现copy功能,造成程序代码重复性太高,不易阅读也不美观, 相反的,若我们以AbstractAction抽象类来覆写actionPerformed()方法,我们只需要为每一种功能编写一次程序代码即可,因为 JToolBar,JMenu,JPopupMenu类均有add(Action a)方法,可利用相同的AbstractAction类构造出个别不同的组件.下面范例我们利用 这个概念让用户"按我"选项时,均使用同一个actionPerformed()方法: import javax.swing.*; import java.awt.*; import java.awt.event.*; public class JToolBar2 extends JFrame{ JTextArea theArea = null; ToolBarAction pushAction = null; public JToolBar2(){ super("JToolBar2"); theArea = new JTextArea(); theArea.setEditable(false); getContentPane().add(new JScrollPane(theArea)); JMenuBar MBar = new JMenuBar(); MBar.setOpaque(true); pushAction = new ToolBarAction("按我",null); JMenu mfile = buildFileMenu(); JToolBar theBar = buildToolBar(); this.getContentPane().add(theBar,BorderLayout.NORTH); MBar.add(mfile); setJMenuBar(MBar); }//end of JToolBar2() public JMenu buildFileMenu() { JMenu thefile = new JMenu("File"); thefile.setMnemonic('F'); thefile.add(pushAction); return thefile; }//end of buildFileMenu() public JToolBar buildToolBar() { JToolBar toolBar = new JToolBar(); toolBar.setFloatable(true); toolBar.add(pushAction); return toolBar; }//end of buildToolBar() public static void main(String[] args){ JFrame F = new JToolBar2(); F.setSize(430,200); F.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } });//end of addWindowListener F.setVisible(true); } // end of main class ToolBarAction extends AbstractAction{ public ToolBarAction(String name,Icon icon){ super(name,icon); } public void actionPerformed(ActionEvent e){ try{ theArea.append("不管用哪种方式执行\"按我\",都会出现这句!!"+"\n"); }catch(Exception ex){} } }//end of inner class ToolBarAction }//end of class JToolBar2 说明: 1.利用ToolBarAction类分别建立JToolBar上的JButton与JMenu上的JMenuItem组件,ToolBarAction类继承AbstractAction抽象 类,并覆写actionPerformed()方法.读者在读完JPopupMenu小节后,可将JPopupMenu的功能加入此范例中. 2. 从上面程序中可看出,一般事件处理方式:先产生个别组件,再利用addActionListener()方法侦听ActionEvent事件,最后覆写 actionPerformed()方法.然而以继承AbstractAction抽象类方式处理相同的事件,可以看出程序代码精简许多.读者可比较之间的差 异性. 12-6-2:在JToolBar组件中加入ToolTip: 相信大多数人都有使用过Word文书编辑软件的经验,当我们在使用Word的工具栏时会发现到有一些功能是比较不常用的,而且光 看工具栏上的图标文件也无法立刻得知该图标文件代表什么功能.这时候,我们通常会把鼠标指针移到该图标文件上,稍等待1-2秒后 就会出现一个小提示让我们知道这个图标文件是代表什么意义.这个小提示就是ToolTip. 那么我们在JToolBar中该如何使用这种功能呢?我们来看下面这个范例.这个范例延伸自JToolBar1.java.因此我们只列出 buildToolBar()方法的部份,其他部份的程序都没有改变. public JToolBar buildToolBar() { JToolBar toolBar = new JToolBar(); toolBar.setFloatable(true); ToolBarAction tba_new = new ToolBarAction("new",new ImageIcon("icons/new24.gif")); ToolBarAction tba_open = new ToolBarAction("open",new ImageIcon("icons/open24.gif")); ToolBarAction tba_close = new ToolBarAction("close",new ImageIcon("icons/close24.gif")); JButton JB; JB = toolBar.add(tba_new); //只需要利用setToolTipText()这个方法即可,利用getValue()方法取得各个ToolBarAction类的名称来当作ToolTip显示的字 //符串. JB.setActionCommand("#TooBar_NEW performed!"); JB.setToolTipText((String)tba_new.getValue(Action.NAME)); JB = toolBar.add(tba_open); JB.setActionCommand("#ToolBar_OPEN performed!"); JB.setToolTipText((String)tba_open.getValue(Action.NAME)); JB = toolBar.add(tba_close); JB.setActionCommand("#ToolBar_CLOSE performed!"); JB.setToolTipText((String)tba_close.getValue(Action.NAME)); toolBar.addSeparator(); ToolBarAction tba_B = new ToolBarAction("bold",new ImageIcon("icons/bold24.gif")); ToolBarAction tba_I = new ToolBarAction("italic",new ImageIcon("icons/italic24.gif")); ToolBarAction tba_U = new ToolBarAction("underline",new ImageIcon("icons/underline24.gif")); JB = toolBar.add(tba_B); JB.setActionCommand("#ToolBar_Bold performed!"); JB.setToolTipText((String)tba_B.getValue(Action.NAME)); JB = toolBar.add(tba_I); JB.setActionCommand("#ToolBar_Italic performed!"); JB.setToolTipText((String)tba_I.getValue(Action.NAME)); JB = toolBar.add(tba_U); JB.setActionCommand("#ToolBar_Underline performed!"); JB.setToolTipText((String)tba_U.getValue(Action.NAME)); toolBar.addSeparator(); JLabel JLfont = new JLabel("Font Type"); toolBar.add(JLfont); toolBar.addSeparator(); JComboBox jcb = new JComboBox(ComboStr); jcb.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { theArea.append("*Combobox "+((JComboBox)e.getSource()).getSelectedItem()+" performed! \n"); }}); toolBar.add(jcb); return toolBar; }//end of buildToolBar() 12-7:使用JPopupMenu组件. JPopupMenu的类层次结构图: java.lang.Object --java.awt.Component --java.awt.Container --javax.swing.JComponent --javax.swing.JPopupMenu JPopupMenu是一种特别形式的Menu,其性质与Menu几乎完全相同,但是PopupMenu并不固定在窗口的任何一个位置,而是由鼠标指 针和系统判断决定PopupMenu要出现在哪里.相信大家在使用许多软件时都有用过Popupmenu的功能,例如在使用Word文书编辑器软件 时,当我们在编辑区域的任一处按下鼠标右键,就会跳出一个PopupMenu菜单. JPopupMenu构造函数: JPopupMenu():建立一个新的JPopupMenu; JPopupMenu(String label):建立一个指定标题的JPopupMenu. 12-7-1:构造JPopupMenu组件: 由一表中我们可以知道JPopupMenu的构造方法并不复杂,两种构造方法的差异只在于是否赋予JPopupMenu一个标题文字.我们马上来 看下面这个范例,了解如何应用JPopupMenu. import javax.swing.*; import java.awt.*; import java.awt.event.*; import javax.swing.event.*; import javax.swing.border.*; import java.util.*; import com.incors.plaf.alloy.*; import com.incors.plaf.alloy.themes.glass.*; public class JPopupMenu1 extends JFrame{ JTextArea theArea = null; static final String ComboStr[] = {"Times New Roman","Dialog","宋体","黑体","楷体"}; JPopupMenu Popup = null;//声明一个全局(Global)并设置初始值为null的JPopupMenu组件. public JPopupMenu1(){ super("JPopupMenu1"); theArea = new JTextArea(); theArea.setEditable(false); this.getContentPane().add(new JScrollPane(theArea),BorderLayout.CENTER); JMenuBar MBar = new JMenuBar(); MBar.setOpaque(true); JMenu mfile = buildFileMenu(); JToolBar theBar = buildToolBar(); this.getContentPane().add(theBar,BorderLayout.NORTH); PopupPanel pp = new PopupPanel();//new一个PopupPanel组件来放置JPopupMenu. this.getContentPane().add(pp,BorderLayout.SOUTH); //将PopupPanel组件放置到窗口中. MBar.add(mfile); setJMenuBar(MBar); }//end of JPopupMenu1() /*****************begin********************** 分别建立程序中菜单,工具栏和事件处理模式的部份,我们在此不再加以说明. ****************************************/ public JMenu buildFileMenu() { JMenu thefile = new JMenu("File"); thefile.setMnemonic('F'); JMenuItem newf = new JMenuItem("New",new ImageIcon("icons/new24.gif")); JMenuItem open = new JMenuItem("Open",new ImageIcon("icons/open24.gif")); JMenuItem close= new JMenuItem("Close",new ImageIcon("icons/close24.gif")); JMenuItem quit = new JMenuItem("Exit",new ImageIcon("icons/exit24.gif")); newf.setMnemonic('N'); open.setMnemonic('O'); close.setMnemonic('L'); quit.setMnemonic('X'); newf.setAccelerator( KeyStroke.getKeyStroke('N', java.awt.Event.CTRL_MASK, false) ); open.setAccelerator( KeyStroke.getKeyStroke('O', java.awt.Event.CTRL_MASK, false) ); close.setAccelerator( KeyStroke.getKeyStroke('L', java.awt.Event.CTRL_MASK, false) ); quit.setAccelerator( KeyStroke.getKeyStroke('X', java.awt.Event.CTRL_MASK, false) ); newf.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { theArea.append("- MenuItem New Performed -\n"); }}); open.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { theArea.append("- MenuItem Open Performed -\n"); }}); close.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { theArea.append("- MenuItem Close Performed -\n"); }}); quit.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.exit(0); }}); thefile.add(newf); thefile.add(open); thefile.add(close); thefile.addSeparator(); thefile.add(quit); return thefile; }//end of buildFileMenu() public JToolBar buildToolBar() { JToolBar toolBar = new JToolBar(); toolBar.setFloatable(true); ToolBarAction tba_new = new ToolBarAction("new",new ImageIcon("icons/new24.gif")); ToolBarAction tba_open = new ToolBarAction("open",new ImageIcon("icons/open24.gif")); ToolBarAction tba_close = new ToolBarAction("close",new ImageIcon("icons/close24.gif")); JButton JB; JB = toolBar.add(tba_new); JB.setActionCommand("#TooBar_NEW performed!"); JB.setToolTipText((String)tba_new.getValue(Action.NAME)); JB = toolBar.add(tba_open); JB.setActionCommand("#ToolBar_OPEN performed!"); JB.setToolTipText((String)tba_open.getValue(Action.NAME)); JB = toolBar.add(tba_close); JB.setActionCommand("#ToolBar_CLOSE performed!"); JB.setToolTipText((String)tba_close.getValue(Action.NAME)); toolBar.addSeparator(); ToolBarAction tba_B = new ToolBarAction("bold",new ImageIcon("icons/bold24.gif")); ToolBarAction tba_I = new ToolBarAction("italic",new ImageIcon("icons/italic24.gif")); ToolBarAction tba_U = new ToolBarAction("underline",new ImageIcon("icons/underline24.gif")); JB = toolBar.add(tba_B); JB.setActionCommand("#ToolBar_Bold performed!"); JB.setToolTipText((String)tba_B.getValue(Action.NAME)); JB = toolBar.add(tba_I); JB.setActionCommand("#ToolBar_Italic performed!"); JB.setToolTipText((String)tba_I.getValue(Action.NAME)); JB = toolBar.add(tba_U); JB.setActionCommand("#ToolBar_Underline performed!"); JB.setToolTipText((String)tba_U.getValue(Action.NAME)); toolBar.addSeparator(); JLabel JLfont = new JLabel("Font Type"); toolBar.add(JLfont); toolBar.addSeparator(); JComboBox jcb = new JComboBox(ComboStr); jcb.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { theArea.append("*Combobox "+((JComboBox)e.getSource()).getSelectedItem()+" performed!\n"); }}); toolBar.add(jcb); return toolBar; }//end of buildToolBar() /*****************End********************** 分别建立程序中菜单,工具栏和事件处理模式的部份,我们在此不再加以说明. ****************************************/ public static void main(String[] args){ SwingUtil.setLookAndFeel(); JFrame F = new JPopupMenu1(); F.setSize(430,200); F.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } });//end of addWindowListener F.setVisible(true); } // end of main class ToolBarAction extends AbstractAction{ public ToolBarAction(String name,Icon icon){ super(name,icon); } public void actionPerformed(ActionEvent e){ try{ theArea.append(e.getActionCommand()+"\n"); }catch(Exception ex){} } }//end of inner class ToolBarAction /*本方法建立inner class PopupPanel.这个类继承JPanel并实作MouseListener,PopupMenuListener,ActionListener和 *ActionListener等3个Listener.MouseListener为处理鼠标事件的Listener,PopupMenuListener为Popup菜单事件的Listener, *ActionListener则是大家最熟悉用来处理JMenuItem事件的Listener. */ class PopupPanel extends JPanel implements MouseListener,PopupMenuListener,ActionListener{ public PopupPanel(){ Popup = new JPopupMenu();//new 一个新的JPopupMenu. JMenuItem theItem; //分别建立四个JMenuItem和其事件处理模式将将JMenuItem加入JPopupMenu中. Popup.add(theItem = new JMenuItem("Cut",new ImageIcon("icons/cut24.gif")));//建立JMenuItem组件. theItem.addActionListener(this);//将JMenuItem组件加入事件处理模式. Popup.add(theItem = new JMenuItem("Copy",new ImageIcon("icons/copy24.gif"))); theItem.addActionListener(this); Popup.add(theItem = new JMenuItem("Paste",new ImageIcon("icons/paste24.gif"))); theItem.addActionListener(this); Popup.addSeparator();//在JPopupMenu中加入分隔线,我们在前面有提到JPopupMenu和Menu大致上的性质是一样的,所以 //在JPopupMenu中一样是以JMenuItem来当作选项的组件. Popup.add(theItem = new JMenuItem("Page Setup...")); theItem.addActionListener(this); //利用setBorder()方法将BevelBorder类当作参数传入,使JPopupMenu产生立体边框浮起的效果.我们也可以将参数设置改 //为BevelBorder.LOWERED使得JPopupMenu产生立体边框凹陷的效果. Popup.setBorder(new BevelBorder(BevelBorder.RAISED)); Popup.addPopupMenuListener(this); //将JPopupMenu组件加入PopupMenu事件处理模式中. addMouseListener(this);//将PopupPanel类加入Mouse事件处理模式中. theArea.addMouseListener(this);//后面有说明 }//end of PopupPanel() /*由于PopupPanel这个inner class中实作了MouseListener,因此需要覆写mouseClicked(),mousePressed(), *mouseReleased(),mouseEntered()和mouseExited()等5个方法.在这个范例里当mouseClicked(),mousePressed() *和mouseReleased()等3个方法被触发时会调用checkPopup()方法来判断是否要将PopupMenu输出来. */ public void mouseClicked(MouseEvent me){ checkPopup(me);} public void mousePressed(MouseEvent me){ checkPopup(me);} public void mouseReleased(MouseEvent me){ checkPopup(me);} public void mouseEntered(MouseEvent me){} public void mouseExited(MouseEvent me){} /*checkPopup()方法.其中,在程序中利用isPopupTrigger()方法判断PopupMenu是否已经输出.若没有,则在程序中利用 *show()方法将PopupMenu输出目前鼠标指针(利用getX()和getY()方法得知)的位置上. */ private void checkPopup(MouseEvent me){ if(me.isPopupTrigger()){ Popup.show(me.getComponent(), me.getX(), me.getY()); } }//end of checkPopup() /*由于PopupPanel这个inner class实作了PopupMenuListener,因此需要覆写popupMenuWillBecomeVisible(), *popupMenuWillBecomeInvisible()方法和popupMenuCanceled()等3个方法.在这个范例里当这3个方法被触 *发后会在JTextArea中加入一个信息. */ public void popupMenuWillBecomeVisible(PopupMenuEvent pme){ theArea.append("-PopupMenu Visibel!\n"); } public void popupMenuWillBecomeInvisible(PopupMenuEvent pme){ theArea.append("-PopupMenu Invisibel!\n"); } public void popupMenuCanceled(PopupMenuEvent pme){ theArea.append("-PopupMenu Hidden!\n"); } //当某个JMenuItem被触发后会在JTextArea中加入一个信息. public void actionPerformed(ActionEvent ae){ theArea.append("+Popup "+ae.getActionCommand()+" performed!\n"); } }//end of inner class PopupPanel }//end of class JPopupMenu1 class SwingUtil{ public static final void setLookAndFeel() { try{ Font font = new Font("JFrame", Font.PLAIN, 12); Enumeration keys = UIManager.getLookAndFeelDefaults().keys(); while (keys.hasMoreElements()) { Object key = keys.nextElement(); if (UIManager.get(key) instanceof Font) { UIManager.put(key, font); } } AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true"); AlloyTheme theme = new GlassTheme(); LookAndFeel alloyLnF = new AlloyLookAndFeel(theme); UIManager.setLookAndFeel(alloyLnF); }catch(UnsupportedLookAndFeelException ex){ ex.printStackTrace(); } } } 说明:(1):由于JPopupMenu只是一种Menu的组件,因此在使用JPopupMenu时我们都需要一个Container来放置JPopupMenu,在这里这们 选择使用JPanel组件来作为JPopupMenu的Container. (2):这个程序的运行结果可发现JPopupMenu只有在JTextArea下缘,也就是JPanel的部份才有作用,因为我们并没有在JTextArea 中加入addMouseListener()方法,你可以在PopupPanel()构造函数中加入: theArea.addMouseListener(this); 这行,就能够解决在JTextArea上无法显示JPopupMenu的问题. |