I am coding MVC. In my controller i am listening to the action and if the user clicks a "SHOW-LIST" button i am making an instance of my view class which extends from JFrame and therein the view class i create a new JFrame. My problem is that if i click on SHOW-LIST button multiple times, i have the frame opened multiple time. Can somebody please tell me how can i do so so that once a new frame is about to open the old frame closes..
Controller
public void actionPerformed(ActionEvent event) {
String viewAction = event.getActionCommand();
...
if (viewAction.equals("SHOW-LIST")) {
showListUI = new ShowListDialogUI(displayedCustomerList);
}
}
View
class ShowListDialogUI extends JFrame{
public ShowListDialogUI (List<Customer> customerList) {
..
// I am drawing it here
..
}
}
Can somebody please tell me how can i do so so that once a new frame
is about to open the old frame closes..
use CardLayout, then there no reason to playing with Top-Level Containers, put there required number of JPanels, then just to switch betweens JPanel views
as #trashgod notified, really not good idea, way
otherwise have to clean-up (remove all contents) uselless container, because Top-Level Containers never will be GC'ed
Well, depends on the use case, but instead of closing the old one, and creating the new one, you could focus the existing one (and probably update data?).
Your controller can manage the frames and keep track of it. In the most easiest (and not recommended) way, you have a boolean "isFrameOpen". You set it to true if you open the frame, to false if you close it (your frame has to communicate with the controller then, or the controller has to know about the status of the frame at least). If boolean is true, then focus/recreate it. If false, create a new one.
In more advanced solutions, you can keep track over all frames with a map and you have to deal carefully with concurrent access.
--tb
Related
Experts, need some help.
I have created JFrame in say class 'A' and have added JTabbedPane using NetBeans IDE, also have added a first JPanel to this JTabbedPane. On this JPanel, I have JCheckbox that adds and removes new tab (instance of JPanel) based on the checked/unchecked event. The panel being added & removed is defined in another say class 'B' that extends JPanel. This JPanel has a timer task which runs in a specific interval, get some data from REST resource and update the contents in the JPanel's body as shown below:
private void refreshAgentUtilizationData() {
TimerTask updateAgentDetailsTask = new TimerTask() {
#Override
public void run() {
agentObj.updateData();
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
memChart.repaint();
System.out.println("This is from Agent monitor timer task...");
}
});
}
};
agentMonTimer.scheduleAtFixedRate(updateAgentDetailsTask, 0, master_pollingInterval);
}
JCheckBox action performed (in class 'A') looks below,
Some details first:
AgentMon_ChartsUI = Class that extends JPanel and being added to JTabbedPane i.e. class B
agentMonTabs = JTabbedPane that resides in say class A
private void agentMonSwitchActionPerformed(java.awt.event.ActionEvent evt) {
if (agentMonSwitch.isSelected()) {
AgentMon_ChartsUI agentChartPane = new AgentMon_ChartsUI();
Icon agentIcon = new javax.swing.ImageIcon(getClass().getResource("/resources/abc.png"));
agentMonTabs.addTab("Agent runtime monitor", agentIcon, agentChartPane);
agentMonTabs.setSelectedIndex(agentMonTabs.indexOfTab("Agent runtime monitor"));
} else {
agentMonTabs.remove(agentMonTabs.indexOfTab("Agent runtime monitor"));
}
}
The problem is: I am not able to find graceful way to dispose the instance of JPanel which is removed on checkbox's uncheck event. When I uncheck it, I can see the tab is being successfully removed and it looks like the panel is now gone, but I can see that the System.out.println... is still being executed in timer's job. This means that Jcheckbox > Uncheck simply removes the tab but does not dispose it.
I checked other questions on StackOverflow (this & this) and it is confirmed that once the references are set to null, the GC will take care of it. I am not sure in this case, how should I set the reference to null, as I am simply removing the panel from JTabbedPane. I monitored my application for good amount of time and I didn't see GC clearing it out. Am I looking at it correctly? What is correct & recommended way to dispose/nullify the panel which was removed from JTabbledPane?
There are a number of possible ways you might deal with this. One of the simplest would be to override the removeNotify method of the JPanel. This is called when ever the component is removed from it's parent container.
#Override
public void removeNotify() {
super.removeNotify()
agentMonTimer.cancel();
agentMonTimer.purge();
agentMonTimer = nil;
}
NB: You can cancel the TimerTask instead, if the Timer is shared, but you will need to maintain a reference to it when you create it
I'm not sure I'm following all of this, but it sounds like the tab you are trying to dispose of is represented by a JPanel subclass B which contains a reference to a timer, and that the evidence that the timer is continuing to run is your evidence that B still exists?
But if the timer existence is dependent on that instance of B, wouldn't something in the timer infrastructure have a reference to B? It is not the least clear to me why you aren't trapping the event and disposing of the timer class as well, you can't expect dispose code to do that for you.
In addition, you cannot just monitor the program for a period and decide whether the GC has done whatever it will do. What instances it cleans up, and how soon and so forth, are not entirely time-based. The ones I've spent any time with don't run until the program is low on memory, to start with.
I have a GUI that extends JFrame which is created by this constructor of another object:
public Engine(int width, int height) {
//ui is the GUI object declared as a field of this object
ui = new UI(width, height);
ui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ui.setVisible(true);
}
The GUI's eventListener also creates new threads when certain buttons are clicked:
public void actionPerformed(ActionEvent actionEvent) {
if(actionEvent.getSource().equals(ui.play)) {
if(clickerThread == null) {
autoClicker= new AutoClicker();
clickerThread = new Thread(autoClicker);
clickerThread.start();
}
}
}
Does this mean when I hit the X button on the window, everything related to this program (such as the autoclicker thread, everything in the memory allocated to this program) get cleared and does not slow down the computer in the future?
Or, would System.exit(0) be needed somwhere somehow in order to make it as if this application was never opened after the computer had started and closed the application?
Thanks in advance!
Per the JFrame API:
public void setDefaultCloseOperation(int operation)
Sets the operation that will happen by default when the user initiates a "close" on this frame. You must specify one of the following choices:
DO_NOTHING_ON_CLOSE (defined in WindowConstants): Don't do anything; require the program to handle the operation in the windowClosing method of a registered WindowListener object.
HIDE_ON_CLOSE (defined in WindowConstants): Automatically hide the frame after invoking any registered WindowListener objects.
DISPOSE_ON_CLOSE (defined in WindowConstants): Automatically hide and dispose the frame after invoking any registered WindowListener objects.
EXIT_ON_CLOSE (defined in JFrame): Exit the application using the System exit method. Use this only in applications.
So yes, this will exit the application by calling System exit for you.
Just a little side warning: if your threading is wired incorrectly, and you have long-running code that happens to tie up the Swing event thread, the EDT, then the JFrame's termination button won't respond until the EDT is unblocked.
Side recommendation 2, regarding:
I have a GUI that extends JFrame...
I recommend against creating classes that extend top-level windows such as JFrames since this creates inflexible classes that can only be used as a JFrame. Much better to gear your GUI classes to create (or if need be, extend) JPanel since this way your GUI can be displayed in many different contexts -- in a JFrame, a JDialog, in another JPanel, in a JTabbedPanel... it frees your code up a bit.
Side recommendation 3: regarding creating new threads in a Swing application, if the auto clicker will interact with the Swing application itself, then you may wish to consider using a SwingWorker to help create your background thread since this construct has mechanisms within it that help safe communication between background thread and the GUI without breaking Swing threading rules. Google "Concurrency in Swing" for more on this.
I have 3 JFrames which use a common JFrame for the purpose of selecting a customer from the complete list. These are the 3 JFrames.
AddPayment
AddInvoice
AddPurchase
All these interfaces use a common JFrame called SelectCustomer which has a listbox from which the user can select one customer from the complete customer list. The name of the selected customer should appear in the JFrame which called the SelectCustomer JFrame.
I know I can use a static jTextField to access and set the value. What I want to know is how can I know which of the above 3 called this SelectCustomer JFrame so that I can decide where the selected value should go.
One of the gui which causes the SelectCustomer JFrame to appear:
http://i.imgur.com/l85k4kQ.png
Select Customer JFrame:
http://i.imgur.com/sD7hp7s.png
I hope my question is clear. Thanks!!
if you are using a button to open the frame and then use this in the same action listener
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(!frame2.isVisible())
frame2.setVisible(true);
}
});
Ehm, maybe this answer seems silly, but have you tried sending some reference when you are calling the class, either from the 3 JFrames?, since I think there is no function that can tell you who called the current JFrame.
So, when you call the SelectCustomerFrame, you could do something like
new SelectCustomerFrame(whatever params, this);
It will require three different constructors in the SelectCustomerFrame in order to sort out who actually called the SelectCustomerFrame, each of them capturing the distinct classes.
Hope to have sourted out your troubles.
This seems like a simple behavior, but I'm having difficulty making it happen. I'm working on software which graphs data. I want to redraw the graph when the user hits enter. Well more accurately I want to draw the graph when the user hits enter and doesn't have a text field selected; but for now I'll be satisfied with drawing whenever the user hits enter.
I tried installing a basic KeyListener to the frame first, but that doesn't work since the JFrame children, not the frame, receive the event.
I then tried to use the KeyEventDispatcher, but it's proving too global a concept. I can have two graphs on screen at once, and an old graph can be closed or replaced with a new graph. With the KeyEventDispatcher I have no easy way of knowing which plot I want to activate out of the multiple plots open at a time and the plots currently open now may not be the plots that were opened when I instantiated the key dispatcher. I know this solution could still work, but it requires my storing extra data as to what plot is currently active that doesn't fit well into the program architecture.
It seems as if there should be an easier method to capture any KeyEvents dispatched to a JFrame/JPanel or any of the JFrame's children; but ignore events dispatched to other frames. Preferable a method that can be added to the frame and thus is automatically disposed when the frame is disposed. Can anyone suggest a simpler method then what I've tried?
Don't use a KeyListener.
Add a Key Binding to the graph panel.
This works very well
this.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "fecharAction");
this.getRootPane().getActionMap().put("fecharAction", new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
int resp = JOptionPane.showConfirmDialog(MainForm.this, "Encerrar sistema?", "Confirmação", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
if (resp == 0) {
MainForm.this.setVisible(false);
MainForm.this.dispose();
}
}
});
I'm writing a Java app (Swing GUI) that periodically pops up a JFrame.
Is it possible somehow to bring the window to front (foo.setAlwaysOnTop(true) would be even better) but without having it focus?
Some people move their eyes away from the screen from time to time to look at their keyboard while typing, and I'm sure that if this window would always capture the keyboard focus people would get really annoyed as it's causing them to lose quite a few keystrokes every time it pops up unnoticed.
In other cases, even when the user is actually capable of typing without looking at the keyboard all the time, having a window pop up and get focus could cause unwanted actions from the pop-up window itself (some Tab+Enter combination for example, where the user accidentally selects an option she really wouldn't had selected otherwise).
Thanks in advance!
Update
As Jonas suggests, foo.setFocusableWindowState(false); seems to work if called after the window has been rendered (tested on Gnome only).
This does not work:
foo.setFocusableWindowState(false);
foo.setVisible(true);
foo.setFocusableWindowState(true);
However, this does:
foo.setFocusableWindowState(false);
foo.setVisible(true);
Thread.sleep(1000);
foo.setFocusableWindowState(true);
I'll have to see if there's an event I can catch/listen to that allows me to do foo.setFocusableWindowStatue(true); when appropriate.
I consider my problem solved.
This may work:
foo.setFocusableWindowState(false);
As of Java 1.7 you can call
frame.setAutoRequestFocus(false);
I recently ran into the same problem, and the tentative solution has been:
JFrame frame = ...;
frame.setExtendedState(JFrame.NORMAL);
frame.setAlwaysOnTop(true);
frame.requestFocus();
frame.setAlwaysOnTop(false);
Suggestion: In the GUI Component that creates the Frame, put 2 consecutive calls:
frameJustCreated.requestFocus();
this.requestFocus();
1st one bring the window of the new JFrame to the top, 2nd one keeps the window where the user is typing at the top.
If you want to call setFocusableWindowState(true) in an event (so, not to wait e.g. 1 second), you can add a WindowListener (e.g. derived from WindowAdapter) that changes the property:
appFrame.addWindowListener(new WindowAdapter() {
#Override
public void windowOpened(WindowEvent e) {
super.windowOpened(e);
e.getWindow().setFocusableWindowState(true);
}
});
appFrame.setFocusableWindowState(false);
appFrame.setVisible(true);
JInternalFrame toFront() calls to moveToFront()
Override moveToFront()
public void moveToFront() {
Window window = SwingUtilities.getWindowAncestor(this);
Component focusOwner = (window != null) ? window.getFocusOwner() :
null;
boolean descendant = false;
if (window != null && focusOwner != null &&
SwingUtilities.isDescendingFrom(focusOwner, this)) {
descendant = true;
requestFocus();
}
super.moveToFront();
if (descendant) {
focusOwner.requestFocus();
}
}
the fix is in moveToFront to check if a child has focus, if it does, then temporarily request focus on the internal frame. After the internal frame has movthe ed to front, then request focus back on the previously focused component. This will ensure the appropriate events are generated.
refer
https://bugs.openjdk.java.net/browse/JDK-4309079