用Java来做界面开发是难免而且带有些许尴尬的。而由于对C#的讨厌,我便常常处于这样的境地。
虽然Java不及C#或者MFC等通过拖曳组件来构造界面那般方便(据说Netbeans和eclipse的SWT亦支持拖曳组件来构造界面,但我已经习惯了eclipse和swing,因而没有尝试过),开发效率低,但是我仍然希望最后做出了的界面是体验良好的。
之前做了一个工具,需要用一个文本窗口来显示工具的运行日志,本可以直接通过Runtime来调用notepad完成此事,但由于日志文本数目巨大,因此需要在文本窗口载入文本内容后直接将滚动条移至最下,而notepad无法完成此事,于是带着追求完美和锻炼代码能力的心理自己写了个“notepad”。在以往所制作的java界面程序中,一直没有为文本框一类组件提供右键菜单支持,而这次搞自己的“notepad”,总不能仍然连个右键菜单都没有吧!所以趁此次机会,有了下面的结果...
简单的右键菜单实现:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.*;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import javax.swing.text.Position;
/**
* 简单文本操作右键菜单
* @author Dancen
*
*/
public class MyPopupMenu extends JPopupMenu implements MouseListener, ActionListener
{
/**
*
*/
private static final long serialVersionUID = 1L;
private static MyPopupMenu instance = new MyPopupMenu();
private JMenuItem cutItem;
private JMenuItem copyItem;
private JMenuItem pasteItem;
private JMenuItem deleteItem;
private JMenuItem selectAllItem;
public static void main(String[] args)
{
System.out.println("Just for test ...");
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTextField tf0 = new JTextField(10);
MyPopupMenu.installToTextComponent(tf0);
f.add(tf0, BorderLayout.CENTER);
JTextField tf1 = new JTextField(10);
MyPopupMenu.installToTextComponent(tf1);
MyPopupMenu.installToTextComponent(tf1);
MyPopupMenu.uninstallFromTextComponent(tf1);
f.add(tf1, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
/**
* 为文本组件添加右键菜单
* @param textComponent
* @return
*/
public static boolean installToTextComponent(JTextComponent textComponent)
{
boolean isHasInstalled = false;
MouseListener[] listeners = textComponent.getMouseListeners();
if(null != listeners)
{
for(int i = 0; i < listeners.length; i++)
{
if(listeners[i] == MyPopupMenu.getInstance())
{
isHasInstalled = true;
}
}
}
if(!isHasInstalled)
{
textComponent.addMouseListener(MyPopupMenu.getInstance());
return true;
}
return false;
}
/**
* 从文本组件移除右键菜单
* @param textComponent
*/
public static void uninstallFromTextComponent(JTextComponent textComponent)
{
textComponent.removeMouseListener(MyPopupMenu.getInstance());
}
private static MyPopupMenu getInstance()
{
if(null == instance)
{
instance = new MyPopupMenu();
}
return instance;
}
private MyPopupMenu()
{
this.GUIInit();
this.dataInit();
this.listenerInit();
}
private void GUIInit()
{
this.cutItem = new JMenuItem("剪切(T)");
this.copyItem = new JMenuItem("复制(C)");
this.pasteItem = new JMenuItem("粘贴(P)");
this.deleteItem = new JMenuItem("删除(D)");
this.selectAllItem = new JMenuItem("全选(A)");
this.cutItem.setMnemonic('T');
this.copyItem.setMnemonic('C');
this.pasteItem.setMnemonic('P');
this.deleteItem.setMnemonic('D');
this.selectAllItem.setMnemonic('A');
this.add(this.cutItem);
this.add(this.copyItem);
this.add(this.pasteItem);
this.add(this.deleteItem);
this.addSeparator();
this.add(this.selectAllItem);
}
private void dataInit()
{
}
private void listenerInit()
{
this.cutItem.addActionListener(this);
this.copyItem.addActionListener(this);
this.pasteItem.addActionListener(this);
this.deleteItem.addActionListener(this);
this.selectAllItem.addActionListener(this);
}
@Override
public void mouseReleased(MouseEvent e)
{
if(e.isPopupTrigger() && e.getSource() instanceof JTextComponent)
{
JTextComponent textComponent = (JTextComponent) e.getSource();
if(Boolean.TRUE.equals(textComponent.getClientProperty("DisablePopupMenu")))
{
return;
}
textComponent.requestFocusInWindow();
this.show(textComponent, e.getX(), e.getY());
}
}
@Override
public void mouseClicked(MouseEvent e)
{
}
@Override
public void mousePressed(MouseEvent e)
{
}
@Override
public void mouseEntered(MouseEvent e)
{
}
@Override
public void mouseExited(MouseEvent e)
{
}
@Override
public void show(Component invoker, int x, int y)
{
JTextComponent textComponent = (JTextComponent) invoker;
String selectedText = textComponent.getSelectedText();
boolean isTextAvailable = null != selectedText && !selectedText.equals("");
boolean isEnabled = textComponent.isEnabled();
boolean isEditable = textComponent.isEditable();
boolean isPassword = textComponent instanceof JPasswordField;
this.cutItem.setEnabled(isTextAvailable && isEnabled && isEditable && !isPassword);
this.copyItem.setEnabled(isTextAvailable && isEnabled && !isPassword);
this.deleteItem.setEnabled(isTextAvailable && isEnabled && isEditable);
this.pasteItem.setEnabled(isEnabled && isEditable);
this.selectAllItem.setEnabled(isEnabled);
super.show(invoker, x, y);
}
@Override
public void actionPerformed(ActionEvent e)
{
JTextComponent textComponent = (JTextComponent) this.getInvoker();
if(e.getSource() == this.cutItem)
{
textComponent.cut();
}
else if(e.getSource() == this.copyItem)
{
textComponent.copy();
}
else if(e.getSource() == this.pasteItem)
{
textComponent.paste();
}
else if(e.getSource() == this.selectAllItem)
{
textComponent.selectAll();
}
else if(e.getSource() == this.deleteItem)
{
Document doc = textComponent.getDocument();
int start = textComponent.getSelectionStart();
int end = textComponent.getSelectionEnd();
try
{
Position p0 = doc.createPosition(start);
Position p1 = doc.createPosition(end);
if((null != p0) && (null != p1) && (p0.getOffset() != p1.getOffset()))
{
doc.remove(p0.getOffset(), p1.getOffset() - p0.getOffset());
}
}
catch(BadLocationException be)
{
be.printStackTrace();
}
}
}
}