Reputation: 1019
I've made a program which prints a value in a text field. The problem is that when a user right clicks in the text field, a menu like this won't open:
Is there a way the user can have this menu open upon right click?
This is my code:
public class A extends JFrame{
private JTextField txt1;
private JTextField txt2;
private JLabel val;
private JLabel prt;
private JButton bt1;
public A() {
getContentPane().setLayout(null);
txt1 = new JTextField();
txt1.setBounds(178, 93, 87, 28);
getContentPane().add(txt1);
txt2 = new JTextField();
txt2.setBounds(178, 148, 87, 28);
getContentPane().add(txt2);
val = new JLabel("Enter Value");
val.setBounds(84, 93, 69, 28);
getContentPane().add(val);
prt = new JLabel("Printed Value");
prt.setBounds(80, 148, 87, 28);
getContentPane().add(prt);
bt1 = new JButton("Click This");
bt1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
int n=Integer.parseInt(txt1.getText());
txt2.setText(n+"");
}
});
bt1.setBounds(178, 188, 105, 28);
getContentPane().add(bt1);
setSize(400, 399);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
}
}
Main Method:
public class Main {
public static void main(String[] args) {
A object = new A();
}
}
Upvotes: 3
Views: 14104
Reputation: 3422
I created my own twist on Karlo Kokkak's answer which will enable/disable menu items when applicable. This one takes into account the state of the system clipboard, the selection state of the text field, and the state of the undo manager:
public class StandardTextFieldMenu {
private JTextField field;
private JPopupMenu popup = new JPopupMenu();
private UndoManager undoManager = new UndoManager();
private Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
private Action undoAction;
private Action redoAction;
private Action copyAction;
private Action cutAction;
private Action pasteAction;
private Action selectAllAction;
private StandardTextFieldMenu(JTextField field) {
this.field = field;
this.undoAction = new AbstractAction("Undo") {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent ae) {
StandardTextFieldMenu.this.undoManager.undo();
StandardTextFieldMenu.this.validateUndo();
}
};
this.redoAction = new AbstractAction("Redo") {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent ae) {
StandardTextFieldMenu.this.undoManager.redo();
StandardTextFieldMenu.this.validateUndo();
}
};
this.copyAction = new AbstractAction("Copy") {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent ae) {
field.requestFocus();
field.copy();
}
};
this.cutAction = new AbstractAction("Cut") {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent ae) {
field.requestFocus();
field.cut();
}
};
this.pasteAction = new AbstractAction("Paste") {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent ae) {
field.requestFocus();
field.paste();
}
};
this.selectAllAction = new AbstractAction("Select All") {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent ae) {
field.requestFocus();
field.selectAll(); // Doesn't fire CaretEvent so following line is necessary
StandardTextFieldMenu.this.validateSelection();
}
};
this.validateClipboard();
this.validateSelection();
this.validateUndo();
this.clipboard.addFlavorListener(e -> this.validateClipboard());
field.addCaretListener(e -> this.validateSelection());
field.getDocument().addUndoableEditListener(e -> {
this.undoManager.undoableEditHappened(e);
this.validateUndo();
});
this.undoAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("control Z"));
this.redoAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("control Y"));
this.cutAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("control X"));
this.copyAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("control C"));
this.pasteAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("control V"));
this.selectAllAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("control A"));
this.popup.add(this.undoAction);
this.popup.add(this.redoAction);
this.popup.addSeparator();
this.popup.add(this.cutAction);
this.popup.add(this.copyAction);
this.popup.add(this.pasteAction);
this.popup.addSeparator();
this.popup.add(this.selectAllAction);
field.setComponentPopupMenu(this.popup);
}
private void validateClipboard() {
this.pasteAction.setEnabled(
Arrays.stream(this.clipboard.getAvailableDataFlavors()).anyMatch(DataFlavor::isFlavorTextType));
}
private void validateSelection() {
boolean enabled = this.field.getSelectionEnd() - this.field.getSelectionStart() > 0;
this.copyAction.setEnabled(enabled);
this.cutAction.setEnabled(enabled);
}
private void validateUndo() {
this.undoAction.setEnabled(this.undoManager.canUndo());
this.redoAction.setEnabled(this.undoManager.canRedo());
}
public static void register(JTextField field) {
new StandardTextFieldMenu(field);
}
}
Also, shout out to MadProgrammer for finding a way to listen for text selections. This guy is a mad Swing genius.
Upvotes: 0
Reputation: 3714
Static class to instantly add regular popup menu to a textfield.
import javax.swing.*;
import java.awt.event.ActionEvent;
import javax.swing.undo.*;
public class JTextFieldRegularPopupMenu {
public static void addTo(JTextField txtField)
{
JPopupMenu popup = new JPopupMenu();
UndoManager undoManager = new UndoManager();
txtField.getDocument().addUndoableEditListener(undoManager);
Action undoAction = new AbstractAction("Undo") {
@Override
public void actionPerformed(ActionEvent ae) {
if (undoManager.canUndo()) {
undoManager.undo();
}
else {
System.out.println("No Undo Buffer.");
}
}
};
Action copyAction = new AbstractAction("Copy") {
@Override
public void actionPerformed(ActionEvent ae) {
txtField.copy();
}
};
Action cutAction = new AbstractAction("Cut") {
@Override
public void actionPerformed(ActionEvent ae) {
txtField.cut();
}
};
Action pasteAction = new AbstractAction("Paste") {
@Override
public void actionPerformed(ActionEvent ae) {
txtField.paste();
}
};
Action selectAllAction = new AbstractAction("Select All") {
@Override
public void actionPerformed(ActionEvent ae) {
txtField.selectAll();
}
};
cutAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("control X"));
copyAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("control C"));
pasteAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("control V"));
selectAllAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("control A"));
popup.add (undoAction);
popup.addSeparator();
popup.add (cutAction);
popup.add (copyAction);
popup.add (pasteAction);
popup.addSeparator();
popup.add (selectAllAction);
txtField.setComponentPopupMenu(popup);
}
}
Usage:
JTextFieldRegularPopupMenu.addTo(jTxtMsg);
Instantly adds popup menu to the chosen JTextFIeld.
Upvotes: 6
Reputation: 324118
Read the Swing tutorial on How to Use Menus for the basics of creating a popup menu.
Then you can use the Actions
provided by the DefaultEditorKit
to create your popup menu.
For the "Delete" action you will need to create your own custom Action. Read the Swing tutorial on How to Use Actions for the basics. Except you would extend TextAction
since it has methods that allow you to access the text component with focus so you can create reusable code.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
public class TextFieldPopup extends JPanel
{
public TextFieldPopup()
{
JTextField textField = new JTextField(10);
add( textField );
JPopupMenu menu = new JPopupMenu();
Action cut = new DefaultEditorKit.CutAction();
cut.putValue(Action.NAME, "Cut");
cut.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("control X"));
menu.add( cut );
Action copy = new DefaultEditorKit.CopyAction();
copy.putValue(Action.NAME, "Copy");
copy.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("control C"));
menu.add( copy );
Action paste = new DefaultEditorKit.PasteAction();
paste.putValue(Action.NAME, "Paste");
paste.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("control V"));
menu.add( paste );
Action selectAll = new SelectAll();
menu.add( selectAll );
textField.setComponentPopupMenu( menu );
}
static class SelectAll extends TextAction
{
public SelectAll()
{
super("Select All");
putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("control S"));
}
public void actionPerformed(ActionEvent e)
{
JTextComponent component = getFocusedComponent();
component.selectAll();
component.requestFocusInWindow();
}
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("TextFieldPopup");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new TextFieldPopup() );
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
Upvotes: 14
Reputation: 347204
I'd start with How to use menus and Bringing Up a Popup Menu (although I'd personally use JComponent#setComponentPopupMenu
instead of a MouseListener
)
Then I'd have a look at JTextField#copy
, JTextField#cut
and JTextField#paste
Upvotes: 2