I have a problem to reopen one JInternalFrame in my code. I select in MenuBar option "Cadastro"->"Cadastro de Veículos" and this action open one screen to insert a vehicle. However, if I close this screen and try reopen it again I can't anymore.
Below, two code that I'm using.
First, JMain (that is my JFrame):
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyVetoException;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.WindowConstants;
import javax.swing.event.InternalFrameListener;
public class JMain extends JFrame implements ActionListener{
/**
* Create the panel.
*/
private JMenuBar menuBar = new JMenuBar();
private JMenu firstMenu = new JMenu("Cadastro");
private JMenu secndMenu = new JMenu("Indicadores");
private JMenu thirdMenu = new JMenu("Agendamentos");
private JMenu fourthMenu = new JMenu("Relatórios");
private JMenuItem cadVeiculos = new JMenuItem("Cadastro de Veículos");
private JMenuItem cadMotoristas = new JMenuItem("Cadastro de Motoristas");
private JMenuItem cadCargas = new JMenuItem("Cadastro de Cargas");
private JMenuItem newExit = new JMenuItem("Sair");
public JDesktopPane jdPane = new JDesktopPane();
JCadVeiculos telaCadVeiculos;
public static void main (String args []){
JMain jmain = new JMain();
}
public JMain() {
jdPane.setBackground(Color.LIGHT_GRAY);
setTitle("Gtrix - Version 0.1");
setSize(600, 500);
getContentPane().add(jdPane);
setJMenuBar(menuBar);
menuBar.add(firstMenu);
menuBar.add(secndMenu);
menuBar.add(thirdMenu);
menuBar.add(fourthMenu);
firstMenu.add(cadVeiculos);
firstMenu.add(cadMotoristas);
firstMenu.add(cadCargas);
firstMenu.addSeparator();
firstMenu.add(newExit);
cadVeiculos.addActionListener(this);
setVisible(true);
}
public void actionPerformed(ActionEvent evt) {
if(evt.getSource() == cadVeiculos){
if(telaCadVeiculos == null){
telaCadVeiculos = new JCadVeiculos(this);
}
//telaCadVeiculos.show();
//telaCadVeiculos.setDefaultCloseOperation(JCadVeiculos.DO_NOTHING_ON_CLOSE);
jdPane.moveToFront(telaCadVeiculos);
}
}
}
and JCadVeiculos (my JInternalFrame):
package ui;
import java.awt.EventQueue;
import java.awt.Menu;
import javax.swing.JDesktopPane;
import javax.swing.JInternalFrame;
public class JCadVeiculos extends JInternalFrame {
private JMain telaPrincipal;
/**
* Create the frame.
*/
public JCadVeiculos(JMain telaPrincipal) {
super("", true, true, false);
setSize(600,500);
setTitle("Cadastro de Veículos");
setVisible(true);
this.telaPrincipal = telaPrincipal;
telaPrincipal.jdPane.add(this);
}
}
Please, help me! :)
You will need to make the JInternalFrame visible again, as it was "hidden" when it was closed, for example...
public void actionPerformed(ActionEvent evt) {
if(evt.getSource() == cadVeiculos){
if(telaCadVeiculos == null){
telaCadVeiculos = new JCadVeiculos(this);
}
if (!telaCadVeiculos.getParent().equals(jdPane)) {
jdPane.add(telaCadVeiculos);
}
telaCadVeiculos.setVisible(true);
//telaCadVeiculos.show();
//telaCadVeiculos.setDefaultCloseOperation(JCadVeiculos.DO_NOTHING_ON_CLOSE);
jdPane.moveToFront(telaCadVeiculos);
}
}
On a personal note, I find...
telaPrincipal.jdPane.add(this);
in you JCadVeiculos class worrying. Your JCadVeiculos shouldn't really be making decisions about how it might be getting used and I'd personally refrain from making components publicly visible in this way, as it leads to possible misuse on the part of other developers.
The responsibility for the management of the JDesktopPane lies with the JMain class, it should be deciding what gets added to the JDesktopPane and when
Just saying.
You might also like to take a look at Initial Threads and make sure you're initialising your UI from within the context of the Event Dispatching Thread
Related
I need to access variables from another class and I have done it using 2 different approaches described below.
My question is which of the two is preferable and why since both work quite nicely -or is there another better way to do it?. I have also done it using internal classes but this is inconvenient when the number of code lines gets growing ever larger.
In the following test code the commented asterisks repesent different files:
import java.awt.EventQueue;
import javax.swing.JFrame;
public class Test {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
MainFrame f = new MainFrame("Testing",50,50);
f.setResizable(false);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
}
//**********************************************************************
import java.awt.BorderLayout;
import javax.swing.JFrame;
public class MainFrame extends JFrame {
public MainFrame(String title,int x,int y) {
setTitle(title);
this.setLocation(x, y);
UpperPanel pUp=new UpperPanel();
add(pUp, BorderLayout.NORTH);
LowerPanel pLow=new LowerPanel();
add(pLow, BorderLayout.SOUTH);
pack();
}
}
Now as you can see below UpperPanel must access JButtons from LowerPanel and LowerPanel must access the menu from UpperPanel. For this reason I could pass pUp as a parameter to the LowerPanel constructor but I can't pass pLow as parameter to UpperPanel as it hasn't been created yet.
Therefore I have used 2 methods, one declaring instances of the relevant classes and the other using static variables. The previous 2 classes above are the same in each approach.
Below is the code of the panels in the first case:
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JMenu;
import javax.swing.JPanel;
public class LowerPanel extends JPanel implements ActionListener {
static JButton butEnableMenu;
static JButton butEnableBut1;
public LowerPanel() {
setLayout(new FlowLayout(FlowLayout.LEFT));
butEnableMenu=new JButton("Enable menu");
butEnableMenu.setEnabled(true);
butEnableMenu.addActionListener(this);
add(butEnableMenu);
butEnableBut1=new JButton("Enable first button");
butEnableBut1.setEnabled(false);
butEnableBut1.addActionListener(this);
add(butEnableBut1);
}
public void actionPerformed(ActionEvent e) {
UpperPanel up = null;
Object clicked=e.getSource();
JMenu mnu=up.myMenuBar.getMenu(0);
if(clicked.equals(butEnableMenu)) {
mnu.setEnabled(true);
butEnableMenu.setEnabled(false);
}
else if(clicked.equals(butEnableBut1)) {
butEnableMenu.setEnabled(true);
butEnableBut1.setEnabled(false);
}
}
}
//**********************************************************************
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
public class UpperPanel extends JPanel {
static JMenuBar myMenuBar;
public UpperPanel() {
setLayout(new FlowLayout(FlowLayout.LEFT));
myMenuBar=new JMenuBar();
JMenu but2=new JMenu("2nd button");
JMenuItem enableBut2=new JMenuItem("Enable");
but2.setEnabled(false);
enableBut2.addActionListener(new menuActionListener());
myMenuBar.add(but2);
but2.add(enableBut2);
add(myMenuBar);
}
}
class menuActionListener implements ActionListener {
static String clickedMenuItem=null;
LowerPanel lp;
public void actionPerformed(ActionEvent e) {
clickedMenuItem=e.getActionCommand();
JMenuItem mnuItm=(JMenuItem)e.getSource();
JPopupMenu pmen = (JPopupMenu)mnuItm.getParent();
JMenu pmnu =(JMenu)pmen.getInvoker();
if(clickedMenuItem.equals("Enable")) {
pmnu.setEnabled(false);
lp.butEnableBut1.setEnabled(true);
}
}
}
And these are the panels in the second case:
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
public class UpperPanel extends JPanel {
static JMenuBar myMenuBar;
public UpperPanel() {
setLayout(new FlowLayout(FlowLayout.LEFT));
myMenuBar=new JMenuBar();
JMenu but2=new JMenu("2nd button");
JMenuItem enableBut2=new JMenuItem("Enable");
but2.setEnabled(false);
enableBut2.addActionListener(new menuActionListener());
myMenuBar.add(but2);
but2.add(enableBut2);
add(myMenuBar);
}
}
class menuActionListener implements ActionListener {
static String clickedMenuItem=null;
public void actionPerformed(ActionEvent e) {
clickedMenuItem=e.getActionCommand();
JMenuItem mnuItm=(JMenuItem)e.getSource();
JPopupMenu jpm = (JPopupMenu)mnuItm.getParent();
JMenu pmnu =(JMenu)jpm.getInvoker();
if(clickedMenuItem.equals("Enable")) {
pmnu.setEnabled(false);
LowerPanel.butEnableBut1.setEnabled(true);
}
}
}
//**********************************************************************
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JMenu;
import javax.swing.JPanel;
public class LowerPanel extends JPanel implements ActionListener {
static JButton butEnableMenu;
static JButton butEnableBut1;
public LowerPanel() {
setLayout(new FlowLayout(FlowLayout.LEFT));
butEnableMenu=new JButton("Enable menu");
butEnableMenu.setEnabled(true);
butEnableMenu.addActionListener(this);
add(butEnableMenu);
butEnableBut1=new JButton("Enable first button");
butEnableBut1.setEnabled(false);
butEnableBut1.addActionListener(this);
add(butEnableBut1);
}
public void actionPerformed(ActionEvent e) {
Object clicked=e.getSource();
JMenu mnu=UpperPanel.myMenuBar.getMenu(0);
if(clicked.equals(butEnableMenu)) {
mnu.setEnabled(true);
butEnableMenu.setEnabled(false);
}
else if(clicked.equals(butEnableBut1)) {
butEnableMenu.setEnabled(true);
butEnableBut1.setEnabled(false);
}
}
}
In general there are 2 ways to access a variable from another class:
You create an object of that class. Then this object has all the variables from the scope of that class assigned to it. For example:
Test t = new Test();
t.name = "test";
You can also create a static variable. Then the variable is assigned to the class not the object of that class. This way you will not need to create an object, but all instances of the class will share the same variable.
//In the scope of the class
static String name;
-------------------------
//when classing the class
Test.name = "The Name of the Test";
If you do not want to create a new instance of a class every time, and always use the same instance, you can create a singleton object. You write a getter method that gets you the object. It looks like this:
public class Test {
Test t;
public static void main(String[] args) {
t = new Test();
}
public Test getTest() {
if (t != null) {
return t;
} else {
t = new Test();
return t;
}
}
}
I see you work with a JFrame. Then you will probably want to make it a singleton. Else you will open a new instance of the JFrame every time you call upon it, which is not recommended.
Does this answer your question?
I'm currently working on a project that requires the state of a JRadioButton to change when the record being viewed is updated.
We've had a few clients complain to us that when the record changes, if the JRadioButton is off-screen, it won't be updated until the screen is shown. This behavior seems to be a result of using the Windows Look and Feel, as it doesn't seem to happen when it is not set.
The code example below demonstrates this.
The default selected JRadioButton is 'Cat', so by selecting the 'Dog' JButton and then changing tab to 'Question', you can see the JRadioButton transition occur.
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
/**
* Example of JRadioButton not updating until it's parent panel becomes visible.
*/
public class RadioButtonExample extends JPanel implements ActionListener {
public static final String CAT = "Cat";
public static final String DOG = "Dog";
private final JRadioButton radCat;
private final JRadioButton radDog;
private final ButtonGroup grpAnimal;
public RadioButtonExample() {
super(new BorderLayout());
JLabel lblQuestion = new JLabel("Are you a cat or dog person?");
radCat = new JRadioButton(CAT);
radCat.setActionCommand(CAT);
radCat.setSelected(true);
radDog = new JRadioButton(DOG);
radDog.setActionCommand(DOG);
grpAnimal = new ButtonGroup();
grpAnimal.add(radCat);
grpAnimal.add(radDog);
JPanel pnlQuestion = new JPanel(new GridLayout(0, 1));
pnlQuestion.add(lblQuestion);
pnlQuestion.add(radCat);
pnlQuestion.add(radDog);
JButton btnSetCat = new JButton(CAT);
btnSetCat.setActionCommand(CAT);
btnSetCat.addActionListener(this);
JButton btnSetDog = new JButton(DOG);
btnSetDog.setActionCommand(DOG);
btnSetDog.addActionListener(this);
JPanel pnlButtons = new JPanel(new GridLayout(0, 1));
pnlButtons.add(new JLabel("Update your choice of animal"));
pnlButtons.add(btnSetCat);
pnlButtons.add(btnSetDog);
JTabbedPane tabPane = new JTabbedPane();
tabPane.addTab("Buttons", pnlButtons);
tabPane.addTab("Question", pnlQuestion);
add(tabPane, BorderLayout.LINE_START);
setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
}
public void actionPerformed(ActionEvent evt) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
grpAnimal.clearSelection();
if (CAT.equals(evt.getActionCommand())) {
grpAnimal.setSelected(radCat.getModel(), true);
}
else if (DOG.equals(evt.getActionCommand())) {
grpAnimal.setSelected(radDog.getModel(), true);
}
}
});
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("RadioButtonExample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
JComponent newContentPane = new RadioButtonExample();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
// Comment out the line below to run using standard L&F
setLookAndFeel();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void setLookAndFeel() {
try {
// Set Windows L&F
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
}
catch (Exception e) {
// handle exception
}
}
}
Is there a way to prevent this behavior or even speed it up to make it less noticeable for our users?
You might be able to disable the animation by specifying the swing.disablevistaanimation Java system property:
java -Dswing.disablevistaanimation="true" your-cool-application.jar
In the com.sun.java.swing.plaf.windows.AnimationController class, there is a VISTA_ANIMATION_DISABLED field that is initialized to the swing.disablevistaanimation property. This field determines whether the paintSkin method calls the skin.paintSkinRaw method if animations are disabled or else starts to get into the animations.
It works on my Windows 8.1 laptop with Java 8 (jdk1.8.0_65), so its effect does not seem to be limited to Windows Vista only.
I am learning the basics of Java and decided to practice working on objects, by making a simple program which I called a 'PlayerAction Counter'. It does nothing more that counting an 'action' which is fired by clicking '+1' button and additionally reset the counter, when the 'Reset' button is clicked. For this case I've made a Application.java which holds the main method and launches the program, Interface.java for GUI, EventHandling.java for events and Person.java which holds interface components and methods to change their state. It looks like this:
My idea was to create the window in Interface class and set it's layout, then create two Person objects called PlayerOne and Player Two. The Person class creates two labels and two buttons and set a label of one by a constructor parameter.
I've managed to add these two objects' elements to the GUI by getters and it looks just fine. I added ActionListener to both buttons in Person class and it also works just fine.
I am stuck on getting back to Person fields and methods from EventHandling class. I've created a setValueLabel() which increases by one a value of 'action' and sets it on the label, but I have to idea how to launch the method from another class. I can not make another object inside (throws StackOverFlow error), but should it not somehow refer to those two made in Interface class?
Here is the code:
Application.java
import java.awt.EventQueue;
public class Application {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
new Interface().setVisible(true);
}
});
}
}
Interface.java
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.SwingConstants;
public class Interface extends JFrame {
private JLabel titleLabel;
private JPanel mainPanel;
private JPanel leftPanel, rightPanel;
private JSeparator separator;
Person PlayerOne = new Person("PlayerOne");
Person PlayerTwo = new Person("PlayerTwo");
public Interface() {
//Basic init
setTitle("PlayerAction Counter");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
//Layout
mainPanel = new JPanel();
add(mainPanel);
mainPanel.setLayout(new BorderLayout());
mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
leftPanel = new JPanel();
rightPanel = new JPanel();
leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.Y_AXIS));
leftPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
mainPanel.add(leftPanel, BorderLayout.WEST);
separator = new JSeparator(SwingConstants.VERTICAL);
mainPanel.add(separator, BorderLayout.CENTER);
titleLabel = new JLabel("PlayerAction Counter");
mainPanel.add(titleLabel, BorderLayout.PAGE_START);
//Components init
PlayerTwo.getPersonLabel().setAlignmentX(Component.CENTER_ALIGNMENT);
leftPanel.add(PlayerTwo.getPersonLabel());
PlayerTwo.getValueLabel().setAlignmentX(Component.CENTER_ALIGNMENT);
leftPanel.add(PlayerTwo.getValueLabel());
PlayerTwo.getValueUpButton().setAlignmentX(Component.CENTER_ALIGNMENT);
leftPanel.add(PlayerTwo.getValueUpButton());
PlayerTwo.getValueResetButton().setAlignmentX(Component.CENTER_ALIGNMENT);
leftPanel.add(PlayerTwo.getValueResetButton());
rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.Y_AXIS));
rightPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
mainPanel.add(rightPanel, BorderLayout.EAST);
PlayerOne.getPersonLabel().setAlignmentX(Component.CENTER_ALIGNMENT);
rightPanel.add(PlayerOne.getPersonLabel());
PlayerOne.getValueLabel().setAlignmentX(Component.CENTER_ALIGNMENT);
rightPanel.add(PlayerOne.getValueLabel());
PlayerOne.getValueUpButton().setAlignmentX(Component.CENTER_ALIGNMENT);
rightPanel.add(PlayerOne.getValueUpButton());
PlayerOne.getValueResetButton().setAlignmentX(Component.CENTER_ALIGNMENT);
rightPanel.add(PlayerOne.getValueResetButton());
pack();
}
}
Person.java
import java.awt.Component;
import javax.swing.JButton;
import javax.swing.JLabel;
public class Person {
private JLabel personLabel;
private JLabel valueLabel;
private JButton valueUpButton;
private JButton valueResetButton;
private int actionValue = 0;
public Person(String s) {
personLabel = new JLabel(s);
setComponents();
}
private void setComponents() {
valueUpButton = new JButton("+1");
valueResetButton = new JButton("Reset");
valueLabel = new JLabel(""+actionValue);
EventHandling eventHand = new EventHandling(valueUpButton, valueResetButton);
valueResetButton.addActionListener(eventHand);
valueUpButton.addActionListener(eventHand);
}
public void setValueLabel() {
actionValue++;
valueLabel.setText("" +actionValue);
}
public JLabel getPersonLabel() {
return personLabel;
}
public JLabel getValueLabel() {
return valueLabel;
}
public JButton getValueUpButton() {
return valueUpButton;
}
public JButton getValueResetButton() {
return valueResetButton;
}
}
EventHandling.java
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JLabel;
public class EventHandling implements ActionListener {
private JButton valueUpButton;
private JButton valueResetButton;
public EventHandling(JButton valueUpButton, JButton valueResetButton) {
this.valueUpButton = valueUpButton;
this.valueResetButton = valueResetButton;
}
#Override
public void actionPerformed(ActionEvent event) {
if (event.getSource() == valueUpButton) {
//no idea how to launch Person.setValueLabel();
//creating new Person object throws StackOverFlow error and I doubt that's the way
}
else if (event.getSource() == valueResetButton) {
}
}
}
I do hope my issue is understandable. The question is: how should it be done?
Please keep in mind that I am a complete rookie and try to learn OOP, but am very confused by it. Please point my mistakes in thinking and the code.
Any feedback will be greatly appraciated.
Thank you.
I am pretty new to Swing, any help appreciated.
I have the following situation:
A "Main" Class where I define my main JPanel and default Label text.
A "GUILabel" Class (extends JLabel) where I define the look of the Text Labels.
A "popupmenu" Class (extends JPopupMenu) where I define the content of the popupmenu.
Target:
When I right-click on a panel the popupMenu should appear (this already works).
When I choose a menu item of this popupMenu, the text of the label I clicked on should change.
I guess its currently not working (I am sorry this code isn't complete - this is my 5th attempt), because I create the popup menu Once in the Main Class. Then I am adding this popup menu to each Label. So I guess thats why getInvoker() returns null in the popup menu class.
But do I really have to create a new popupmenu for each JLabel? Cant this single menu just handle all Components assigned to?
Main Frame:
package popupshit;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.border.BevelBorder;
public class Model implements ActionListener {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridLayout(0, 3));
frame.setVisible(true);
GUIPopupMenu popup = new GUIPopupMenu(9);
JLabel label1 = new GUILabel();
label1.setComponentPopupMenu(popup);
JLabel label2 = new GUILabel();
label2.setComponentPopupMenu(popup);
JLabel label3 = new GUILabel();
label3.setComponentPopupMenu(popup);
frame.add(label1);
frame.add(label2);
frame.add(label3);
frame.pack();
}
#Override
public void actionPerformed(ActionEvent e) {
((JLabel) e.getSource()).setText("" + e.getActionCommand());
}
}
PopupMenu:
package popupshit;
import java.awt.event.ActionListener;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
public class GUIPopupMenu extends JPopupMenu {
public GUIPopupMenu(int numbers) {
for (int i = 1; i < numbers; i++) {
JMenuItem popMenuItem = new JMenuItem("" + i);
popMenuItem.addActionListener ((ActionListener) this.getInvoker());
System.out.println(this.getParent());
this.add(new JMenuItem("" + i));
}
this.addSeparator();
this.add(new JMenuItem("remove"));
}
}
GUILabel:
package popupshit;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.border.BevelBorder;
import javax.swing.border.BevelBorder;
public class GUILabel extends JLabel implements ActionListener {
public GUILabel() {
this.setBorder(new BevelBorder(BevelBorder.LOWERED));
this.setVisible(true);
this.setPreferredSize(new Dimension(50, 50));
this.setText("0");
}
#Override
public void actionPerformed(ActionEvent e) {
this.setText((String) e.getActionCommand());
JOptionPane.showMessageDialog(null, "worked!" );
}
}
invoker is null because until the popup menu is a actually invoked, it has no invoker.
Instead, add a simple ActionListener to the menu item which, when invoked, uses the invoker property to determine which should occur.
My personal preference would be to create a new instance of the popup menu for each component separately, passing a reference of the component in question or some other controller as required...but that's me...
Add an ActionListener to the menu item something like:
#Override
public void actionPerformed(ActionEvent e)
{
Component c = (Component)e.getSource();
JPopupMenu popup = (JPopupMenu)c.getParent();
JLabel label = (JLabel)popup.getInvoker();
...
}
Don't extend JPopupMenu just to add a few menu items to the popup.
I am having some problems regarding to the JMenuBar and I cant seem to figure it out.
I will start with an abriviation of the problem: The program consists of a JFrame, a JDialog and a JMenuBar. Initially, you will get to see a JFrame with the JMenuBar in the top. But at some point, the JDialog will pop up where a user can fill in some text fields. The problem that I'm having is that as soon as the focus goes to the JDialog, the JMenuBar disappears. What I want is that the JMenuBar stays in the top of the screen all the time, except if the whole program is NOT in focus. Here are 2 screenshots, in the first screen shot, the JFrame is selected and in the other one the JDialog is selected.
So what i actually want is instead of only seeing the JMenuBar when the focus is on the JFrame, i want to see the JMenuBar all the time. Since a JDialogs can not have the JMenuBar in the top, like a JFrame has, i decided not to have multiple JMenuBars, but just the one that should be visible all the time.
At last i will give a part of the code that is as small as possible (and still working) and also contains the problem:
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JRootPane;
import javax.swing.KeyStroke;
/**
* #author Guus Leijsten
* #created Oct 27, 2012
*/
public class MenuBarProblem extends JFrame {
public MenuBarProblem() {
super("Frame");
this.setMinimumSize(new Dimension(270, 200));
this.setPreferredSize(new Dimension(800, 530));
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
JRootPane root = this.getRootPane();
//Menu
JMenu fileMenu = new JMenu("File");
JMenuItem file_exit = new JMenuItem("Exit");
file_exit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
file_exit.setToolTipText("Exit application");
file_exit.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
fileMenu.add(file_exit);
JMenuBar menu = new JMenuBar();
menu.add(fileMenu);
root.setJMenuBar(menu);
this.setVisible(true);
JDialog d = new JDialog(this, "Dialog");
d.setSize(200, 100);
d.setLocation(0, (int)root.getContentPane().getLocationOnScreen().getY());
d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
d.setVisible(true);
}
public static void main(String[] args) {
String os = System.getProperty("os.name").toLowerCase();
if(os.indexOf("mac") >= 0) {
System.setProperty("apple.laf.useScreenMenuBar", "true");
}
new MenuBarProblem();
}
}
If I can be honoust, i think that the problem lies in the part of JRootPane. But we'll see ;)
Did anyone else encountered this problem and managed to solve it alrady, or is there anybody that wants to give it a shot?
Thanks in advance!
Added content:
In the following example I will show a version that gives some functionality to the play.
This is the program i'm making:
The second image shows the state in which the right menu is undocked.
Obviously the JMenuBar should still be visible and operational because without it, a lot of functionalities of the program will be disabled.
At this point i'm starting to think that it is impossible for the JMenuBar to stay visible when the dialog (undocked menu) is undocked, and focussed on.
I know that the JMenuBar on a JDialog can not be in the mac osx style (top of screen), so are there any other techniques i can use for undocking, which does give me a mac osx style JMenuBar?
One key to solving this problem, pun intended, is to let a key binding share a common menu action, as shown below. Note how a menu item, your dialog's content and an (otherwise superfluous) button can all use the same Action instance. A few additional notes:
Kudos for using getMenuShortcutKeyMask().
Swing GUI objects should be constructed and manipulated only on the event dispatch thread (EDT).
System properties should be set before starting the EDT.
Make the dialog's setLocation() relative to the frame after its geometry is known.
A common Mac idiom uses the following predicate:
if (System.getProperty("os.name").startsWith("Mac OS X") {…}
See also this example.
For local use in the dialog itself, also consider JToolBar.
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
/**
* #see https://stackoverflow.com/a/13100894/230513
*/
public class MenuBarProblem extends JFrame {
private static final int MASK =
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
private static final String exitName = "Exit";
private static final KeyStroke exitKey =
KeyStroke.getKeyStroke(KeyEvent.VK_W, MASK);
private final ExitAction exitAction = new ExitAction(exitName);
public MenuBarProblem() {
super("Frame");
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
JMenu fileMenu = new JMenu("File");
JMenuItem fileExit = new JMenuItem(exitAction);
fileMenu.add(fileExit);
JMenuBar menu = new JMenuBar();
menu.add(fileMenu);
JDialog d = new JDialog(this, "Dialog");
JPanel p = new JPanel();
p.getInputMap().put(exitKey, exitName);
p.getActionMap().put(exitName, exitAction);
p.add(new JButton(exitAction));
d.add(p);
d.pack();
d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
this.setJMenuBar(menu);
this.pack();
this.setSize(new Dimension(320, 240));
this.setLocationByPlatform(true);
this.setVisible(true);
d.setLocation(this.getRootPane().getContentPane().getLocationOnScreen());
d.setVisible(true);
}
private static class ExitAction extends AbstractAction {
public ExitAction(String name) {
super(name);
this.putValue(Action.MNEMONIC_KEY, exitKey.getKeyCode());
this.putValue(Action.ACCELERATOR_KEY, exitKey);
}
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}
public static void main(String[] args) {
System.setProperty("apple.laf.useScreenMenuBar", "true");
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new MenuBarProblem();
}
});
}
}
Solved!
Using a JFrame with the use of setAlwaysOnTop(true) gives me the desired effect of having a JMenuBar when the focus changes.