I have a program that should issue some action when it gets activated after loosing focus to some other application before. I wrote a Focus-Listener to achieve this:
frame.addWindowFocusListener(new WindowFocusListener() {
#Override
public void windowGainedFocus(WindowEvent e) {
<do something when we gain focus>
}
#Override
public void windowLostFocus(WindowEvent e) {
<do something else when we lose focus>
}
});
Problem is, the gain-focus-action is also called when a modal dialog (for instance an authentication dialog) closes - the main window gains focus again. So I somehow would need to detect, if I gain focus from within my program or from the outside. Or, differently put, the focus action should not be located on the main window but on the application itself. What would be a simple way to do this?
Thanks #Aelop for helping me find an answer. e.getOppositeWindow() is null for windows of other applications, so I can neatly distinguish from where I'm coming from:
frame.addWindowFocusListener(new WindowFocusListener() {
#Override
public void windowGainedFocus(WindowEvent e) {
if (e.getOppositeWindow()==null) {
<do something when we gain focus>
}
}
#Override
public void windowLostFocus(WindowEvent e) {
<do something else when we lose focus>
}
});
if you didn't find a good solution use static variable when the focus is lost from a dialog in your application set a static boolean variable to true so when the focus is gained and the variable is true means that the focus is from some window in the application else the focus is from somewhere else i hope you get the idea try it if you didn't find some application or check the type of the source who lost the focus
Related
I need to write a Java Swing application that will run and act about the same on Linux, Windows and Mac. And for virtually all Widgets I create, I need to add some special handling, including, everything needs to be able to pop up a menu when asked. Even widgets like labels and buttons.
I'm able to catch menu requests by adding:
MouseListener m = new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e)
{
if (e.isPopupTrigger())
{
onMenuSummons(); //do my thing
}
}
};
addMouseListener(m);
to the constructor on my extended widget.
But I'm concerned that this is a Linux-only solution. Do I only need to check isPopupEvent() in MousePressed? What about MouseClicked? I could hook both to be sure, but do I run a risk that some platform someday would have isPopupEvent() be true in both functions for the same mouse action?
Ideally MouseAdapter would spare me the question by offering an overridable popupRequest(MouseEvent e), but it doesn't. So what is the always right, works everywhere on all platforms and always will forever solution?
Also, some of the widgets I'm extending may have their own popup menus; I need to suppress those and implement my own. How do I make sure only my own menu is displayed? TIA.
Read the section from the Swing tutorial on Bringing up a Popup Menu for the basic of using menus and popup menus.
To write a MouseListener the basic code is:
class PopupListener extends MouseAdapter {
public void mousePressed(MouseEvent e) {
maybeShowPopup(e);
}
public void mouseReleased(MouseEvent e) {
maybeShowPopup(e);
}
private void maybeShowPopup(MouseEvent e) {
if (e.isPopupTrigger()) {
popup.show(e.getComponent(),
e.getX(), e.getY());
}
}
}
some of the widgets I'm extending may have their own popup menus; I need to suppress those and implement my own.
Also note the the example from the tutorial is older. The newer approach for adding a popup menu to a component is to use:
component.setComponentPopupMenu(....);
Not sure, but since this method only allows a single popup it may replace the default popup?
So I am currently doing some work with Multi-Threading in Java and I'm pretty stuck on a, most likely, simple thing.
I currently have a JButton that, when pressed invokes the method as follows:
private void clickTest() throws InterruptedException{
statOrganizer.incrementHappiness();
Thread t = new Thread(new Happiness(workspaceHappy));
t.start();
}
and then takes around 10-30 seconds to complete. During this time however, it is still possible to re-click the JButton so that it messes with how the information is displayed.
What I want to do is during the time this particular thread is "alive", disable the button so that it is no longer possible to click it(and thus activate this thread once it's already going). Once the thread is finished, I want to re-enable the button again.
The button code just looks like this
button.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent evt) {
if (evt.getClickCount() == 1) {
try {
clickTest();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Disable the button right before starting the thread. In the thread, at the end, post an event that would re-enable the button (using invokeLater).
You may also need a cancel option, but that's a separate question.
Try the following:
button.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent evt) {
if (evt.getClickCount() == 1) {
try {
clickTest();
button.setEnabled(false);//this assume 'button' is final
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Then, modify the run method of your Happiness class:
public void run()
{
//your processing code here
...
button.setEnabled(true);
//reference to button can be passed in constructor of Happiness
// or access using getter, ... This really depend on your implementation.
}
The nice solution for this is to use a glass pane to capture all events and stopping them from propagating to any of your UI elements on the panel under the glass pane. Of course while you only have one or two, you can call setEnabled(false) on them manually but glass panes give you more flexibility, you'll never have to worry about adding a new element to your UI and forgetting to disable it during background processing.
Probably an overkill for one button though.
Another, unrelated thing you should consider is the use of Executors instead of launching threads for background tasks. It results in cleaner and more scalable code.
My users like having multiple JFrames; it allows them to resize the different components and place them wherever they want on the screen. However, I have a request to make all the child windows come to the front together... in other words, lets say they maximize another window in front of all the windows, and then use the task bar to click on just one of the JFrames. How can I set it so that they all come to the front? Note: it is also possible to close the child windows; if they are actually hidden, I do not want them to come to the front. I have a class ApplicationModel that keeps track of whether a window is hidden or not.
Things I've tried:
Using windowActivated() and focusGained() to try to bring them all to the front. This usually results in an infinite loop. The problem is that my eventing framework sends these requests off the Event Dispatch Thread, so any sort of blocking with an AtomicBoolean doesn't last long enough.
The main problem is not that I can't make them come to the front... I have made them come to the front. The problem is that they KEEP trying to come to the front, as bringing a window to the front throws the focusGained and windowActivated events, which creates an endless loop...
Making one window the master, and making the others a JDialog. Unfortunately, either the windows are modeless (and therefore don't come to front with the master window), or they are modal, (and therefore block the master window).
How can I fix either of these problems, or is there an entirely different third solution?
You can use a boolean field as a flag to prevent the infinite loop:
private boolean movingAllFramesToFront;
public void windowActivated(WindowEvent event) {
if (movingAllFramesToFront) {
return;
}
movingAllFramesToFront = true;
List<Frame> frames = getAllApplicationFrames();
for (Frame frame : frames) {
if (!applicationModel.isHidden(frame)) {
frame.toFront();
}
}
event.getWindow().toFront();
event.getWindow().requestFocus();
EventQueue.invokeLater(new Runnable() {
public void run() {
movingAllFramesToFront = false;
}
);
}
Another thing you can try is the new autoRequestFocus property introduced in Java 1.7. I have never tried using it, but here's my understanding of how it works:
public void windowActivated(WindowEvent event) {
final List<Frame> frames = getAllApplicationFrames();
for (Frame frame : frames) {
if (!applicationModel.isHidden(frame)) {
frame.setAutoRequestFocus(false);
frame.toFront();
}
}
EventQueue.invokeLater(new Runnable() {
public void run() {
for (Frame frame : frames) {
if (!applicationModel.isHidden(frame)) {
frame.setAutoRequestFocus(true);
}
}
}
);
}
I have an application with a lot of windows and had a problem similar to yours. My workaround is:
#Override
public void windowActivated(WindowEvent e) {
if (e.getOppositeWindow() == null) {
//front every window
}
}
First I created a class "SlveFrame" (Slve being the name of my app), a child of "JFrame".
public class SlveFrame extends JFrame implements WindowListener {
static ArrayList<SlveFrame> frames = new ArrayList<SlveFrame>();
public SlveFrame () {
addWindowListener(this); / /to make JFrame fire WindowListener's method
}
/ /... every method added from WindowListener
#Override
public void windowActivated(WindowEvent e) {
if (e.getOppositeWindow() == null) { // return null if window is not from my (or Your) work
for (SlveFrame frame : frames) { // if you have no idea what this is, look for "for each loop java" in google
frame.toFront();
}
}
}
/**
* The use of SlveFrame is almost the same as Jframe
*/
#Override
public void setVisible (boolean b) {
if (b)
frames.add(this);
else
frames.remove(this); // may raise an exception if you're not careful
super.setVisible(b); // or your window will simply not be visible.
}
#Override
public void dispose () {
frames.dispose(this) // may raise an exception you'll want to handle
}
}
The trick being that WindowEvent.getOppositeWIndow() returns a Jframe if the JFrame (or child class) is from your own program, meaning that if you switch to another program or app (such as eclipse, Firefox or a text editor) then back to any of your windows, then a call to getOppositeWindow() will return a 'null'. A simple if (e.getOppositeWindow()) makes it fairly easy to determine whether your window gain focus in condition that would require you to bring every window to the front, or rather to let everything be.
The overriding of setVisible (boolean b) and dispose () are optional but allow the dev to use it as a regular window.
I hope i could be of some help. Sincerly ~a lama
I have a view that has several "flag" buttons (JToggleButton). When the user clicks a flag button, I want to update an array that keeps track of which buttons are flagged. This is pretty simple, and here is what I have done:
...
bflag[i].addItemListener(this); //View listens to state change
...
void itemStateChange(ItemEvent ie) {
try {
jtb = (JToggleButton)ie.getSource();
//Update mark array
}
catch (ClassCastException cce) {}
}
This works just fine, but it is ugly with the try/catch. I would much prefer to do something like this:
void itemStateChange(ItemEvent ie) {
handleStateChange(ie.getSource());
}
void handleStateChange(JToggleButton jtb) {
//handle state change
}
void handleStateChange(Object o) {}
This is much nicer, but the only problem is that the Object method will fire even if the source is a JToggleButton (because a JToggleButton is an Object after all).
I have also considered using double dispatch, but this would require overriding the JToggleButton method that fires itemStateChange(), and I don't know what that is (and that seems unsafe).
Any suggestions on how to get this to work without a try/catch, conditional check, etc.?
You will have to check for the Type explicitly I think.
if(ie.getSource() instanceof JToggleButton){
//toggle button logic
}else{
//something else
}
Alternatively you can use anonymous inner classes to implement your listeners and avoid having to check the source altogether.
Something like this:
toggleBtn.addItemListener(new ItemListener(){
public void itemStateChange(ItemEvent ie){
//handle toggle button event
}
});
I'm trying to listen for a window close event on the parent JFrame of a JPanel. In the WindowClosing event I'd like to de-register a listener to a different component.
Unfortunately the only code I can gaurantee to have run is the constructor for the panel. What this means is that the panel itself doesn't have an ancestor window yet, so simply calling SwingUtilities.getWindowAncestor doesn't work. So what I do is register a hierarchy listener, and in the hierarchyChanged event look for SHOWING_CHANGED event. When that even fires, now I can look for the window ancestor of the panel.
So basically I have the following:
class ShapeControlPanel extends JPanel{
public ShapeControlPanel(){
final ShapeControlPanel me = this;
me.addHierarchyListener(new HierarchyListener() {
#Override
public void hierarchyChanged(HierarchyEvent e) {
if((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) == HierarchyEvent.SHOWING_CHANGED){
SwingUtilities.getWindowAncestor(me).addWindowListener(new WindowListener() {
/* Snipped some empty handlers */
#Override
public void windowClosing(WindowEvent e) {
/* Finally get to remove the handler. */
me.getApparent().removeLocationSelectionListener(me.GUID(), me);
}
});
}
}
});
}
}
Is this sane? Is there a more reasonable way of getting a handle on the frame closing event?
It's not the ugliest thing I've seen (I wouldn't even say it's all that bad), but you have to ask yourself: why does your panel really need to know when the window is closed? It seems to be an odd coupling that would best be removed.
I don't know enough about your context and what you are truly trying to accomplish to suggest an alternative right now. But if a panel needs to know about the container in which it resides, there is probably some bad design with harmful coupling.