I've inserted a JMenu (instance named: exitMenu) without any JMenuItem, so my intention is to make available a way to EXIT the program without access unnecessary menu items, since my program has just one JMenu object (Someone might says: WTF!!! but...).
Thus, to capture the event occurred in this specific JMenu component, my class implements the MenuListener interface. As everybody knows, there are three mandatory implementation methods, although I need to use just one, the menuSelected() method.
To make my program a little bit intuitive, undoubtedly, once the user selects the exitMenu, the (in)famous popup JOptionPane.showConfirmDialog() presents itself where he/she needs to choose between the YES or NO option.
If the chosen option is YES, no problem at all, since the program is finished through System.exit(0). The problem is the NO option, when the focus returns to the program, the exitMenu remains selected, off course, since I've selected previously. The "thing" I'd like to do is to remove the object selection right after the NO option is chosen, so the user'll be able to click on it again.
Even using exitMenu.setSelected(false) within the three mandatory methods (one calling another), although exitMenu component is "deselected" it's necessary to click on it twice to call its event listener.
Any suggestion?
Thanks in advance.
One thing I attempted is to simply call setSelected(false) from within the menuSelected(...) method, but this has side effects. For one, the menu doesn't appear to be selected, and for another, it doesn't work all the time.
One possible solution that does work is to deselect the menu in a Swing Timer. Something like:
#Override
public void menuSelected(MenuEvent mEvt) {
// show JOptionPane
// if yes selected, exit.
// Otherwise...
final JMenu menu = (JMenu) mEvt.getSource();
new Timer(200, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
menu.setSelected(false);
((Timer)e.getSource()).stop();
}
}).start();
}
There are two levels, for
JMenu there is MenuListener
JMenuItem there is ButtonModel
Related
I have a screen which has list. By right click, I can open a small pop up and add new records to the that list by choosing some record and clicking OK button from pop up.
OK button which is on pop up has an action listener like below:
okButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
setVisible(false);
}
});
And that is all the actionPerformed method does and I do not understand how this method is adding new record to the list on main window. There should be another part of code which is connected to this part but I do not know what is that. Do you have any idea what I do not see on that logic?
The ActionListener is not empty and in fact it is changing the state of the window that holds the JButton, making it no longer visible.
No one can say with 100% confidence what logic is being used here since you've yet to show enough code for that, but our guess is that this button is being held within a modal JDialog -- a window that freezes code flow in the calling code once the dialog window is visible, and (here's the key) that releases the block on code flow once this dialog is no longer visible. So in this situation, making the dialog no longer visible will allow the calling code, the code that initially told the dialog to display itself, to resume flow of its logic. Presumably in the subsequent code, it will query the dialog for data that was entered, and extract it, again the details of which are in code not yet shown to us.
Is there any reason why in LWUIT a Button can have its own ActionListener (via button.addActionListener) while a Command does not?
Is the only way to have a listener for a specific command is to add an ActionListener to a form and check the listener for which Command the event came from like below?
public void startApp() {
Display.init(this);
f = new Form("Mixed Record");
exit = new Command("Exit");
start = new Command("Start");
Button button = new Button("Button");
f.addCommand(exit);
f.addCommand(start);
f.addCommand(delete);
f.addComponent(button);
f.addCommandListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
if (ae.getCommand().equals(exit)) {
//Do Exit command code
} else if (ae.getCommand().equals(start)) {
//Do Start command code
}
}
});
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
//Do button code
}
});
f.show();
}
Well, I can't tell you exactly why the people who wrote LWUIT made that decision but there are several reasons why it makes sense.
When a Form contains several Commands, they are grouped in a menu. Every time the user expands then collapses the menu, a maximum of one Command is executed. As such, the Commands are conceptually more linked to one another than Buttons are, especially since it is not uncommon to reuse Button subclasses from one Form to another.
There might also have been a concern about making the API of the LWUIT Form look a lot like the LCDUI Form in the MIDP specification.
I also like that your code shows one positive consequence of the decision:
You already have 2 unnamed inner classes (the ActionListener subclasses) in your code. If each Command had its own ActionListener, you would probably have written 3 unnamed inner classes. Developers tend to do that a lot even though, when you have spent a bit more time looking at stack traces of code that contains multiple unnamed inner classes, you will realize that it is bad practice to have more than one in each named class.
I am a new user of Java swing. I need to be able to create a popup with row info when the user clicks on that row. I managed to incorporate the mouseClick event reaction in my table class, and I have the row info available. How can I notify the main window about the event so it can display the dialog box/popup box?
Just call a method on the main window to perform the action
There are several ways to handle this:
1) You can have the custom table class have a custom listener on it (Observer Pattern) which it then calls whenever the click occurs
2) You can have the table call a method on the main window - i.e. pass in the main window as part of the construction of the table
3) You can have the main Window register as a listener to the table (i.e. a mouse listener) and have it handle the events instead.
There are others, I am sure. These are the ones I have seen most often used. Depending on the size, scope and intent of the software being written, each has it's merits and detriments. Is this a project for school, a toy being written to learn about Swing, or is it designed to be a longer term, larger project? If it is the latter, I would recommend looking up Model View Controller (MVC) architecture discussions, as it can make, long term, the maintenance of the code much easier, in my experience.
Good luck.
You can do it like this:
myTable.addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent e) {
if(SwingUtilities.isRightMouseButton(e)) {
int index = myTable.rowAtPoint(e.getPoint());
JPopupMenu popup = new JPopupMenu();
popup.add(myMenuAction);
popup.show(e.getComponent(), e.getX(), e.getY());
}
}
});
And then implement an Action myMenuAction where you use the index from your table.
Here's the situation, I have a jFrame with a tabbed pane and within the tabs I have a couple of jTables and a jTree. I want to be able to chain the selections between the tables and the tree based on whether a user uses a ctrl/shift + click versus a regular click. (If you hold ctrl and click in the first table/tree, it adds to the overall selection, if you use a regular click it clears the selections in the other tables/tree). Currently I'm having an issue with Java's jTree component. I have added a TreeSelectionListener and a MouseListener with a class that implements both interfaces, call it MyBigListener;
i.e.
MyBigListener listener = new MyBigListener();
jTree1.addMouseListener( listener );
jTree1.addTreeSelectionListener( listener );
MyBigListener implements TreeSelectionListener, MouseListener {
private boolean chained = false;
public synchronized setChained(boolean ch){
chained = ch;
}
public synchronized boolean isChained(){
return chained
}
public void valueChanged(TreeSelectionEvent e){
if(isChained()){ blah... }
}
public void mousePressed(MouseEvent e){
setChained(e.isControlDown() || e.isShiftDown());
}
}
My plan was to set a boolean flag if the user uses a ctrl/shift + click that I could check during the valueChanged(TreeSelectionEvent e) implemented by the tree selection listener.
I want to be able to process the mouse events before the valueChanged TreeSelectionEvents, but the problem is that I receive the mouse events after the valueChanged treeSelection event. This seems weird to me that I receive the selection change before the mouse pressed event fires, when the selection change is actually initiated by the mouse pressed. (I've already synchronized the boolean flag setting, which ironically helped to highlight the mis-order of events.)
I've already tried alternatives like adding a keyListener, but this doesn't work when the focus is on a separate frame, which goofs me up when a user holds ctrl and then clicks into the jTree causing it to receive both the focus and fire any valueChanged selection events.
Any help would be appreciated, thanks!
--EDIT-- #akf
I have separate jTables and jTrees in a tabbed Pane that serve as a summary/control panel for data in a nodal-graph. I'm using these components in the tabbed Pane to do coordinated selection to a graph displayed in a separate jFrame. Individually each table works just fine for its selection as does the jTree. It's coordinating between the panes that's tricky. This works fine so far with jTable components because I fire the new selections as the result of a MouseEvent where I can tell if the shift/ctrl button was down, formulate my new selection, and pass it to the parent frame which coordinates selections between all panes and sends the final selection to the graph. However, the parent needs to know if it needs to chain a selection between panes, or squash the others. With the jTables it's fine again, because I fire selection changes as the result of a mouse click. The jTree is more of a problem because I'm doing some forced selections. If you click on a branch, it forces all leaves into the selection. I needed to implement a TreeSelectionListener to do that, but only get a valueChanged(TreeSelectionEvent) to realized changes. I added a mouseListener to listen for ctrl+clicks and shift+clicks, but apparently the events don't always happen in the same order.. at least so far I receive the valueChanged event before the mousePressed event, so checking to if a ctrl+click happened posts after the selection has already been modified.
Right now, I'm posting a pending selection change and then have the MouseListener grab that and send it up the chain, but if these events aren't guaranteed to happen in the same order, at some point it's going to fail. Implementing a delayer also rubs me the wrong way.
Thanks for the help so far.
--EDIT2-- #ykaganovich
I think overriding the fireValueChanged method is closer to the right way to go about things. Depending on my definition of what actions should cause a "chained" selection to the other components, I'd need to gather some context on what's going on before the valuedChanged method fires. This basically means calling it myself in all cases where I can define what it means by who triggers it. I.e. If a mouse event causes it and ctrl is down then set what I need to set (interpret) then fire. If it's going to change due to a keyboard event, again, set what I need to set, then fire. I don't think the TreeSelectionModel is the way to go, because I still won't know what the circumstances were when the event fired. I think this means I'll need to rewrite parts of the jTree to do this but I guess I'll see how it goes. Thanks.
Don't do it that way, override JTree.fireValueChanged instead.
Try something like this (untested):
class ChainedSelectionEvent extends TreeSelectionEvent {
ChainedSelectionEvent(TreeSelectionEvent e) {
super(e.newSource, e.paths, e.areNew, e.oldLeadSelectionPath, e.newLeadSelectionPath);
}
}
protected void fireValueChanged(TreeSelectionEvent e) {
if(chained) { // figure out separately
super.fireValueChanged(new ChainedSelectionEvent(e));
} else {
super.fireValueChanged(e);
}
}
Then check instanceof ChainedSelectionEvent in your listener
EDIT
Actually, I think the right way to do this is to implement your own TreeSelectionModel, and override fireValueChanged there instead. Assuming setSelectionPath(s) methods imply a new selection, and add/removeSelectionPath(s) imply chaining, you could distinguish between the two cleanly. I don't like listening to either keyboard or mouse events explicitly, because there's more than one way to change a selection (e.g. if someone is holding down SHIFT and hitting a down-arrow, you won't get a mouse event).
You may get the mouse event before or after the tree selection event. Best not to rely on such orders. The reason is that the tree selection event is caused in response to the mouse event. Is that mouse event listener called before or after your listener? Could be either.
This sort of thing is closely involved with the implementation of the PL&F.
the key here is to understand that a JTree is delivered with a BasicTreeUI.MouseHandler, see javax.swing.plaf.basic.BasicTreeUI.
to answer the central question, "what fires fireValueChanged", the answer is "this mouse handler"... which turns out to be the only mouse listener returned when you go tree.getMouseListeners().
So you have to replace this default mouse listener with your own version ... which is a little tricky. I use Jython, which everyone needs to discover. This code shouldn't be too difficult to translate into Java however:
from javax.swing.plaf.basic import BasicTreeUI
def makeMouseHandlerClass():
class MouseHandlerClass( BasicTreeUI.MouseHandler ):
def mousePressed( self, mouseEvent ):
genLog.info( "mouse handler MOUSE PRESSED!" )
nTFSelf.mousePressedStatus = True
BasicTreeUI.MouseHandler.mousePressed( self, mouseEvent )
nTFSelf.mousePressedStatus = False
return MouseHandlerClass
suppliedMouseHandler = nTFSelf.taskTree.mouseListeners[ 0 ]
nTFSelf.taskTree.removeMouseListener( suppliedMouseHandler )
nTFSelf.taskTree.addMouseListener( makeMouseHandlerClass()( nTFSelf.taskTree.getUI() ))
... basically the equivalent Java here would be to extend BasicTreeUI.MouseHandler as MyMouseHandler, and then in the last line replace with new MyMouseHandler( tree.getUI() )... "nTFSelf" here is merely a reference to the "this" object of the code where all this is being written...
I have a Java program where I have a JMenu with an arbitrary number of items (in this case, there is one menu item for each dynamic library currently loaded in a different program). I'm running a loop to add JCheckBoxMenuItem s to the menu, since I don't know how many there will be.
How can I set up an action listener for these menu items that is aware of which option called it? Specifically, I want to run the same function but with a different set or parameters for each of the menu items (and a different function again depending on whether the check is being toggled or detoggled).
Could someone point me in the right direction?
While event.getSource() will definitely let you know which particular button the event came from it has the side effect of needing to track the generated buttons or snooping into the button. Also you may want to present a different name of the library to the user (possibly including the version information) than is used to identify the library. Using the "ActionCommand" property of the button may provide a way to separate those issues. So you will need to alter code in the generation of the checkbox menu items and in the listener.
ActionListener actionListener = ... // whatever object holds the method, possibly this
String[] libraries = ... // however you get your library names
JMenu parentMenu = ... // the menu you are adding them to
for (String s : libraries) {
// prettyName is a method to make a pretty name, perhaps trimming off
// the leading path
JCheckBoxMenuItem child = new JCheckBoxMenuItem(prettyName(s), true);
child.setActionCommand(s);
parentMenu.acc(child);
}
The action handler code would be...
public void actionPerformed(ActionEvent evt) {
// the 'current' selection state, i.e. what it is going to be after the event
boolean selected = ((JCheckBoxMenuItem)evt.getSource()).isSelected();
String library = evt.getActionCommand();
... process based on library and state here...
}
Definitely read over this: http://java.sun.com/docs/books/tutorial/uiswing/misc/action.html
In short, add ActionListener to the menuItems. In the actionPerformed method, use event.getSource(). You can add the SAME ActionListener to all your menu items if you want.
event.getSource() should do it.
When you build the menu you can pass the Action object to the JCheckBoxMenuItem configured with whatever options you need for given action (you can also push there the reference to the check box to check the state). This way you will not have to do any kind of processing when the action is actually performed, because the correct action will be invoked.
The clean way to do it is to create a different ActionListener for each. EventObject.getSource is fugly.