JButton default cursor - java

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");

Related

Drag and Drop from JTable to JLayeredPane

How to create Drag and drop between JTable and JLayeredPane.
Does anyone have any ideas how to implement this?
I need transfer object by Drag and drop between JTable and JLayeredPane.
You have to do a few things at minimum to get this to work:
Call setDragEnabled(true) on your JTable instance
Set the JTables and JLayeredPanes DropTarget
Create a draggable Component to add to the JLayeredPane
To set a Components DropTarget, call the setDropTarget(DropTarget d) method and pass an anonymous inner class as the argument. Code that drops the Transferables data into the Component should be located in the drop(DropTargetDropEvent dtde) method.
The below snippet shows how to receive a Transferable and insert it into the row of a JTable where the drop was initiated:
table.setDropTarget(new DropTarget() {
#Override
public synchronized void drop(DropTargetDropEvent dtde) {
try {
// get row to put new item in
int row = table.rowAtPoint(dtde.getLocation());
// inserting row:
((DefaultTableModel) table.getModel()).insertRow(
//if the row wasn't found, add it to the end of the JTable
row == -1 ? table.getRowCount() : row,
// pass string flavor of transferable data as row data parameter
new Object[] {dtde.getTransferable()
.getTransferData(DataFlavor.stringFlavor)});
} catch(UnsupportedFlavorException | IOException e) {
e.printStackTrace();
}
}
});
This below snippet again receives a Transferable but instead adds it to the end of a JLayeredPane. Note that components are added to the end of the JLayeredPane because I assign a BoxLayout(SwingConstants.VERTICAL) to it.
layeredPane.setDropTarget(new DropTarget() {
#Override
public synchronized void drop(DropTargetDropEvent dtde) {
try {
// create draggable label to add to layered pane
// creating this class will be explained next
final DraggableLabel label = new DraggableLabel(
(String) dtde.getTransferable()
.getTransferData(DataFlavor.stringFlavor));
// add label to layered pane
layeredPane.add(label, JLayeredPane.DEFAULT_LAYER);
layeredPane.revalidate();
layeredPane.repaint();
} catch(UnsupportedFlavorException | IOException e) {
e.printStackTrace();
}
}
});
To create a draggable Component (In this example a JLabel), you must:
Create a new class that extends JLabel and implements DragGestureListener and DragSourceListener
Override all the necessary methods
In the constructor:
Create a new DragSource
Create a DragGestureRecognizer and assign it to this the JLabel subclass and this the DragGestureListener
Start a drag using the DragSource in the dragGestureRecognized(DragGestureEvent evt) method
class DraggableLabel extends JLabel implements DragGestureListener, DragSourceListener {
private DragSource dragSource;
DraggableLabel(String text) {
super(text);
// create the drag source
dragSource = new DragSource();
// assign this component a DragGestureRecognizer
dragSource.createDefaultDragGestureRecognizer(
this, DnDConstants.ACTION_COPY_OR_MOVE, this);
// for contrast with other items in layered pane
setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));
}
#Override
public void dragGestureRecognized(DragGestureEvent evt) {
dragSource.startDrag(
evt, //trigger event
DragSource.DefaultMoveDrop, // icon
new StringSelection(getText()), // transferable data
this); // this the DragSourceListener
}
#Override
public void dragEnter(DragSourceDragEvent evt) {}
#Override
public void dragOver(DragSourceDragEvent evt) {}
#Override
public void dragExit(DragSourceEvent evt) {}
#Override
public void dropActionChanged(DragSourceDragEvent evt) {}
#Override
public void dragDropEnd(DragSourceDropEvent evt) {}
}
Full working example:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDropEvent;
import java.io.IOException;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JTable;
import javax.swing.WindowConstants;
import javax.swing.table.DefaultTableModel;
class DragDropExample {
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
final JFrame frame = new JFrame("JLabel Text Example");
final JTable table = new JTable(new DefaultTableModel(
new Object[][] {
{"Item 1"},
{"Item 2"},
{"Item 3"},
{"Item 4"},
{"Item 5"}},
new String[] {"Column Name"}));
table.setDragEnabled(true);
table.setDropTarget(new DropTarget() {
#Override
public synchronized void drop(DropTargetDropEvent dtde) {
try {
// get row to put new item in
int row = table.rowAtPoint(dtde.getLocation());
// inserting row:
((DefaultTableModel) table.getModel()).insertRow(
//if the row wasn't found, add it to the end of the JTable
row == -1 ? table.getRowCount() : row,
// pass string flavor of transferable data as row data parameter
new Object[] {dtde.getTransferable()
.getTransferData(DataFlavor.stringFlavor)});
} catch(UnsupportedFlavorException | IOException e) {
e.printStackTrace();
}
}
});
final JLayeredPane layeredPane = new JLayeredPane() {
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 300);
}
};
layeredPane.setBorder(BorderFactory.createLineBorder(Color.BLACK));
layeredPane.setLayout(new BoxLayout(layeredPane, BoxLayout.Y_AXIS));
layeredPane.setDropTarget(new DropTarget() {
#Override
public synchronized void drop(DropTargetDropEvent dtde) {
try {
// create draggable label to add to layered pane
// creating this class will be explained next
final DraggableLabel label = new DraggableLabel(
(String) dtde.getTransferable()
.getTransferData(DataFlavor.stringFlavor));
// add label to layered pane
layeredPane.add(label, JLayeredPane.DEFAULT_LAYER);
layeredPane.revalidate();
layeredPane.repaint();
} catch(UnsupportedFlavorException | IOException e) {
e.printStackTrace();
}
}
});
frame.getContentPane().add(table, BorderLayout.WEST);
frame.getContentPane().add(layeredPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
});
}
static class DraggableLabel extends JLabel implements DragGestureListener, DragSourceListener {
private DragSource dragSource;
DraggableLabel(String text) {
super(text);
// create the drag source
dragSource = new DragSource();
// assign this component a DragGestureRecognizer
dragSource.createDefaultDragGestureRecognizer(
this, DnDConstants.ACTION_COPY_OR_MOVE, this);
// for contrast with other items
setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));
}
#Override
public void dragGestureRecognized(DragGestureEvent evt) {
dragSource.startDrag(
evt, //trigger event
DragSource.DefaultMoveDrop,
new StringSelection(getText()),
this);
}
#Override
public void dragEnter(DragSourceDragEvent evt) {}
#Override
public void dragOver(DragSourceDragEvent evt) {}
#Override
public void dragExit(DragSourceEvent evt) {}
#Override
public void dropActionChanged(DragSourceDragEvent evt) {}
#Override
public void dragDropEnd(DragSourceDropEvent evt) {}
}
}
DropTarget dt = new DropTarget(Droptargetobject, new DropTargetAdapter() {
#Override
public void dragEnter(DropTargetDragEvent dtde) {
//executed if mouse with items enters object
}
#Override
public void drop(DropTargetDropEvent dtde) {
//executed if you drop the item
}
});
and to implement the drag use a java.awt.dnd.DragGestureEvent;.
i hope you understand what i mean
imports i used:
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetAdapter;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;

