A JFrame that won't disappear - java

I have a following situation: my program repeatedly calls something that makes a JFrame with text appear. I read the text from that frame. The frame has a special type, let's call it MyFrameType, so I recognize it by the type, and dispose of the frame at the end of each call, in all possible way of closing a frame I know of... (the following code is within a loop)
callMyFrame();
Frame[] frames = Frame.getFrames();
for (Frame openFrame : frames) {
if (openFrame instanceof MyFrameType) {
MyFrameType myFrame = (MyFrameType) openFrame;
(do something, read the frame etc.)
myFrame.setVisible(false);
myFrame.dispose();
myFrame.dispatchEvent(new WindowEvent(
myFrame,
WindowEvent.WINDOW_CLOSED));
break;
}
}
Now, the problem is: while the frame gets actually closed (which is not always case with the last frame for some reason - sometimes it gets closed, sometimes not), the closed frames are still listed by the frames array and the program ends up reading from the wrong frame - the first one of MyFrameType it finds, although only one of them is actually open. I know that getFrames() gets all frames created by the application. But how do I exclude those disposed frames, so that it doesn't just pick a random previously created, long forgotten frame? The frames in question have apparently no owner, so that removing ownerless frames does not do the job.

You can just check if the JFrame is displayable, here is a simple example that you can use to verify:
JFrame jFrame = new JFrame();
jFrame.setVisible(true);
jFrame.dispose();
System.out.println(jFrame.isDisplayable());
Output:
false
So in your loop instead of just checking if the JFrame is an instanceof MyFrameType you can do:
for (Frame openFrame : frames) {
if (openFrame instanceof MyFrameType && openFrame.isDisplayable()) {
}
}

You should set the frame in the array to null, or otherwise indicate that it is "deleted". Also, to do this you need to use a standard for-loop instead of the enhanced for-loop, something like this:
Frame[] frames = Frame.getFrames();
for(int i=0; i<frames.length; i++) {
if (frames[i] instanceof MyFrameType) {
(do something, read the frame etc.)
frames[i].setVisible(false);
frames[i].dispose();
frames[i].dispatchEvent(new WindowEvent(
frames[i],
WindowEvent.WINDOW_CLOSED));
frames[i] = null;
break;
}
}

Related

How to detect when a user presses a key outside of the app [duplicate]

This question already has answers here:
Java - checking if parseInt throws exception
(8 answers)
Closed 1 year ago.
So I tried to look a bit in forums and StackOverflow but nothing worked for me I need when enter is pressed to stop my code this is my code `
JFrame f;
JTextField I;
// JButton
JToggleButton b;
// label to display text
JLabel l;
f = new JFrame("AutoClicker");
i = new JTextField("100");
// create a label to display text
l = new JLabel("clicks/seconds");
// create a new buttons
b = new JToggleButton("Start");
// create a panel to add buttons
JPanel p = new JPanel();
// add buttons and textfield to panel
p.add(b);
p.add(i);
p.add(l);
// setbackground of panel
p.setBackground(Color.red);
// add panel to frame
f.add(p);
// set the size of frame
f.setSize(280, 80);
f.setVisible(true);
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int jml = Integer.parseInt(i.getText());
if(jml < 50)
{
jml = 50;
}
AutoClicker(jml);
}
});
}
static void AutoClicker(int jml)
{
while(true)
{
try{
Robot r = new Robot();
int button = InputEvent.BUTTON1_DOWN_MASK;
r.mousePress(button);
Thread.sleep(jml);
r.mouseRelease(button);
Thread.sleep(jml);
}
catch(Exception e){
e.printStackTrace();
System.out.println("not good");
}
}
}
}`
I tried to add a KeyListener but it did not work.
I don't understand why it doesn't work so if you can just help me know why it doesn't work it would be much apreciated.
KeyListener isn't going to solve the problem of the fact that you are simply not handling the potential of Integer.parseInt to throw an exception - I mean, how can it convert "" or "This is not a number" to an int. In those cases it throws an exception
The JavaDocs clearly state
Throws:NumberFormatException - if the string does not contain a
parsable integer.
Go back and have a look at the original error you were getting from your previous question on this exact topic
java.lang.NumberFormatException: For input string: "Enter"
It's telling you exactly what the problem is - the text "Enter" can not be converted to an int value.
YOU have to handle this possibility. No offence, but this is honestly basic Java 101. See Catching and Handling Exceptions
Another option which "might" help is to use a formatted text field
You also don't seem to have a firm grip on the concept of what a "event driven environment" is or what the potential risk of what doing something like while (true) will do if executed within the context of the Event Dispatching Thread. This makes me think you've got yourself in over all head.
You're going to want to learn about Concurrency in Swing as AutoClicker should never be called within the context of the Event Dispatching Thread, which is going to lead you another area of complexity, concurrency and all the joys that brings.
Updated
Wow, you changed the title. Maybe a better description of the problem you're trying to solve would have a gotten a better answer. In short, you can't, not natively in Java anyway. The only way you can detect keyboard input out side of the app is using native integration, JNA/JNI. Plenty of examples about, for example

