override actionPerformed on JMenu - java

I am trying to make a pop up window appear when the user clicks on the About menu.
Is that possible to do in Java? I have seen that clicking on a menu does not invoke actionPerformed. After a bit of searching i found that i should try to use this:
new AbstractAction("Do XY")
but NetBeans tells me that an identifier is expected. Is there any other way to do this, or does Java not allow buttons directly on the Menu bar?

Of course you can do this in Java. You could simply add a MenuListener to your menu.
Here is an example of such thing (it also implements the traditional "About" menu item):
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.SwingUtilities;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;
public class TestAboutMenu {
protected void initUI() {
final JFrame frame = new JFrame("test");
JMenuBar bar = new JMenuBar();
JMenu help = new JMenu("Help");
help.addMenuListener(new MenuListener() {
#Override
public void menuSelected(MenuEvent e) {
showAboutDialog(frame);
}
#Override
public void menuDeselected(MenuEvent e) {
// TODO Auto-generated method stub
}
#Override
public void menuCanceled(MenuEvent e) {
// TODO Auto-generated method stub
}
});
JMenuItem about = new JMenuItem(new AbstractAction("About") {
#Override
public void actionPerformed(ActionEvent e) {
showAboutDialog(frame);
}
});
help.add(about);
bar.add(help);
frame.setJMenuBar(bar);
frame.setSize(400, 400);
frame.setVisible(true);
}
protected void showAboutDialog(final JFrame frame) {
JDialog dialog = new JDialog(frame);
dialog.add(new JLabel("About this program"));
dialog.setModal(true);
dialog.pack();
dialog.setLocationRelativeTo(frame);
dialog.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestAboutMenu().initUI();
}
});
}
}

To do it you would propably need to write your own Menu bar class. But you could do such trick: Write mouse listener with mouseClicked() method. If you place your menu bar on top then you know it's bounds are: 0, windowWidth(), ~20 (menu bar height), windowWidth(). And then you check if position of mouse is in this rectangle. If yes - you show pop-up window. It's just on the spot idea so let me know if it works for you.

Related

Get the in-focus tab after closing a tab

In a JTabbedPane, I associated a custom-made Data object to each added tab. I also have a corresponding Metadata object that shows up in another panel when the tab is selected. The problem I have now is when a tab is closed, the metadata panel shows the metadata of the Data object in the tab that just gets closed. Ideally, I want the panel to show the metadata for the in-focus tab that the user sees. However, the act of closing a tab means the “selected tab” is the tab being closed, so tabpane.getSelectedIndex() would not work. How can I get the tab that is in focus after closing a tab? Thank you in advance!
Devil is in the detail, which you provided none.
I did a quick test and discovered that, ChangeListener is called before ContainerListener, which is a real pain, but, it was always reporting the correct index.
So, what you need to do is marry the two together, so that, both will update the meta data pane when they are called.
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JTabbedPane tabbedPane = new JTabbedPane();
tabbedPane.addTab("One", new TabPane(tabbedPane));
tabbedPane.addTab("Two", new TabPane(tabbedPane));
tabbedPane.addTab("Three", new TabPane(tabbedPane));
tabbedPane.addTab("Four", new TabPane(tabbedPane));
tabbedPane.addContainerListener(new ContainerListener() {
#Override
public void componentAdded(ContainerEvent e) {
}
#Override
public void componentRemoved(ContainerEvent e) {
System.out.println("Removed " + e.getChild());
}
});
tabbedPane.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
System.out.println(tabbedPane.getSelectedIndex());
}
});
JFrame frame = new JFrame();
frame.add(tabbedPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TabPane extends JPanel {
private JTabbedPane parent;
public TabPane(JTabbedPane parent) {
this.parent = parent;
setLayout(new GridBagLayout());
JButton btn = new JButton("Close");
add(btn);
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
parent.remove(TabPane.this);
}
});
}
}
}

How to use a JPanel as JButton?