Twoway connection between two swing Documents

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(); });
}
}

KeyListener not working on my object [duplicate]

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.

Why won't my JFrame respond to mouse and window changes?

Here is my code:
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
public class wind extends JFrame implements ComponentListener, MouseListener
{
JButton button;
JLabel label;
public wind()
{
// initialise instance variables
setTitle("My First Window!");
setSize(400, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
JPanel content = new JPanel();
content.setLayout(new FlowLayout());
content.addComponentListener(this);
content.addMouseListener(this);
label = new JLabel("My First Window");
content.add(label);
label.addComponentListener(this);
button = new JButton("Click If You Wish To Live!");
button.addMouseListener(this);
content.add(button)
setContentPane(content);
}
public void componentHidden(ComponentEvent e){
try{wait(100);}
catch(InterruptedException error){}
button.setText("Hidden!");
}
public void componentShown(ComponentEvent e){
try{wait(100);}
catch(InterruptedException error){}
button.setText("Shown!");
}
public void componentResized(ComponentEvent e){
try{wait(100);}
catch(InterruptedException error){}
button.setText("Resized!");
}
public void componentMoved(ComponentEvent e){
try{wait(100);}
catch(InterruptedException error){}
button.setText("Moved!");
}
public void mouseExited(MouseEvent e){
try{wait(100);}
catch(InterruptedException error){}
label.setText("Exited!");
}
public void mouseEntered(MouseEvent e){
try{wait(100);}
catch(InterruptedException error){}
label.setText("Entered!");
}
public void mousePressed(MouseEvent e){
try{wait(100);}
catch(InterruptedException error){}
label.setText("pressed at: "+e.getX()+" "+e.getY());
}
public void mouseReleased(MouseEvent e){
try{wait(100);}
catch(InterruptedException error){}
label.setText("Released!");
label.setLocation(e.getX(), e.getY());
}
public void mouseClicked(MouseEvent e){}
}
It won't respond to the mouse or window re-sizing, hiding, or moving. Furthermore the button is not being displayed. fixed! I am just starting to learn about Java's JFrame and other graphics so I have no idea what's wrong with my code, although I suspect it has something to do with the way I made the button and added the listeners to the objects. Could someone please explain why it does this, and how to fix it. Thank you in advance!
Your problem is that you are using the wait function not correctly. Try to use the class javax.swing.Timer also known as a Swing Timer for delays in Swing programs, for simple animations and for repetitive actions. For more information see this example on stackoverflow: Java Wait Function
One possible way to add a ActionListener to a JButton:
// You are adding an ActionListener to the button
//Using the method addActionListener and a anonymous inner class
button.addActionListener(new ActionListener() {//anonymous inner class
#Override
public void actionPerformed(ActionEvent arg0)
{
button.setText("Text modified by an event called ActionEvent!");
}
});
I decided to play with similar code and came up with this bit of code that tries to show the state of things in a status bar at the bottom:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.AbstractAction;
import javax.swing.AbstractButton;
import javax.swing.Action;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
#SuppressWarnings({ "serial"})
// so the compiler won't complain
public class MyWindPanel extends JPanel {
private static final int PREF_W = 1200;
private static final int PREF_H = 600;
private static final String MOUSE_LOCATION = "Mouse Location [%04d, %04d]";
private static final String COMPONENT_STATE = "Component: %-15s";
private static final String TIMER_LABEL = "Elapsed Time: %02d:%02d:%02d:%03d";
private static final int TIMER_DELAY = 20;
private static final String MOUSE_STATE = "Mouse State: %-15s";
public static final String BUTTON_TEXT = "Set MyWindPanel %s";
private JLabel mouseLocation = new JLabel(
String.format(MOUSE_LOCATION, 0, 0));
private JLabel mouseState = new JLabel(String.format(MOUSE_STATE, ""));
private JLabel componentState = new JLabel(
String.format(COMPONENT_STATE, ""));
private JLabel timerLabel = new JLabel(
String.format(TIMER_LABEL, 0, 0, 0, 0));
private long startTime = System.currentTimeMillis();
private Action buttonAction = new MyButtonAction(String.format(BUTTON_TEXT, "Invisible"));
private JPanel statusPanel;
public MyWindPanel() {
setBackground(Color.pink);
Font font = new Font(Font.MONOSPACED, Font.BOLD, 14);
mouseLocation.setFont(font);
mouseState.setFont(font);
componentState.setFont(font);
timerLabel.setFont(font);
statusPanel = new JPanel();
statusPanel.setLayout(new BoxLayout(statusPanel, BoxLayout.LINE_AXIS));
statusPanel.add(mouseLocation);
statusPanel.add(Box.createHorizontalStrut(25));
statusPanel.add(mouseState);
statusPanel.add(Box.createHorizontalStrut(25));
statusPanel.add(componentState);
statusPanel.add(Box.createHorizontalStrut(25));
statusPanel.add(timerLabel);
new Timer(TIMER_DELAY, new TimerListener()).start();
MouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseMotionListener(myMouseAdapter);
addMouseListener(myMouseAdapter);
addComponentListener(new MyComponentListener());
setLayout(new BorderLayout());
// add(statusPanel, BorderLayout.PAGE_END);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public Action getButtonAction() {
return buttonAction;
}
public JComponent getStatusPanel() {
return statusPanel;
}
private class TimerListener implements ActionListener {
private static final int SECONDS_PER_MIN = 60;
private static final int MSEC_PER_SEC = 1000;
private static final int MIN_PER_HOUR = 60;
#Override
public void actionPerformed(ActionEvent evt) {
if (!MyWindPanel.this.isDisplayable()) {
((Timer) evt.getSource()).stop(); // so timer will stop when program
// over
}
long currentTime = System.currentTimeMillis();
long diff = currentTime - startTime;
int hours = (int) (diff / (MIN_PER_HOUR * SECONDS_PER_MIN * MSEC_PER_SEC));
int minutes = (int) (diff / (SECONDS_PER_MIN * MSEC_PER_SEC))
% MIN_PER_HOUR;
int seconds = (int) ((diff / MSEC_PER_SEC) % SECONDS_PER_MIN);
int mSec = (int) diff % MSEC_PER_SEC;
timerLabel.setText(String.format(TIMER_LABEL, hours, minutes, seconds,
mSec));
}
}
private class MyComponentListener extends ComponentAdapter {
#Override
public void componentHidden(ComponentEvent e) {
componentState.setText(String.format(COMPONENT_STATE, "Hidden"));
}
#Override
public void componentMoved(ComponentEvent e) {
componentState.setText(String.format(COMPONENT_STATE, "Moved"));
}
#Override
public void componentResized(ComponentEvent e) {
componentState.setText(String.format(COMPONENT_STATE, "Resized"));
}
#Override
public void componentShown(ComponentEvent e) {
componentState.setText(String.format(COMPONENT_STATE, "Shown"));
}
}
private class MyButtonAction extends AbstractAction {
public MyButtonAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent e) {
boolean visible = MyWindPanel.this.isVisible();
String text = visible ? "Visible" : "Invisible";
((AbstractButton) e.getSource()).setText(String.format(BUTTON_TEXT, text));
MyWindPanel.this.setVisible(!MyWindPanel.this.isVisible());
Window win = SwingUtilities.getWindowAncestor(MyWindPanel.this);
win.revalidate();
win.repaint();
}
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mouseMoved(MouseEvent e) {
mouseLocation.setText(String.format(MOUSE_LOCATION, e.getX(), e.getY()));
}
#Override
public void mouseDragged(MouseEvent e) {
mouseState.setText(String.format(MOUSE_STATE, "Dragged"));
mouseLocation.setText(String.format(MOUSE_LOCATION, e.getX(), e.getY()));
}
public void mousePressed(MouseEvent e) {
mouseState.setText(String.format(MOUSE_STATE, "Pressed"));
};
public void mouseReleased(MouseEvent e) {
mouseState.setText(String.format(MOUSE_STATE, "Released"));
};
public void mouseEntered(MouseEvent e) {
mouseState.setText(String.format(MOUSE_STATE, "Entered"));
};
public void mouseExited(MouseEvent e) {
mouseState.setText(String.format(MOUSE_STATE, "Exited"));
};
}
private static void createAndShowGui() {
MyWindPanel mainPanel = new MyWindPanel();
JPanel topPanel = new JPanel();
topPanel.add(new JButton(mainPanel.getButtonAction()));
JFrame frame = new JFrame("MyWind");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.getContentPane().add(topPanel, BorderLayout.PAGE_START);
frame.getContentPane().add(mainPanel.getStatusPanel(), BorderLayout.PAGE_END);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Fixing JPopupMenu separators (GTK LaF) and items highlighting

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"));

Categories