I'm practicing my gui skills with Java and I have been doing menus and menu bars.
They make sense to me just fine but I have a question about where I can learn more about them.
The basic menus I have done, the ActionListener function actionPerformed has to be in the same class as the menu, and the item that the menu is changing also has to be in the class as the menu.
What If I want to have a menu that affects a JPanel that is created by a constructor from another class and placed in my frame.. I'm not sure how the menu can change components of it.
Any tips, hints or sites you guys have found helpful would be great, thanks in advance.
I find it useful to wrap menubar actions in an Action object. This encapsulates:
The name and icon of the action
If it is enabled or disabled
(for a checkbox action) if it is selected
The keyboard shortcut for the action
The implementation of the action listener
You would define a subclass of AbstractAction in the class whose data that action acts on. Then define a getter for that action so that your menu building code can get it. You can add the Action directly to a menu - a MenuItem is constructed automatically for it.
The other advantage of actions is that that same action can be used in a button, toolbar, etc.
class ModelClass {
int value;
Action incAction = new AbstractAction("Increment") {
public void actionPerformed() {
value++;
setEnabled(value < 10);
}
};
public Action getIncAction() {
return incAction;
}
}
class UIClass {
void buildMenu() {
JMenu menu = new JMenu("Model");
menu.add(model.getIncAction());
}
}
Related
I am in the process of refactoring my application and my teacher recommended that I replace the GUI builder generated code with a more generic one.
Right now every JMenuItem has its own action listener. What I'm trying to achieve is a sort of generic control function for every menu item by using enums in a single action listener. The code below should give you a general idea. clE is the enum key and I believe the enum should implement an interface for reading its label.
I've been doing a bit of research and I'm sure it's something simple, but I can't get fully grasp it yet. Thanks in advance!
public class JECheckBox<E extends ENUM_Label_INTF<?>> extends JCheckBox {
private final E clE;
// +++++++ CONSTRUCTOR +++++++++
public JECheckBox(final E clE) {
super( ((GetLabelINTF) clE).GetLabel() );
this.clE = clE;
}
public E GetKey() {
return clE;
}
}
I believe the enum should implement an interface for reading its label.
If you want to read the text of the check box, then you create a generic listener by doing something like:
Action action = new AbstractAction()
{
#Override
public void actionPerformed(ActionEvent e)
{
JCheckBox checkbox = (JCheckBox)e.getSource();
System.out.println( checkbox.getText() );
}
};
Now you can add the Action to each check box.
Note an Action is a more versatile ActionListener. Read the section from the Swing tutorial on How to Use Actions for more information and examples.
Not suew what you mean by generic enums. Try giving every menu item (or any component) it's own name using component.setName(SomeEnum.soneValue.toString()). Then get the name in the action listener and do a switch(SomeEnum.valueOf(name).
I've just starting using Java Swing and I have a issue.
I tried to do a simple menuBar and a menuItem 'Exit', but before linking the button to the action the menuItem appeared, now that I've linked the button to a System.exit(0) action it disappeared. Help?
The code is the following:
in MainPanel (the autogenerated code from swing is excluded):
public void init() {
initComponents();
initActions();
setLocationRelativeTo(null);
pack();
setVisible(true);
}
private void initActions() {
this.menuItemExit.setAction(Application.getInstance().getPanelControl().getActionExit());
}
In PanelControl:
public class PanelControl {
private Action actionExit;
public Action getActionExit() {
return actionExit;
}
public class ActionExit extends AbstractAction{
public ActionExit(){
putValue(Action.NAME, "Exit");
putValue(Action.SHORT_DESCRIPTION, "Exit from the application");
putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("ctrl e"));
putValue(Action.MNEMONIC_KEY, KeyEvent.VK_E);
}
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}
In Application:
private void init() {
viewMainPanel = new MainPanel();
controlPanel = new ControlPanel();
viewMainPanel.init();
}
i think the problem is somewhere in here but i can't figure out where. any help?
(there's other code but i just put the more relevant part, also i translated the code from italian so i'm sorry if there are any problems or a few names dont match up)
private Action actionExit;
public Action getActionExit() {
return actionExit;
}
Your actionExit variable is null.
Nowhere in your code do you create an instance of your ActionExit class.
Somewhere you need:
actionExit = new ActionExit();
Your design seems a bit complicated, I have no idea why you have a panel just to create an instance of the ActionExit class.
I would suggest you just create the ActionExit instance in your main class and get rid of the PanelControl class.
Instead of using an IDE to generate confusing code you should consider learning how to write the code yourself so you can better structure your classes. Read the section from the Swing tutorial on How to Use Menus for a working example to get you started.
A menu item has to be added to a Native Java Swing component. You have to add it to a JFrame. You can't add a MenuItem to a Panel. The Parent 'root' container in any Java Swing application is 'native' and a JFrame. Everything else in that container is 'drawn' into the rectangle using the look and feel of your choosing.
Then you CREATE a MenuItem using your TAbstractAction item. That object CAN be used to create a JButton, JMenuItem or ToolBar button. Keeping a reference to your TAbstractAction in your code, you can enable/disable the object and it implements an 'observable' pattern where it will enable/disable ALL UI controls you used to build with it. I actually wrote a Java Swing framework for doing Java Applications. It used to be on the Sun Open Source web site. If you wish I can put it up on GitLab for you to play with. Java Swing is nice but JavaFX should be the long term goal for UI on a JVM.
In your JFrame object you need to do this:
_menuBar = new JMenuBar();
// add controls to the frame
setJMenuBar(_menuBar);
Then you need to add your 'exitMenuItem' to your _MenuBar control.
Cheers
I've read the Java trail oracle provides and they said that the objects properties are set to match the actions properties. I would like to know if this is a limited set of properties that is shared, or if the Action is casted to the same class as the object you are setting the action to.
Another question I have is such... is it possible to set the Action to have the same properties as the Component that I'm setting it to so that it doesn't reset everything? The only work around that I can think of is either setting the action for the object before doing anything with the object, or passing the object through the actions methods or constructor and setting all the values you want at that point. I was hoping however I could set the actions at a later time in the program without disturbing anything, it be more convenient.
Example ...
JMenuItem myItem = new JMenuItem("someText");
myItem.setAction(myAction);// Clears the text from my menu item which is the problem
Thanks
Me:
Why not have "someText" associated with the Action from the get-go?
You:
How do I do that?
Solution:
// can also pass in an icon to this constructor as a 2nd parameter
Action myAction = new AbstractAction("Some Text") {
{
// set properties here including mnemmonic
putValue(MNEMONIC_KEY, KeyEvent.VK_S);
}
#Override
public void actionPerformed(ActionEvent e) {
// action initiated code goes here
}
};
Also you can set the button's text via the Action's NAME property:
Action myAction = new AbstractAction() {
{
putValue(NAME, "Some Text");
putValue(MNEMONIC_KEY, KeyEvent.VK_S);
}
// ... etc...
};
Ik have used this tutorial to define a menu that is built up during runtime. But the next step I want to take is when some event occurs I want to re-build this menu programmatically, for instance by saying to the menu manager, refresh or something like that? Any idea how I can do this?
You can tell the menu manager to remove all items each time the menu is shown, giving you the opportunity to rebuild your menu:
MenuManager mm = new MenuManager();
mm.setRemoveAllWhenShown(true);
mm.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager manager) {
if(giraffes) {
Action giraffeAction = new Action("Giraffe") {
public void run() {
// do giraffe-y stuff
}
};
mgr.add(giraffeAction);
}
}
});
Control myControl = myViewer.getControl();
myControl().setMenu(mm.createContextMenu(myControl));
Instead of using an ExtensionContributionFactory, use org.eclipse.ui.menus to add a dynamic element to the menu you want. The implementation class you provide subclasses org.eclipse.ui.actions.CompoundContributionItem and you will have the opportunity to rebuild that part of the menu on every menu open.
EDIT: add pointer to example.
See http://git.eclipse.org/c/platform/eclipse.platform.ui.git/tree/examples/org.eclipse.ui.examples.contributions/plugin.xml#n666 for the plugin.xml difference. The implementing class is also contained in that plugin.
The code below shows a problem I'm having with combo actions. The getSelectedItem() is fired multiple times instead of just at selection. Simply loading the frame calls the method 3 times. Each click on the combo box is a call, even if its just for the dropdown and not the actual selection. Clicking inside the editable text area also triggers the getSelectedItem() method. Is there a way to filter this event?, or an alternate way to validate data on the box model level?
public class SSCCE {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
JFrame aframe = new JFrame();
Combo _combo = new Combo();
_combo.addElement("This");
_combo.addElement("That");
JComboBox _box = new JComboBox(new Combo());
_box.setEditable(true);
aframe.add(_box);
aframe.setVisible(true);
}
static class Combo extends DefaultComboBoxModel{
public Combo(){
}
int i = 0;
#Override
public Object getSelectedItem() {
System.out.println("Get selected Item" + i);
i++;
return super.getSelectedItem();
}
}
}
See this tutorial on how to use JComboBox, specifically the section on handling events. You should add an ActionListener to your combobox. It will be triggered when the user actually makes a gesture indicating that their selection is confirmed.
You have look at ItemListener or ActionListener added to the JComboBox
getSelectedItem() indeed fires multiple times, as well as the action event. For an editable combo box the action fires once for comboboxchanged, and once for comboboxedited. I've set up the validation that is not specific to end item in the getSelectedItem, and moved the rest into a filtered action event for comboboxchanged. I've completely ignored comboboxedited event.