I've set up a Server which runs and accepts connections from my Remote Client, and now I'm working on my GUI.
Before anything else, my goal here is to create a nice looking client that will have a login screen (login/pw), and then a nice layout with my options/perhaps a chat box after the user has logged in.
I've searched a lot online and used this site to set up my server and get things working, but I've got a bit of a problem with the GUI/theory and hope someone here can guide me a bit.
At the moment, I've set up a class called ClientGUI which is called from my main class, and this produces a 420x240 size screen. After placing my login/password JTextField boxes here, is it "proper" to set up the other GUI's the way I've outlined below? I'm not sure if I should be putting them under one class or how I would advance from one GUI to the next. I'm thinking I should repaint and resize the screen as necessary, but I am not sure how to set it all up. A brief outline would be helpful (you don't need to give me exact code).
public class ClientGUI extends JFrame {
public ClientGUI() {
setSize(420,240);
setVisible(true);
setTitle("Title");
setResizable(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(null);
}
public loginGUI() {
//code for my login/pw boxes, images, listener for entering information
}
public afterlogginginGUI() {
}
paint() {
//not too sure about how this should be setup either. Should I do all my textfield
//and image work in paint()?
}
}
I have never made anything like this, so I have the feeling I'm not setting this up in an ideal way.
An alternative is to have a different java class extending JFrame for each 'screen' I want, but if I do it this way, would I do it like this?
In my main RemoteClient class:
main {
ClientGUI();
//display whatever
LoginGUI();
//listen for login info
if (loginIsValid) {
afterlogginginGUI();
}
}
I think you're thinking in to much of a linear fashion, where the code flows from A then to B then to C ... where in fact, Swing (and GUI's in general) are event driven...
C happens, so you do B, which triggers F so you do E ...
Start by creating a JPanel, onto this add your JTextField and JPasswordField, this will act as you basic login view. You could then add this to a JFrame or JDialog depending on your needs. You will need some way for the user to either "cancel" or "validate" their credentials.
Typically, I do this a separate view, as I never know where my poor "user details" pane might end up, but you could do this a single view (including the buttons within the "user details" pane), that will come down to your requirements.
You can use a CardLayout to switch from the "login" view to the "application" view. This has the benefit of maintaining only a single frame and prevents windows from been splashed all about the place...
I would, personally, separate the core functionality of the views to separate classes, this means you can simply create an instance when you need it and add it to whatever container you want.
I would recommend against extending from JFrame directly. This locks you into a single container (making it hard to re-use components or extend the program later) and you're not adding any new functionality to the class anyway...
Start by having a look at Creating a GUI With JFC/Swing.
You'll probably also be interested in How to Use CardLayout, How to Make Dialogs, How to Use Buttons, Check Boxes, and Radio Buttons and How to Write an Action Listeners
You'll also need to have a look at Laying Out Components Within a Container
Because you're likely waiting for a response from the server at some point, you will need to have a look at Concurrency in Swing and Worker Threads and SwingWorker wouldn't hurt
Related
I want to fill values of multiple jTextBox from a jFrame into another, using accessor methods like
String getNameVal()
{
return jTextBox1.getText();
}
How to call these methods from another jFrame?
Suggestions:
It sounds like your GUI code is geared towards making JFrames, and if so, you will want to avoid this. You are painting yourself in a corner by having your class extend JFrame, forcing you to create and display JFrames, when often more flexibility is called for. In fact, I would venture that most of the Swing GUI code that I've created and that I've seen does not extend JFrame, and in fact it is rare that you'll ever want to do this.
More commonly your GUI classes will be geared towards creating JPanels, which can then be placed into JFrames or JDialogs, or JTabbedPanes, or swapped via CardLayouts, wherever needed. This will greatly increase the flexibility of your GUI coding.
This question has direct bearing on your problem. I will guess that your main problem isn't how to give classes getter methods, and how to have other classes call the getter methods. More often then not, when faced with the issue of extracting information from one GUI view to another, the issue is one of when to extract the information. If you displayed your second window as a non-modal JFrame, and then had the calling class immediately extract the data from that second JFrame, you'd get nonsense data, because you'd be extracting data before the user would have time to interact with the 2nd window and enter data.
One possible solution to this when using non-modal windows to get information from the user is to use a WindowListener so you can be notified when the user has completed his dealing with the second window, and so now data can be safely extracted.
Often better is for the 2nd window not be non-modal, as JFrames are, but instead to be a modal window such as a modal JDialog. When the calling code displays a modal dialog, all code flow in the calling code stops until the dialog is no longer visible. In this situation, no WindowListener is needed since you will know exactly when the dialog has been dealt with -- on the code line immediately after you set it visible -- and so can extract your data from it with ease.
A nice variant on this has already been mentioned in by Andrew Thompson in comments -- use a JOptionPane. Don't poo-poo this option since JOptionPanes are powerful tools, likely much more powerful than you realize as they can hold fully formed complex JPanel views, and behave just as described above, as modal dialogs.
If you need more specific help, then please don't hesitate to comment to this answer. Also if so, then consider creating and posting a Minimal, Complete, and Verifiable Example Program where you condense your code into the smallest bit that still compiles and runs, has no outside dependencies (such as need to link to a database or images), has no extra code that's not relevant to your problem, but still demonstrates your problem.
Edit
For my mcve code examples of the above suggestions, please my answers to the following StackOverflow Questions:
Using a modal JDialog to extract information
Using a JOptonPane to extract information
I assume the textfields are present in frame1 and you want to access them in frame2. The following can be a way to achieve this:
First create getters for all JTextFields that you have in your frame1. Alternatively you can have them in a panel and call getComponents() method.
Create a private variable of JFrame type in your frame2.
Modify the constructor of frame2 to receive the frame1 object and assign it to the private variable of JFrame type.
Now you can create a close() method in frame2 which disposes the frame2 and sets frame1 to visible.
But in my opinion you should create a class which handles the data in these textfields. Initialize the class object in any button click of frame1 and check for any inconsistency in the input. I can guess there is something wrong with your design.
I've been working on a console based program that acts as an inventory of Plant objects.
I have a parent class "Plant" that has child classes of "Flower", "Weed", etc... These objects are added, removed, displayed, searched through another class containing the main method and methods for the actions above.
The methods/actions are chosen by the user via console input processed with a switch statement.
My question is this: We are adding a GUI to this console based program using a JFrame, JPanels, etc... Would the proper way to go about this be to create a new class for the interface and a new main method in that class to run the program? I would of course change the former main method to a method called by the new main.
Moving from a console program requires a lot more than just changing main methods. GUI programs are event driven. So you're not going to be running endless loops like you would in a console program.
What I mean by event driven is, for example, a button get pressed, an event is fired. You as the programmer are responsible for coding what happens when that event is fired.
So some advice.
You should go through the tutorials and learn some of the basic components and how they work. Some of the basic ones are JLabel, JTextField, JButton
You will definitely need to focus on how to write event listeners. Some of the basic ones you may want to focus on are ActionListener for button presses MouseListener for mouse events.
Should learn to layout out components correctly. Some of the basic layouts you may want to focus on are GridLayout, BorderLayout, and FlowLayout
You want to learn about the basic containers like JFrame and JPanel and learn their capabilities
The Swing tutorials are always a good place to start. Once you pick up on the basics, then move on to some more complex material.
How do buttons in software written in Java work?
For example the above screenshot: when the user clicks different buttons, different algorithms are run on user-inputted data (it's a data analysis application) and the output is displayed. Just getting started writing Java GUI's though, it all seems like magic to me -- is there one ActionListener for every pane? Does it listen for different ActionCommands of the different buttons and execute the algorithm right within the actionPerformed() method (it seems a little nonintuitive to me to execute an algorithm in a method independent of data...i.e. the button doesn't know what data it's dealing with?). So far, all the action listener tutorials I've read online have merely printed something when the button is pressed...
What's the general structure for connecting button, actionlisteners, and actual actions performed in the background?
Thanks in advance.
The usual way is to have one action listener per button. The Statistics panel has access (via one of its fields), to the data it needs to read and modify). So, the handling of the first button in this panel could look like:
private void initButtonListeners() {
this.averageDegreeButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
computeAverageDegree();
}
}
// other buttons...
}
And the computeAverageDegree() method could look like
private void computeAverageDegree() {
double result = this.statistics.computeAverageDegree();
this.averageDegreeLabel.setText(formatDoubleToString(result));
}
My personal preference is to do almost nothing in the UI, but move it all to the model/controller side (not sure what the best name is as it is seldom pure MVC).
I think that everything you do in the UI should be doable through the API as well. Benefits are easier testing, redesign of the UI is possible without messing up your logic, easy to perform the heavy work on background threads, ... .
A good read describing this is the Humble Dialog article. Not really Swing specific, but applicable to all sort of UI's.
To answer your questions:
is there one ActionListener for every pane?
No, typically you have an Action (or ActionListener) for each button. I prefer to use Action instances as they are far more reusable then the typical anonymous ActionListener (and easier to test as well)
Does it listen for different ActionCommands of the different buttons and execute the algorithm right within the actionPerformed() method
Certainly not. Doing heavy calculations in that method will block the Swing UI thread (the Event Dispatch Thread), which results in a non-responsive UI while the calculations are ongoing. Showing progress becomes also impossible. Calculations are typically done on a worker thread, launched when your Action is triggered (for example using a SwingWorker). This is explained in the Concurrency in Swing tutorial.
it seems a little nonintuitive to me to execute an algorithm in a method independent of data...i.e. the button doesn't know what data it's dealing with?
The button should not know about the data. The data is typically stored in the model. The UI is only displaying it, but does not contain it (unless it is input just provided by the user). The button should just know what to call on the model. The model does whatever it has to do and fires an event. The UI picks up that event and updates itself.
At least, that is how Swing is designed (for example JTable and its TableModel). I so no good reason to not follow that model when making your own Swing UI's
I know this is sort of a vague question, but I will try to make it as clear as possible. When my Java app launches for the first time, it does some checking to see if files and directories exist and checks for an internet connection.
The app then allows the user to move on to the dashboard, which requires loading and adding many Swing components to the Background Panel. This takes time.
I was wondering how I could make it so that during the loading process at the start, the app loads all of the Swing components Images etc. so that they appear instantly when the user executes the command to do so.
I can load all of the components like this:
JButton = new JButton("blah");
but I'm not sure that's enough to make the components appear instantly, wouldn't adding several image filled Swing components at the same time still lag the UI thread, even if it was already "loaded" as seen above?
Thanks!
on the components use
setVisible(false)
for example
public class myParentPanel extends JPanel{
public myParentPanel{
//add all the child components
//Do what ever takes along time
setVisible(false); //this then makes in invisible but still
//allows all the set up code to run
}
public void showParent(){
setVisible(true);
invalidate();
}
}
and then create a method to make them visible when required. Hence all your setting in the constructors ca be called then when you call your method say:
drawWindow()
it then only has to call setVisible(true) and invalidate the screen to call their painting methods :).
An advancement on this would be to *run your setups i.e your checking and loading the panels methods on a separate threads*so you don't have to wait for a sequential loading. So on your loading you may to use an anonymous class
SwingUtilities.invokeLater(new Runnable(){ public void run(){
//do my display set up
}});
I have developed my Java code in Netbeans, and now I want to develop the GUI for my application.
The application communicates with a server, so it's going to have a login frame for sure. After that there will be a main frame. From the main frame the user can choose where to go and as you can understand there will be a lot of frames.
I have already developed a version of the application where there are a lot of frames and using the "setVisible()", but I want something better looking. I want a stable frame and inside it, changing the panels or something similar.
How would I do this?
You might use JInternalFrames if you like them, or simply use a main panel with a CardLayout, and display the appropriate card depending on the clicked menu item, or the selected JTree node (as it's done in Windows Explorer and similar applications).
Use the Swing tutorial to get you started.
You can, at any time, make any Container object a JFrame's ContentPane. You can also add and remove Containers from any other Container. If you want a user to be able to jump to any of a dozen panels at any time, CardLayout, as suggested in another answer, is easily the best route. If, however, you intend to lead the user along a somewhat controlled path, you can start with a login JPanel. When that's done, you can create the next panel (a JPanel or something else), add it, and dispose of the first one. And so on until the user exits.
If the transition from one panel to another affects nothing else in the program besides the two panels and the parent Container (JFrame or descendant), this is probably the way to go. If a bunch of other places in the program need to know about the change, you'll want a more centralized mechanism, maybe using CardLayout.