Как извество, у компонент JTextComponent (типа JTextField, JTextArea итд), при нажатии на них правой кнопкой мыши, не появляется всплывающее окно с пунктами "копировать", "вставить", "вырезать" и "отменить". Вот класс, который решает эту проблему:
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.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
import javax.swing.*;
import javax.swing.undo.UndoManager;
import javax.swing.text.JTextComponent;
import javax.swing.text.Document;
import java.util.HashMap;
import java.util.List;
import java.util.Iterator;
import java.awt.event.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.DataFlavor;
import java.awt.*;
/**
* Created by IntelliJ IDEA.
* User: Deady
* Date: 29.06.2006
* Time: 12:15:55
*/
public class DocumentUndoManager {
private static DocumentUndoManager instanse;
private UndoActionListener listener;
private HashMap items = new HashMap();
private EditPopup popup;
private DocumentUndoManager() {
listener = new UndoActionListener();
popup = new EditPopup();
}
public static DocumentUndoManager getInstance() {
if (instanse== null ) {
instanse = new DocumentUndoManager();
}
return instanse;
}
public void registerDocumentHolder(JTextComponent documentHolder) {
//создаем новый менеджер изменений документа
UndoManager undo = new UndoManager();
//запоминаем его для данного текстового поля
items.put(documentHolder, undo);
//получаем модель документа такстового поля
Document doc = documentHolder.getDocument();
//добавляем слушатель изменений документа
doc.addUndoableEditListener(undo);
//добавляем слушатель нажатий клавиш (он будет обрабатывать ctrl+z)
documentHolder.addKeyListener(listener);
//добавляем слушатель нажатий кнопок мыши (он обработает нажатие правой кнопки)
documentHolder.addMouseListener( new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
//если нажата правая кнопка мыши
if (e.getButton()==MouseEvent.BUTTON3) {
//if (e.isPopupTrigger()) { // <-- в линуксе (Fedora Core 5, KDE 3.5.3) это не работает
//устанавливаем текстовый компонент для меню
popup.setDocumentHolder((JTextComponent) e.getSource());
//отображаем всплывающее меню
popup.show((JTextComponent)e.getSource(), e.getX(), e.getY());
}
}
});
}
/**
* очищает историю изменений для текстовых компонент
* @param documentHolders список компонент (из JTextComponent)
*/
public void clearChangeHistory(List documentHolders) {
for (Iterator iterator = documentHolders.iterator(); iterator.hasNext();) {
JTextComponent textComponent = (JTextComponent) iterator.next();
UndoManager manager = (UndoManager) items.get(textComponent);
manager.discardAllEdits();
}
}
class EditPopup extends JPopupMenu {
private JMenuItem copy;
private JMenuItem cut;
private JMenuItem paste;
private JMenuItem undo;
private JTextComponent documentHolder = null ;
public EditPopup() {
copy = new JMenuItem("Копировать");
copy.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (documentHolder!= null ) {
documentHolder.copy();
}
}
});
cut = new JMenuItem("Вырезать");
cut.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (documentHolder!= null ) {
documentHolder.cut();
}
}
});
paste = new JMenuItem("Вставить");
paste.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (documentHolder!= null ) {
documentHolder.paste();
}
}
});
undo = new JMenuItem("Отмена");
undo.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (documentHolder!= null ) {
UndoManager manager = (UndoManager) items.get(documentHolder);
if (manager.canUndo()) {
manager.undo();
}
}
}
});
add(copy);
add(cut);
add(paste);
addSeparator();
add(undo);
}
public void setDocumentHolder(JTextComponent documentHolder) {
this .documentHolder = documentHolder;
//устанавливаем доступность пунктов "копировать" и "вырезать"
if (documentHolder.getSelectedText()!= null && documentHolder.getSelectedText()!= null ) {
copy.setEnabled(true);
cut.setEnabled(true);
}
else {
copy.setEnabled(false);
cut.setEnabled(false);
}
//устанавливаем доступность пункта "вставить"
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
Transferable contents = clipboard.getContents( this );
DataFlavor flavor = DataFlavor.stringFlavor;
if (contents!= null && contents.isDataFlavorSupported(flavor)) {
paste.setEnabled(true);
}
else {
paste.setEnabled(false);
}
//устанавливаем доступность пункта "отмена"
UndoManager manager = (UndoManager) items.get(documentHolder);
if (manager.canUndo()) {
undo.setEnabled(true);
}
else {
undo.setEnabled(false);
}
}
}
class UndoActionListener extends KeyAdapter {
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_Z && e.isControlDown()) {
UndoManager manager = (UndoManager) items.get(e.getSource());
if (manager.canUndo()) {
manager.undo();
}
}
}
}
}
пользоваться им просто: каждое текстовое поле, для которого нужно показывать всплывающее меню, регистрируется в менеджере:
1.
2.
3.
DocumentUndoManager undo = DocumentUndoManager.getInstance();
undo.registerDocumentHolder(textfield1);
undo.registerDocumentHolder(textfield2);
после этого будет появляться меню.
для каждого поля ведется лог изменений. Если необходимо для какого-то поля сбросить лог, вызывается метод clearChangeHistory, параметром ему передается список тех полей, для которых нужно сбросить лог.
1.
2.
3.
4.
5.
6.
DocumentUndoManager undo = DocumentUndoManager.getInstance();
List textHolders = new ArrayList();
textHolders.add(textfield1);
textHolders.add(textfield2);
undo.clearChangeHistory(textHolders);
все. можно в faq.