I am writing a simple Java swing application. I have two JTextPanes. On the first one I can write a html code and on the second one I see the appearience defined by the code. My goal is to provide two-way connection between this textpanes, so that if I type some characters in one pane, I see the changes in the second pane. And that must work in two ways: I can type in both code pane and content pane and changes should be automatically applied to the other pane.
I have tried to use two DocumentListener objects to handle DocumentEvents, but if I change the content of one pane it fires an event and second pane is modifing and also fires an event and this is repeating all the time, so it's not a good way. Setting the same document instance on both text panes also doesn't work.
What should I do? Here is my code. I have an exception IllegalStateException now.
public class TestEditor extends JFrame {
public TestEditor(){
createConnection();
createGUI();
}
private void createGUI(){
setDefaultCloseOperation(EXIT_ON_CLOSE);
JScrollPane scroll1=new JScrollPane(text);
JScrollPane scroll2=new JScrollPane(html);
JSplitPane split=new JSplitPane();
split.setLeftComponent(scroll1);
split.setRightComponent(scroll2);
split.setDividerLocation(0.5);
split.setResizeWeight(0.5);
getContentPane().add(split);
setTitle("Test");
setPreferredSize(new Dimension(600,300));
pack();
}
private void createConnection(){
text=new JTextPane();
html=new JTextPane();
html.setContentType("text/html");
html.getStyledDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent e) {
text.setText(html.getText());
}
#Override
public void removeUpdate(DocumentEvent e) {
text.setText(html.getText());
}
#Override
public void changedUpdate(DocumentEvent e) {
text.setText(html.getText());
}
});
text.getStyledDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent e) {
html.setText(text.getText());
}
#Override
public void removeUpdate(DocumentEvent e) {
html.setText(text.getText());
}
#Override
public void changedUpdate(DocumentEvent e) {
html.setText(text.getText());
}
});
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new TestEditor().setVisible(true);
}
});
}
private JTextPane text;
private JTextPane html;
}
Try this
import javax.swing.JTextPane;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import java.awt.Container;
import java.awt.GridLayout;
import javax.swing.JSplitPane;
import javax.swing.event.DocumentListener;
import javax.swing.event.DocumentEvent;
import javax.swing.text.html.HTMLDocument;
import java.awt.event.FocusListener;
import java.awt.event.FocusEvent;
public final class TwoWayEditor extends JFrame{
private JTextPane textPane;
private JTextPane viewPane;
private JSplitPane contentPane;
private static DocumentListener textPaneDocumentListener;
private static DocumentListener viewPaneDocumentListener;
#Override
protected void frameInit(){
super.frameInit();
this.setVisible(true);
this.setBounds(0,0,500,500);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.selfInitialize();
}
private void selfInitialize(){
textPane = new JTextPane();
textPane.setContentType("text/plain");
textPane.addFocusListener(new FocusListener(){
#Override
public void focusGained(FocusEvent e){ textPane.getStyledDocument().addDocumentListener(textPaneDocumentListener);}
#Override
public void focusLost(FocusEvent e){ textPane.getStyledDocument().removeDocumentListener(textPaneDocumentListener); }
});
viewPane = new JTextPane();
viewPane.setContentType("text/html");
viewPane.addFocusListener(new FocusListener(){
#Override
public void focusGained(FocusEvent e){viewPane.getStyledDocument().addDocumentListener(viewPaneDocumentListener);}
#Override
public void focusLost(FocusEvent e){viewPane.getStyledDocument().removeDocumentListener(viewPaneDocumentListener);}
});
viewPaneDocumentListener = new DocumentListener(){
#Override
public void changedUpdate(DocumentEvent e){
textPane.setText(viewPane.getText());
}
#Override
public void insertUpdate(DocumentEvent e){ textPane.setText(viewPane.getText());}
#Override
public void removeUpdate(DocumentEvent e){ textPane.setText(viewPane.getText());}
};
textPaneDocumentListener = new DocumentListener(){
#Override
public void changedUpdate(DocumentEvent e){
viewPane.setText(textPane.getText());
}
#Override
public void insertUpdate(DocumentEvent e){ viewPane.setText(textPane.getText()); }
#Override
public void removeUpdate(DocumentEvent e){ viewPane.setText(textPane.getText()); }
};
contentPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,true,textPane,viewPane);
this.setContentPane(contentPane);
contentPane.setDividerLocation(this.getWidth()/2);
}
public static void main(final String [] args){
SwingUtilities.invokeLater(()->{ TwoWayEditor editor = new TwoWayEditor(); });
}
}
Related
I'm trying to check a JFormattedTextField after a value has been entered to make sure it does not match any other values entered in the other similar fields. It becomes a real pain if this check happens repeatedly while the user is typing because I want to provide an error message and I need to implement a number of changes if the value changes. But inputs like 123 will match 12 before the 3 is typed even though no error has really been made yet. Thus the need for a delay. So I'm trying to use a document listener but delay it until the user has validated (as accepted by the text field, by action or shifting focus) the entry.
I thought I had a good method, and it nearly works. My plan was to use a document listener to set up focus and action listeners. Unfortunately, I seem to end up with tons of focus and action listeners since the document listener keeps adding them. That means the error message and subsequent processing happen a ridiculous number of times instead of once. I've tried two work-arounds: 1) remove focus and action listeners before adding new ones, and 2) use a boolean to mark the existence of the focus and action listeners to avoid creating them again.
sscce (I'm new here, should I leave out all the includes?):
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
public class Tester {
private JFrame frame;
private JTextField textField;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Tester window = new Tester();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Tester() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setBounds(50, 50, 200, 50);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
textField = new JTextField("Change this.");
textField.getDocument().addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent e) {
trigger();
}
public void removeUpdate(DocumentEvent e) {
trigger();
}
public void changedUpdate(DocumentEvent e) {
trigger();
}
public void trigger() {
textField.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
}
public void focusLost(FocusEvent e) {
System.out.println("You changed the text to: " + textField.getText());
}
});
textField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("You changed the text to: " + textField.getText());
}
});
}
});
frame.add(textField);
}
}
So attempted fix 1 was to place textField.removeFocusListener(null) and textField.removeActionListener(null) just before the two textField.add... lines. Nothing changed from attempted fix 1. Attempted fix 2 was to create a boolean triggeringEvent outside of trigger() and then start trigger() with if(triggeringEvent == false) { triggeringEvent = true; ... all the focus and action listener lines. Attempted fix 2 just left me with nothing triggering at all.
Thank you for any insight anyone can provide!!!
Edit: I had tried Boann's addChangeListener, but that triggers incessantly, too, and it even triggers when the value hasn't been changed.
Edit: I thought I found a solution by adjusting attempted fix 2, but it fails with more than one JTextField:
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
public class Tester {
private JFrame frame;
private JTextField textField;
private boolean eventTrigger = false;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Tester window = new Tester();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Tester() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setBounds(50, 50, 200, 50);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
textField = new JTextField("Change this.");
textField.getDocument().addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent e) {
if(eventTrigger == false) {
trigger();
}
}
public void removeUpdate(DocumentEvent e) {
if(eventTrigger == false) {
trigger();
}
}
public void changedUpdate(DocumentEvent e) {
}
public void trigger() {
eventTrigger = true;
textField.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
}
public void focusLost(FocusEvent e) {
System.out.println("You changed the text to: " + textField.getText());
eventTrigger = false;
}
});
textField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("You changed the text to: " + textField.getText());
eventTrigger = false;
}
});
}
});
frame.add(textField);
}
}
You can see in this. If you start hopping between fields there are a whole bunch of extra times it triggers. It works fine for the first one you try adjusting, but then it fails.
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
public class Tester {
private JFrame frame;
private JPanel panel;
private JTextField textField1;
private JTextField textField2;
private boolean eventTrigger = false;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Tester window = new Tester();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Tester() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setBounds(50, 50, 200, 100);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new JPanel();
panel.setLayout(new GridLayout(0,1,0,0));
textField1 = new JTextField("Change the first.");
textField2 = new JTextField("Change the second.");
textField1.getDocument().addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent e) {
if(eventTrigger == false) {
trigger();
}
}
public void removeUpdate(DocumentEvent e) {
if(eventTrigger == false) {
trigger();
}
}
public void changedUpdate(DocumentEvent e) {
}
public void trigger() {
eventTrigger = true;
textField1.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
}
public void focusLost(FocusEvent e) {
System.out.println("You changed the text to: " + textField1.getText());
eventTrigger = false;
}
});
textField1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("You changed the text to: " + textField1.getText());
eventTrigger = false;
}
});
}
});
textField2.getDocument().addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent e) {
if(eventTrigger == false) {
trigger();
}
}
public void removeUpdate(DocumentEvent e) {
if(eventTrigger == false) {
trigger();
}
}
public void changedUpdate(DocumentEvent e) {
}
public void trigger() {
eventTrigger = true;
textField2.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
}
public void focusLost(FocusEvent e) {
System.out.println("You changed the text to: " + textField2.getText());
eventTrigger = false;
}
});
textField2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("You changed the text to: " + textField2.getText());
eventTrigger = false;
}
});
}
});
panel.add(textField1);
panel.add(textField2);
frame.add(panel);
}
}
I am trying to make a game engine. I have made the Game class but the error resides in the KeyBoard class. Here I leave some code.
Class:: Game
package transfer2pc.co.cc.game.tileengine;
import java.awt.Graphics;
import java.util.HashMap;
import javax.swing.JPanel;
import transfer2pc.co.cc.game.tileengine.input.KeyBoard;
public abstract class Game extends JPanel implements Runnable {
/**
*
*/
private static final long serialVersionUID = 640206679500196209L;
HashMap<String, ?> maps = null;
KeyBoard keyBoard = null;
public Game(){
super();
keyBoard = new KeyBoard(this);
setKeyBoard(keyBoard);
Thread th = new Thread(this);
th.start();
}
public void run(){
while(true){
repaint();
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public void paint(Graphics g){
}
public void addMap(){
}
public void setMap(){
}
public abstract void keyPressed(int code);
public abstract void keyReleased(int code);
public abstract void keyTyped(int code);
public void setKeyBoard(KeyBoard key){
addKeyListener(key);
}
}
Class:: KeyBoard
package transfer2pc.co.cc.game.tileengine.input;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import transfer2pc.co.cc.game.tileengine.Game;
public class KeyBoard extends KeyAdapter implements KeyListener {
Game game = null;
public KeyBoard(Game gm){
this.game = gm;
}
#Override
public void keyPressed(KeyEvent e) {
System.out.println("KeyPressed");
game.keyPressed(e.getKeyCode());
}
#Override
public void keyReleased(KeyEvent e) {
game.keyReleased(e.getKeyCode());
}
#Override
public void keyTyped(KeyEvent e) {
game.keyTyped(e.getKeyCode());
}
public static char getChar(int key){
return (char)key;
}
}
Class:: KeyTest
package transfer2pc.co.cc.game.tileengine.test;
import java.awt.Graphics;
import javax.swing.JFrame;
import transfer2pc.co.cc.game.tileengine.Game;
import transfer2pc.co.cc.game.tileengine.input.KeyBoard;
public class KeyTest extends Game {
/**
*
*/
private static final long serialVersionUID = 8557676950779023327L;
char pressed;
public KeyTest(){
super();
addKeyListener(new KeyBoard(this));
}
#Override
public void keyPressed(int code) {
pressed = KeyBoard.getChar(code);
}
#Override
public void keyReleased(int code) {
}
#Override
public void keyTyped(int code) {
}
#Override
public void paint(Graphics g){
g.drawString("You pressed: "+pressed, 20, 20);
}
public static void main(String[] args){
JFrame frame = new JFrame("KeyTest");
frame.setSize(640, 480);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.add(new KeyTest());
frame.setVisible(true);
}
}
But the error was there was no exception thrown and the input isn't being read. Could anybody say me the correct way of doing this..
Simply, your panel needs to be focusable. Add in wherever you create the panel:
panel.setFocusable(true);
panel.requestFocusInWindow();
Here's a SSCCE (I suggest asking questions with one of these in the future):
import java.awt.Dimension;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class SimpleKeyTest {
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
frame.getContentPane().add(panel);
panel.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {}
#Override
public void keyReleased(KeyEvent e) {}
#Override
public void keyPressed(KeyEvent e) {
System.out.println("Pressed " + e.getKeyChar());
}
});
panel.setFocusable(true);
panel.requestFocusInWindow();
frame.setSize(new Dimension(300, 300));
frame.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}
Also, https://www.google.com/search?q=jpanel+keylistener
You can add the key listener to the JFrame, that's something I've done in the past.
It's probably not a good idea however if you have other components in the JFrame.
Is there a way to set default cursor of JButton components?
This is how to set cursor for a one JButton:
JButton btn = new JButton("Click me");
btn.setCursor(new Cursor(Cursor.HAND_CURSOR));
According lookAndFeel Nimbus defaults there's no a property like "Button.cursor".
I'd like to set default cursor once so all the JButtons in the app have the same hand-cursor when the mouse cursor moves over.
You can have a custom button that extends the JButton and use that. Some thing like :
MyCustomJButton.java
import java.awt.Cursor;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JButton;
#SuppressWarnings("serial")
public class MyCustomJButton extends JButton implements MouseListener
{
private Cursor defaultCursor;
private Cursor handCursor;
public MyCustomJButton()
{
super();
init();
}
public MyCustomJButton(Action a)
{
super(a);
init();
}
public MyCustomJButton(Icon icon)
{
super(icon);
init();
}
public MyCustomJButton(String text, Icon icon)
{
super(text, icon);
init();
}
public MyCustomJButton(String text)
{
super(text);
init();
}
#Override
public void mouseClicked(MouseEvent e)
{
}
#Override
public void mousePressed(MouseEvent e)
{
}
#Override
public void mouseReleased(MouseEvent e)
{
}
#Override
public void mouseEntered(MouseEvent e)
{
this.setCursor(handCursor);
}
#Override
public void mouseExited(MouseEvent e)
{
this.setCursor(defaultCursor);
}
private void init()
{
defaultCursor = this.getCursor();
handCursor = new Cursor(Cursor.HAND_CURSOR);
addMouseListener(this);
}
}
Once you have implemented your own custom button, you can instantiate it like you would instantiate the JButton.
MyCustomJButton myButton = new MyCustomJButton("My Button");
I've got an interface with 2 JFormattedTextFields for which I need the values (not just the displayed text) to be identical. Ideally they should both be editable, with a change in one being mirrored in the other.
I started by just sharing a single Document between the two, but quickly ran into the problem that this only links the displayed text, not the underlying value. (Silly me!)
I haven't tried adding reciprocal PropertyChangeListeners for the "value" property because I would expect that to set up an infinite loop of modification.
Am I missing something? Is there some way to do this? Or am I stuck with only allowing users to edit one of the two and only having the value propagate in one direction?
Thank you!
I need the values (not just the displayed text) to be identical.
Ideally they should both be editable, with a change in one being
mirrored in the other.
use DocumentListener,
for example (only the one directions)
import java.awt.GridLayout;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
public class TextLabelMirror {
private JPanel mainPanel = new JPanel();
private JTextField field = new JTextField(20);
private JTextField field1 = new JTextField(20);
public TextLabelMirror() {
field.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void changedUpdate(DocumentEvent e) {
updateLabel(e);
}
#Override
public void insertUpdate(DocumentEvent e) {
updateLabel(e);
}
#Override
public void removeUpdate(DocumentEvent e) {
updateLabel(e);
}
private void updateLabel(DocumentEvent e) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
field1.setText(field.getText());
}
});
}
});
mainPanel.setLayout(new GridLayout(1, 0, 10, 0));
mainPanel.add(field);
mainPanel.add(field1);
}
public JComponent getComponent() {
return mainPanel;
}
private static void createAndShowUI() {
JFrame frame = new JFrame("TextLabelMirror");
frame.getContentPane().add(new TextLabelMirror().getComponent());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowUI();
}
});
}
}
You can use a key listener. You simply add a key listener to both fields using the below code. the reason you need the other events is it will throw errors unless you have them in the code.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class CreateGrid
{
JFrame thisframe;
JFormattedTextField jFormattedTextField1, jFormattedTextField2;
public CreateGrid()
{
GridLayout thislayout = new GridLayout(0,2);
thisframe = new JFrame();
thisframe.setLayout(thislayout);
jFormattedTextField1 = new JFormattedTextField();
jFormattedTextField2 = new JFormattedTextField();
jFormattedTextField1.addKeyListener(new KeyAdapter()
{
public void keyReleased(KeyEvent e)
{
JFormattedTextField textField = (JFormattedTextField) e.getSource();
String text = textField.getText();
jFormattedTextField2.setText(text);
}
public void keyTyped(KeyEvent e)
{
}
public void keyPressed(KeyEvent e)
{
}
});
jFormattedTextField2.addKeyListener(new KeyAdapter()
{
public void keyReleased(KeyEvent e)
{
JFormattedTextField textField = (JFormattedTextField) e.getSource();
String text = textField.getText();
jFormattedTextField1.setText(text);
}
public void keyTyped(KeyEvent e)
{
}
public void keyPressed(KeyEvent e)
{
}
});
thisframe.add(jFormattedTextField1);
thisframe.add(jFormattedTextField2);
thisframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
thisframe.setVisible(true);
thisframe.pack();
}
public static void main(String args[])
{
new CreateGrid();
}
}
I have tested this out and it works perfectly what ever you type into one field will show up in the other as you type it.
yesterday I've been using for the first time Swing for a quick desktop application (I'm a fan of swt indeed...).
BTW I came across a couple of problems with JPopupMenu:
1) With GTK LaF, separators are not showing due to a bug.
2) While moving the mouse over menu items, they do not highlight (seen on linux and win)
Here's a variation using MouseAdapter, as well as an sscce for future reference.
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
/** #see http://stackoverflow.com/questions/7254488 */
public class JPopupMenuEx extends JPopupMenu {
private MouseAdapter mouseListener = new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
((JMenuItem) e.getSource()).setArmed(true);
}
#Override
public void mouseExited(MouseEvent e) {
((JMenuItem) e.getSource()).setArmed(false);
}
};
#Override
public void addSeparator() {
add(new JSeparatorEx());
}
#Override
public JMenuItem add(JMenuItem menuItem) {
menuItem.addMouseListener(mouseListener);
return super.add(menuItem);
}
private static class JSeparatorEx extends JSeparator {
#Override
public Dimension getPreferredSize() {
Dimension d = super.getPreferredSize();
if (d.height == 0) {
d.height = 4;
}
return d;
}
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JPopupMenuEx popup = new JPopupMenuEx();
popup.add(new JCheckBoxMenuItem("Item 1"));
popup.addSeparator();
popup.add(new JMenuItem("Item 2"));
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel p = new JPanel();
p.add(new JLabel("Right click for context menu."));
p.setComponentPopupMenu(popup);
f.add(p);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
}
I decided to extend JPopupMenu class in order to fix the two issues above and now I just want to share the code, just in case someone faces the same problem.
import java.awt.Dimension;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;
public class JPopupMenuEx
extends JPopupMenu
implements MouseListener {
/**
*
*/
private static final long serialVersionUID = -5352058505305990803L;
#Override
public void addSeparator() {
add(new JSeparatorEx());
}
#Override
public JMenuItem add(JMenuItem menuItem) {
menuItem.addMouseListener(this);
return super.add(menuItem);
}
#Override
public void mouseEntered(MouseEvent e) {
((JMenuItem)e.getSource()).setArmed(true);
}
#Override
public void mouseExited(MouseEvent e) {
((JMenuItem)e.getSource()).setArmed(false);
}
#Override
public void mouseClicked(MouseEvent e) {}
#Override
public void mousePressed(MouseEvent e) {}
#Override
public void mouseReleased(MouseEvent e) {}
public class JSeparatorEx extends JSeparator{
/**
*
*/
private static final long serialVersionUID = 3477309905456341629L;
public Dimension getPreferredSize() {
Dimension d = super.getPreferredSize();
if (d.height==0)
d.height = 4;
return d;
}
}
}
So you can use it just like using JPopupMenu, like this:
JPopupMenuEx popup = new JPopupMenuEx();
popup.add(new JCheckBoxMenuItem("Item 1"));
popup.addSeparator();
popup.add(new JMenuItem("Item 2"));