Closing only a single instance of JFrame?

So I have two classes, Main and MakeUserWindow, inside of my Main class I call MakeUserWindow several times with different parameters by using a loop. The only problem is, this creates several windows that overlap each-other (Which isn't that much of a deal, it's just that I can get 20 windows on top of each-other). What I thought of doing was simply using window.dispose(); right before recalling the instance, however, when I do that it closes all instances of the window. Not allowing me to recreate the instance using the same variable. Is there a way of closing only the single instance like window.close(); that I am unaware about, or am is there just a better way of doing this? I have searched for awhile before coming here, no results have helped.
For some reference, here is a simplified version of what I am doing
(MakeUserWindow is a class that extends JFrame)
MakeUserWindow newWindow;
for(stuff){
newWindow.dispose();
newWindow = new MakeUserWindow("parameters here");
}
EDIT---
The reason I initialize MakeUserWindow outside of the loop is because I need to use newWindow's properties.
Thanks for reading, -Zach.
I had tested it and this is what i got:
JFrame frame = new JFrame();
for (int i = 0; i < 5 ; i++) {
frame.dispose();
frame = new JFrame();
}
More or less like your code. Only the last frame survived cause you are closing the others when you do the ".dispose()". What you can do is a Map that keeps all the instances.
Map<String, JFrame> frames = new HashMap<String, JFrame>();
JFrame frame = new JFrame();
for (int i = 0; i < 5 ; i++) {
frame = new JFrame();
frames.put("Window" + i,frame);
}
And if you want to close a frame you do:
frames.get("WindowX").dispose();

Why won't .validate() update the contentPane in this code?

I'm having trouble with a contentPane. Here's the code in question:
public void graph() {
JFrame frame = new JFrame("Graph");
Graph[] graphs = new Graph[timeSlices];
int k = 0;
for (TreeMap<MyPoint, BigDecimal> prevU : prevUs) {
graphs[k] = new Graph(prevU);
k++;
}
// The KeyList handles switching between graphs.
frame.addKeyListener(new KeyList(frame.getContentPane(), graphs));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(810, 500);
frame.setVisible(true);
}
private class KeyList extends KeyAdapter {
private Container contentPane;
private Graph[] graphs;
private int index;
public KeyList(Container contentPane, Graph[] graphs) {
this.contentPane = contentPane;
this.graphs = graphs;
this.index = 0;
this.contentPane.add(this.graphs[0]);
}
public void keyPressed(KeyEvent e) {
// Go back a time step
if (e.getKeyCode() == KeyEvent.VK_LEFT && index > 0) {
contentPane.remove(graphs[index]);
contentPane.add(graphs[--index]);
contentPane.validate();
System.out.println(index);
}
// Go forward a time step
else if (e.getKeyCode() == KeyEvent.VK_RIGHT && index < timeSlices - 1) {
contentPane.remove(graphs[index]);
contentPane.add(graphs[++index]);
contentPane.validate();
System.out.println(index);
}
// Exit if Esc is hit
else if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
System.exit(0);
}
}
Graph is just a Component, easy peasy. When I hit the right arrow, I want to replace the currently displayed Graph with the next one in the array, and when I hit the left arrow, I want to replace the Graph with the previous one in the array.
The weird thing is that when I hit right, it works just fine. However, when I hit left, the Graph doesn't change. The index changes, thus I know the code is being reached, but the GUI doesn't change.
Now get ready for this. When I comment out the right key's validate line, the left one will work about half the time. What is going on there? Here's the rest of the code if you want to run and see for your self (just one file) : http://pastebin.com/qWxWrypK. The starting paramemters I'm currently using are T=1, dt=.01, L=1, h=.05.
I was looking into it, I thought it might be because the contentPane of a JFrame is really a JPanel, but that line of thinking didn't get anywhere...
Thanks for any help
Edit:
So I'm still working with it. Here's another weird thing. If I set the index in the KeyList class to timeSlices-1 (basically getting the last Graph in graphs array), and I hit left, it works! But, now the right doesn't! Something weird has to be going on with the array or something because the index changes just fine. Hmm.
Edit:
Something's going on with the array. For some reason, the Graph can only be used once. Perhaps it's being destroyed on removal? Or something like that...
Instead of trying to remove/add panels to a container use a CardLayout which was designed for this purpose.
Also, don't use KeyListeners. Instead you should be using Key Bindings. Then you simply bind the next/previous keys to the next/previous methods of the card layout.

