I have a main jFrame HomePage.java and many other classes which extend javax.swing.JInternalFrame. One of the classes (JInternalFrame) is Login.java. Now I check whether the password is correct in Login.java and if the password is correct, I load success.java. Now the problem arises when I have to load the success.java page.
I have a function in the HomePage.java whose purpose is to remove all internal frames and load success.java class. The function is as follows :-
public void LogIn(){
jDesktopPane1.removeAll();
System.out.println("Pos 2");
success frame = new success();
frame.setVisible(true);
jDesktopPane1.add(frame);
setContentPane(jDesktopPane1);
try {
frame.setSelected(true);
} catch (java.beans.PropertyVetoException e) {
}
}
I call the function in the Login.java page as follows :-
System.out.println("Pos 1 ");
(new HomePage()).LogIn();
The logic does not work. But, I receive the output as
Pos 1
Pos 2
which shows that the program flow was correct. I do not get any error also. Another weird factor is that when I calthe same LogIn() function from the menu in the jFrame itself, I get the desired output. Please solve my dilemma. Any help will surely be appreciated!
This code:
System.out.println("Pos 1 ");
(new HomePage()).LogIn();
Creates a new HomePage object and calls a method on it. Oh you are certainly calling the correct method, and it's going a HomePage instance, but it's not the correct HomePage instance, not the one that's displayed, because you've created a new one.
Short term solution: get a valid reference to the displayed HomePage instance and call your method on it. You could get it by passing it into the class that needs it as a constructor or method parameter, or you could use SwingUtilities.getWindowAncestor(...).
i.e.,
Window window = SwingUtilities.getWindowAncestor(Login.this);
if (window instanceof HomePage) {
HomePage validHomePageRef = (HomePage) window;
validHomePageRef.logIn();
}
Long term solution: don't create spaghetti code with GUI objects changing behaviors of other GUI objects, but instead refactor your code a la MVC or one of its variants, so the GUI can change the model and the other GUI objects can be notified of these changes via listeners and respond if they want.
Related
I have a class with only static methods and one of them opens a JOptionPane error message dialogue using a JFrame object as component.
This is the class + method:
public class miscMethods
{
static JFrame errorWindow = null;
public static void ErrorPopup(String message)
{
errorWindow = new JFrame();
errorWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
errorWindow.setAlwaysOnTop(true);
JOptionPane.showMessageDialog(errorWindow, message, "Error", JOptionPane.ERROR_MESSAGE);
errorWindow = null;
}
}
The ErrorPopup method is used inside a JavaFX controller and other places, called like this:
import static code.miscMethods.ErrorPopup;
...
ErrorPopup("This is the error message");
Problem is that the application's process won't close when I close the the program from the window's ✕ after the popup appears, because the JFrame was created and shown.
I know the JFrame is the culprit, so I added the errorWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
but it doesn't seem to do anything, since the program isn't closing.
In this question: JFrame and why stay running
The accepted answer talks about non-daemon threads, but the only thread I open is a daemon one, so unless JavaFX open one then it can't be that I believe.
So, why does the process keep running and how can I solve it?
I'm still new to Java so if I made a mistake and/or my code shows bad practices please do point them out!
Edit: I'm using a JFrame because I need the setAlwaysOnTop, since using
JOptionPane.showMessageDialog(null, message, "Error", JOptionPane.ERROR_MESSAGE); opens it not on top of the JavaFX window. If there's a better way let me know.
This:
errorWindow = null;
does nothing of use since the object is still displayed. You want this instead:
errorWindow.dispose();
Actually, even better, simply get rid of errorWindow altogether and pass null as the first parameter to the JOptionPane.
I want to dispose a frame in its constructor when the condition is true.
this.dispose is not disposing frame. I want that, when my constructor is called, if condition i.e (configurationBean.getCode().equals(macPass)) is true then a new frame have to be called and this frame must have to be closed. Else this frame have to be created.
public ConfigurationFrame() {
String pcMac = getPcMacAddress();
String macPass = getPassword(pcMac);
ConfigurationDao configurationDao = new ConfigurationDaoImpl();
ConfigurationBean configurationBean = configurationDao.checkCode(macPass);
if(configurationBean == null)
initComponents();
else if(configurationBean.getCode().equals(macPass))
{
new MainLoginFrame().setVisible(true);
this.dispose();
super.setVisible(false);
}
}
}
Note that your question is a classic "XY Problem" type question where you ask "how do I do X", when the best solution is "Don't do X but instead do Y". In other words you definitely do not want to dispose of a top-level window object such as a JFrame in its constructor as you're trying to do.
I think that what you want to do (a guess) is to
Test the configuration of things
If OK, display the main GUI
If not OK, then display a window that allows the user to re-set the configuration
Key point: then re-test if the configuration is OK,
And if so, then display main GUI
Repeat as necessary.
If so, then I would use a while loop to show the set configuration window and exit the loop if the configuration is OK, but also allow the user to exit the loop if they simply want to quit or can't set the configuration OK. Something like this:
// configurationGood: true if config is good
// justQuit: true if the user has had enough and wants to quit
while (!configurationGood && !justQuit) {
// create configuration dialog here
// calling constructors, and all
// use a **modal** dialog here
// change configurationGood and/or justQuit values in here
}
if (!justQuit) {
// create and display main application here
}
Note that
this code is not called within any GUI window constructor, but rather prior to displaying the GUI
The re-set configuration window shouldn't be a JFrame but rather a modal JDialog
This way the program code flow halts while the dialog is displayed and only resumes after the dialog has been dealt with.
This allows the code within the while loop to query the dialog the state of its fields and use this to re-test that the configuration is OK
I am making a library where an application can use it to capture a selection of a screen and convert it to an image, like Gyazo.
This library is not the application itself, but only the tool that returns the File or BufferedImage object to the application.
I want the application to be simple as this:
Bootstrap b = new Boostrap(new GifCapturer());
b.beginCapture(); // user selects an area
File file = b.getFile();
But how can I make the application wait till the library returns the object? as you see the beginCapture method should activate the JFrame where the user will select an area to capture.
Do I need to sleep the thread? or use listeners design?
The beginCapture method starts a jframe window, where the user is able to select an area of the screen. Once selected, the library will convert the selected area to an object and set it as a local variable. So when you will use getFile it ill return the captured image. But the thing is, i need to make sure that the image was selected before getFile call gets executed, and wait instead but im not sure how.
Sorry if the question is not detailed, im on phone.
Please let me know if you need more information.
Implement a listener, that is invoked as soon the selection is ready. Put your File file = b.getFile(); code into the listener.
The code of your JFrame would be necessary to give a more detailed answer.
I have decided to use a Listener with a own built listener class, and interface.
Create an interface which you will use to get the data, or that will get know when the listener gets called, like this in my case:
public static void main(String[] args) throws AWTException {
Bootstrap b = new Bootstrap(new GifCapturer());
b.beginCapture(new ScreenCaptureCallback() {
#Override
public void captureEnded(File file) {
System.out.println("done!");
}
});
}
I need to ask a small question because its irritating me.
How do i pass one vale from one frame to another frame in Java?
Below i have written a small script that is supposed to return the value but i dont quite know how to access it in the other frame.
Here is the code that is suppose to return the current value in a JcomboBox as a string into the other frame:
public String getUser(String user)
{
user = (String)jComboBox1.getSelectedItem().toString();
return user;
}
The way i thought it would work is to call a new instance of that class into the other frame (the classes name is editUser) so here is what i thought i would need to do.
public editPass()
{
initComponents();
editUser name = new editUser();
String test = name.getUser();
}
Thanks in advance for any advice.
The problem is that with doing this: editUser name = new editUser() is that you are creating a new instance (besides the fact that class names should start with upper case as per convention). This causes you to loose any data since you are now referencing a new object.
If you need to access data from the previous frame, what you would need to do would be to either:
Create a new object with all the relevant data and pass it to the next frame OR
Pass the current frame to the next frame. This will allow the new frame to be able to reference the previous one.
As a side note, the Card Layout might be relevant to what you are trying to achieve.
EDIT:
As per your comment question:
Assuming you have an editUser frame, say we call it frame1 and you populate all the data you need.
Then, the user presses Next, or something similar which causes him/her to go to the next frame, thus frame1 will either be hidden or non existant any more, depending on your implementation.
Let us call the second frame frame2. Now, in frame2 you need to access details stored in frame1. Doing like so: editUser name = new editUser(); will cause frame2 to create a new instance of frame1, thus meaning that you have created a new frame with empty values. Calling name.getUser() should not yield anything.
When I mentioned create an object with the relevant data I meant that, if you are editing user values, you could create an object which would have for instance all the information which was edited. So it could have fields like userId, originalUserName, newUserName, etc.
One the user presses Next in your frame1, you could create and populate this object and use it to transfer data from one frame to the next. In this case, the object you would be creating would be known as a Data Transfer Object (DTO).
So, the constructor of your second frame would look something like so:
public editPass(UserEditDTO userEditDTO)
{
initComponents();
String test = userEditDTO.getNewUserName(); //gets the new username the user has provided.
}
And in your editUser class, just before creating a new instance of editPass, you would do something like so:
...
UserEditDTO uEDTO = new UserEditDTO();
uEDTO = ... //set all the relevant fields here
new editPass(uEDTO).setVisible(true);
...
Alternatively, you can pass a reference to frame1 instead of a DTO. This approach is simpler. So your constructor for editPass would look like this:
public editPass(editUser editUser)
{
initComponents();
String test = editUser.getUser();
}
With your editUser code looking like so:
...
new editPass(this).setVisible(true);
...
I'm new to Java programming and am facing a (most likely) easy problem that I don't seem to be able to get across nor understand.
I have three different java files, one where I create an interface (SimulatorGui.java), other where I am creating a panel to use on the jTabbedPanel created in the interface (CollisionPanel.java - CollisionPanel class) and a third one, where I run a code that will create the output needed (Collision.java - Colision class).
In the Collision.java main method, I am doing the following:
public static void main (String[] args) {
//<editor-fold defaultstate="collapsed" desc="Simulation start procedures">
Tally statC = new Tally ("Statistics on collisions");
Collision col = new Collision (100, 50);
col.simulateRuns (100, new MRG32k3a(), statC);
//</editor-fold>
new SimulatorGUI().setVisible(true);
CollisionPanel update = new CollisionPanel();
update.updatepanel();
The first block, will create the desired output. I then want to send that output to the updatepanel! I am not passing any arguments to the method as I am still trying to debug this. updatepanel method is created in the file CollisionPanel as following:
public void updatepanel(){
System.out.println ("debug");
jTextArea1.setText("update\n");
}
What happens then is that when I run the Collision.java file it will output the "debug" text but won't set the text to the jTextArea1 (append doesn't work aswell). I then created a button to try and do so and in that case it works. In CollisionPanel.java:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
updatepanel();
}
This does the trick! I've searched and tried different things but can't seem to understand why this won't work.
Thanks in advance for your help, hope I've made the problem clear!
Okay I think I've eventually got the problem, and it is because of the IDE, you see in your main method you initiate a new CollisionPanel, which is wrong, netbeans has already added and initiated that panel in the SimulatorGUI, so now what you need to do is add a get method in the SimulatorGUI to get the initiated panel, then call the update method on that panel.
So add this to SimulatorGUI:
public CollisionPanel getCollisionPanel1() {
return collisionPanel1;
}
replace your old updatePanel() method with:
void updatepanel(String str) {
System.out.println ("debug");
jTextArea1.setText(str);
// jTextArea1.revalidate();
jLabel1.setText("test");
}
after that change your main too look like this:
SimulatorGUI simulatorGUI = new SimulatorGUI();
simulatorGUI.setVisible(true);
CollisionPanel cp=simulatorGUI.getCollisionPanel1();
cp.updatepanel("Hi");
and dont forget to remove the old updatePanel() method call from your CollisionPanel constructor, because now you can simply call cp.updatePanel("text here"); in your SimulatorGUI class instead of calling it only in the constructor.
I hope this is easy to grasp, if you're unsure let me know
Where do you add your CollisionPanel to the main GUI? I fear that this is your problem, and that you need to do this for your code to work. In fact where do any of your three classes get a reference to the others? For different classes to work in a program, there must be some communication between them. Understand that if you create a CollisionPanel object inside the GUI, and create another CollisionPanel object inside of the main method, calling a method on one object will have no effect on the other since they are two completely distinct entities.
For example, this code:
new SimulatorGUI().setVisible(true);
CollisionPanel update = new CollisionPanel();
update.updatepanel();
It appears that you are in fact calling updatePanel() on a CollisionPanel, but it's not on any CollisionPanel that is visualized in your GUI.
Consider giving SimulatorGUI a method that allows one to pass the CollisionPanel into it so that it can use it. This may in fact be a constructor parameter:
CollisionPanel update = new CollisionPanel();
SimulatorGUI simulatorGUI = new SimulatorGUI(update);
update.updatePanel();
Meaning SimulatorGUI's constructor would have to look something like:
public SimulatorGUI(CollisionPanel update) {
this.update = update;
// add update to GUI somewhere
}
There are three different levels when developping a GUI:
The view: the graphical component
The Model: the code that you run
The controller: checks if are update on the model in order to refresh the view.
So When you first start your program, the view will have the value assigned in the code; for instance say you created your JTextArea with the initial value type here. The view will show the JTextArea with the text type here.
When a change is made to the model, the view is not aware of it, it is job of the controller to check for update on the model and then refresh the view.
So this:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
updatepanel();
}
Will generate an event that say a property has been modify. So the controller will update the view.
Other than that, the change will not appear on the view.
Hope this helps..