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() 方法将 BevelBorde r类当作参数传入,使 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 的问题。