I must use a swing-ui designer tool to create my UI, that only supports graphically editing JPanels. Those panels (they basically contain complex button designs) to work like a JButton. I cannot use anything other than JPanel as base class of these panels (UI editor limitation).
What is the most generic solution to do this?
Create a custom button that uses the panel's draw method instead of
it's own?
Create a base-panel class that reimplements the whole
button?
Another more elegant solution?
Here is a quick demo, to show you how you could use borders to simulate a button.
The demo also reacts to mouse and key events :
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.Border;
import javax.swing.border.EtchedBorder;
public class JPanelButton extends JPanel {
Border raisedetched = BorderFactory.createEtchedBorder(EtchedBorder.RAISED);
Border loweredetched = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED);
public static void main(final String[] args) {
JFrame frame = new JFrame();
final JPanelButton panel = new JPanelButton();
panel.raiseBorder();
panel.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(final MouseEvent e) {
panel.lowerBorder();
}
#Override
public void mouseReleased(final MouseEvent e) {
panel.raiseBorder();
}
});
panel.setFocusable(true); // you need this or the panel won't get the key events
panel.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(final KeyEvent e) {
panel.lowerBorder();
}
#Override
public void keyReleased(final KeyEvent e) {
panel.raiseBorder();
}
});
frame.setContentPane(panel);
frame.setSize(100, 100);
frame.setVisible(true);
}
public void raiseBorder() {
setBorder(raisedetched);
}
public void lowerBorder() {
setBorder(loweredetched);
}
}
Simply add MouseListener.
JPanel jp = new JPanel();
jp.addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent e) {
System.out.println("Clicked");
}
});
If this answer isn't specific enough, leave a comment and I'll give you more explanation.

Update a JPopupMenu menu items while it is open

In my UI i have a JPopMenu with values as ,
for e.g A,B,C
The scenario is,
I opened the JPopupMenu and kept it open.
At back end with a timer running , it updates the content B to some other alphabet at frequent interval.
3.I want the JPopupMenu to get updated while it is kept open.
In current behavior if i close and open JPopupMenu the updated value shows up.
I tried repaint()but it doesn't do anything.
What is the best way to do this?? Am new to swings please help.
Menu items can change their content at run time just fine. Without seeing your code it's hard to tell what you're doing wrong, but here's a working example:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
public class PopupTest {
private static final String[] messages = {
"You are today's 1000th user!",
"You have won an internet!",
"Claim your prize!"
};
private PopupTest() {
JFrame frame = new JFrame("You have won");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel lbl = new JLabel("Check your prize!");
frame.setLocationByPlatform(true);
frame.add(lbl);
frame.pack();
final JPopupMenu menu = new JPopupMenu();
final JMenuItem item = new JMenuItem(messages[0]);
menu.add(item);
menu.add(new JMenuItem("Another item that does not work"));
final Timer timer = new Timer(1000, new ActionListener() {
int count;
#Override
public void actionPerformed(ActionEvent e) {
count++;
count %= messages.length;
item.setText(messages[count]);
}
});
menu.addPopupMenuListener(new PopupMenuListener() {
#Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
}
#Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
timer.stop();
}
#Override
public void popupMenuCanceled(PopupMenuEvent e) {
timer.stop();
}
});
lbl.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
maybeShowPopup(e);
}
#Override
public void mouseReleased(MouseEvent e) {
maybeShowPopup(e);
}
private void maybeShowPopup(MouseEvent e) {
if (e.isPopupTrigger()) {
menu.show(e.getComponent(), e.getX(), e.getY());
timer.start();
}
}
});
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new PopupTest();
}
});
}
}
Try to use .revalidate() with .repaint() it might help.
The docs suggest that the revalidate method is called every time something like size changes and manually calling it with repaint seems to solve problems like these.

Why doesn't click in JContextMenu invoked in JDialog fire an ActionEvent?