Problem in Java swing code

I intend to take the elements of an integer list and add it to a label and print them in downward fashion one after another. I wrote the following code for it.
public static JFrame ListDraw(JFrame frame , ArrayList<Integer> e)
{
for(int i= 0;i<e.size();i++)
{
JLabel j = new JLabel(e.get(i).toString(),JLabel.CENTER);
frame.add(j);
}
return frame;
}
But it just prints the last array element in the label. What am I doing wrong here?
---------------------(update)
This is just a query that I have regarding the same thing. Therefore I am going to ask it here only. Is there any way to print the label items in a stack as in vertical alignment. Right now I get all the values printed in the horizontal fashion.
I guess you need to set layout for your frame, f.ex: frame.setLayout(new FlowLayout());.
Your frame isn't adapting to the new group of elements- the LayoutManager isn't getting a chance to resize the window. At the end of your function, add frame.pack().
You should use setBounds() to define the size of your frame and give it a LayoutManager of your choice.

Maintaining a single instance of JInternalFrame?

I have an application which opens multiple JIFs, But I only want to create a single instance of the JIF, so I use these function to check that, and I use dispose to close the JIF after a key is pressed(JDesktopPane.getSelectedFrame().dispose()). However after 2-3 successive disposes, it doesn't create a new JIF? Am I doing anything wrong over here?
public static void setInternalFrame(final JInternalFrame internalFrame) {
log.debug("CurActiveInternalFrame " + ShoppyPOSApp.getCurrentActiveInternalFrame(), null);
log.debug("Incoming internalFrame " + internalFrame, null);
boolean isFrameFound = false;
try {
// Have a check whether the DesktopPane contains the internal Frame
// If yes bring it to front and set the focus
for (int i = 0; i < ShoppyPOSApp.frame.mainDesktopPane.getAllFrames().length; i++) {
if (ShoppyPOSApp.frame.mainDesktopPane.getAllFrames()[i].getClass() == internalFrame.getClass()) {
isFrameFound = true;
}
}
if (!isFrameFound) {
internalFrame.setVisible(true);
internalFrame.setLocation(
ShoppyPOSApp.frame.mainDesktopPane.getWidth()/ 2 - internalFrame.getWidth() / 2,
ShoppyPOSApp.frame.mainDesktopPane.getHeight() / 2 - internalFrame.getHeight() / 2
);
ShoppyPOSApp.frame.mainDesktopPane.add(internalFrame);
}
internalFrame.setSelected(true);
} catch (Exception e) {
log.debug(e.toString(), null);
}
}
You are comparing the classes of your input parameter and your desktops internal frames in your for loop. This will always be true as your parameter is an instance of JInternalFrame and the getAllFrames method returns an array of JInternalFrames. Why not just do a regular comparison? :
ShoppyPOSApp.frame.mainDesktopPane.getAllFrames()[i] == internalFrame
I would recommend using HIDE_ON_CLOSE as your default close operation on the frames and using setVisible(false) in your key listener instead of dispose(). When frames are disposed they are closed and you should not try and reuse a frame after is has been closed. If you just hide the frame it will still be a child of the desktop pane so you shoud add a call to setVisible(true) when you find a frame in your setInternalFrame method.
It sounds like you're getting inconsistent behaviour (you say it fails after two or three disposes). This suggests to me that you have an event thread problem. Is your setInternalFrame being called on the event thread? Are you familiar with the Event Dispatch Thread and are you using it correctly?
I don't think dispose is doing what you mean for it to do. dispose gets rid of the operating system "peer" of your frame. But if you intend to show that frame again, then you shouldn't throw away its underpinnings!
I'd go with setVisible(false) on the JIF to hide it. Then you can re-activate it with setVisible(true).

Categories