I have a JContextMenu that I open in a JDialog by calling (the MouseListener is registered to the JDialog):
menu.show(e.getComponent(), e.getX(), e.getY());
The menu itself has an ActionListener registered on the menuitems. It opens fine and the actions are performed as expected, until I open another menu (for example the application's main menu or a context menu on another component) that overlaps something else. For example if a menu in the main menu bar overlaps a dialog or if a context menu is opened that reaches outside the window. Then the clicks on the context menu of the JDialog just close the context menu, as if you had clicked beside the menu to close it (the other menus in the application are still fine though).
It's as if the click goes through the menu. If I select a menu item with the arrow keys and press enter, it does the action just fine.
If I specify e.g. the main window of the application as invoker in the menu.show(), then it seems to always work (but of course it opens on the wrong location). What seems to work is registering the mouse listener on the content pane of the JDialog instead.
Can anyone explain what can cause this behaviour? Should a JDialog not be used as invoker of a context menu for some reason?
I also tried using setComponentPopupMenu(), but that only seems to exist for JComponent and not JDialog or it's content pane. Using it on a component inside the JDialog works, but so does the other method of using a mouse listener and menu.show().
Absent a complete example, I'm not sure I can explain your result, but setComponentPopupMenu() works on a JPanel added to a dialog's content pane. The code below is based on this example.
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
/**
* #see https://stackoverflow.com/a/22100940/230513
* #see https://stackoverflow.com/questions/5129294
*/
public class Test {
private void display() {
JDialog d = new JDialog();
d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
final ImagePanel imagePanel = new ImagePanel();
d.add(new JScrollPane(imagePanel));
d.setJMenuBar(imagePanel.menuBar);
d.pack();
d.setLocationRelativeTo(null);
d.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Test().display();
}
});
}
private static class ImagePanel extends JPanel {
private static final int MASK
= Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
private JFileChooser chooser = new JFileChooser();
private Action openAction = new ImageOpenAction("Open");
private Action clearAction = new ClearAction("Clear");
private JMenuBar menuBar = new JMenuBar();
private JPopupMenu popup = new JPopupMenu();
private BufferedImage image;
public ImagePanel() {
this.setComponentPopupMenu(popup);
popup.add("Popup Menu");
popup.add(new JMenuItem(openAction));
popup.add(new JMenuItem(clearAction));
JMenu menu = new JMenu("File");
menu.setMnemonic('F');
menu.add(new JMenuItem(openAction));
menu.add(new JMenuItem(clearAction));
menuBar.add(menu);
}
#Override
public Dimension getPreferredSize() {
if (image == null) {
return new Dimension(320, 240);
} else {
return new Dimension(image.getWidth(), image.getHeight());
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, null);
}
private class ClearAction extends AbstractAction {
public ClearAction(String name) {
super(name);
this.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_C);
this.putValue(Action.ACCELERATOR_KEY,
KeyStroke.getKeyStroke(KeyEvent.VK_C, MASK));
}
#Override
public void actionPerformed(ActionEvent e) {
image = null;
revalidate();
repaint();
}
}
private class ImageOpenAction extends AbstractAction {
public ImageOpenAction(String name) {
super(name);
this.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_O);
this.putValue(Action.ACCELERATOR_KEY,
KeyStroke.getKeyStroke(KeyEvent.VK_O, MASK));
}
#Override
public void actionPerformed(ActionEvent e) {
int returnVal = chooser.showOpenDialog(chooser);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File f = chooser.getSelectedFile();
try {
image = ImageIO.read(f);
revalidate();
repaint();
} catch (IOException ex) {
ex.printStackTrace(System.err);
}
}
}
}
}
}

Bringing borderless swing window to front

I have a swing program which creates a fullscreen borderless window -- I am running on Windows 7. I need the program to be able to focus and bring itself to the front. However, when I attempt to use the method found here, How to bring a window to the front?, instead of bringing the window to the front the window just flashes in the taskbar and does not accept input. Below I wrote a small program that demonstrates the issue:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class WindowTest extends JFrame{
WindowTest(){
setTitle("Window Test");
setSize(600, 600);
setLocationRelativeTo(null);
setUndecorated(true);
setExtendedState(JFrame.MAXIMIZED_BOTH);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
final WindowTest wt = new WindowTest();
wt.setVisible(true);
Timer t = new Timer(3000,new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
wt.toFront();
wt.repaint();
}
});
}
});
t.setRepeats(false);
t.start();
wt.addKeyListener(new KeyListener(){
#Override
public void keyPressed(KeyEvent arg0) {
if(arg0.getKeyCode() == KeyEvent.VK_ESCAPE){
wt.dispose();
System.exit(0);
return;
}
}
#Override
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
});
}
});
}
}
This will create a borderless, maximized window, and then three seconds later will attempt to bring it to the front. If you change to another window before that, the taskbar button will flash but the window will not be brought to the front.
toFront(quite common issue) doesn't works for JFrame, this is basic property for JDialog
basically is possible to move toFront() only one JFrame, have to use setExtendedState, but with side effects flickering and jumping on the scren, use JDialog instead
don't use KeyListener, because JFrame isn't focusable for KeyEvent, have to use KeyBindings
for example
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class WindowTest extends JFrame {
private static final long serialVersionUID = 1L;
private JFrame frame = new JFrame();
public WindowTest() {
frame.setTitle("Window Test");
frame.setSize(600, 600);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setExtendedState(JFrame.ICONIFIED);
Timer t = new Timer(3000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
frame.setExtendedState(JFrame.NORMAL);
}
});
}
});
t.setRepeats(false);
t.start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
final WindowTest wt = new WindowTest();
}
});
}
}
There's another trick that can be used in case you don't want to minimize and then maximize the window. I have no idea why it works, but if you move the mouse before making the window visible it will come to the front. It's pretty weird, I know, but it seems to work for JRE 1.4 through 1.8 at least. In order to minimize the effect on the mouse you can first see where it is and only move it a little. Your code might look something like this:
PointerInfo mInfo = MouseInfo.getPointerInfo();
Point mWhere = mInfo.getLocation();
(new Robot()).mouseMove(mWhere.x + 2, mWhere.y + 2);
frame_.setVisible(true);
I realize this is a rather late response for the person who posted the question but others may still be looking for the answer.

Categories

Resources