Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Original close reason(s) were not resolved
Improve this question
I'm developing an application which displays images, and plays sounds from a database. I'm trying to decide whether or not to use a separate JFrame to add images to the database from the GUI.
I'm just wondering whether it is good practice to use multiple JFrame windows?
I'm just wondering whether it is good practice to use multiple JFrames?
Bad (bad, bad) practice.
User unfriendly: The user sees multiple icons in their task bar when expecting to see only one. Plus the side effects of the coding problems..
A nightmare to code and maintain:
A modal dialog offers the easy opportunity to focus attention on the content of that dialog - choose/fix/cancel this, then proceed. Multiple frames do not.
A dialog (or floating tool-bar) with a parent will come to front when the parent is clicked on - you'd have to implement that in frames if that was the desired behavior.
There are any number of ways of displaying many elements in one GUI, e.g.:
CardLayout (short demo.). Good for:
Showing wizard like dialogs.
Displaying list, tree etc. selections for items that have an associated component.
Flipping between no component and visible component.
JInternalFrame/JDesktopPane typically used for an MDI.
JTabbedPane for groups of components.
JSplitPane A way to display two components of which the importance between one or the other (the size) varies according to what the user is doing.
JLayeredPane far many well ..layered components.
JToolBar typically contains groups of actions or controls. Can be dragged around the GUI, or off it entirely according to user need. As mentioned above, will minimize/restore according to the parent doing so.
As items in a JList (simple example below).
As nodes in a JTree.
Nested layouts.
But if those strategies do not work for a particular use-case, try the following. Establish a single main JFrame, then have JDialog or JOptionPane instances appear for the rest of the free-floating elements, using the frame as the parent for the dialogs.
Many images
In this case where the multiple elements are images, it would be better to use either of the following instead:
A single JLabel (centered in a scroll pane) to display whichever image the user is interested in at that moment. As seen in ImageViewer.
A single row JList. As seen in this answer. The 'single row' part of that only works if they are all the same dimensions. Alternately, if you are prepared to scale the images on the fly, and they are all the same aspect ratio (e.g. 4:3 or 16:9).
The multiple JFrame approach has been something I've implemented since I began programming Swing apps. For the most part, I did it in the beginning because I didn't know any better. However, as I matured in my experience and knowledge as a developer and as began to read and absorb the opinions of so many more experienced Java devs online, I made an attempt to shift away from the multiple JFrame approach (both in current projects and future projects) only to be met with... get this... resistance from my clients! As I began implementing modal dialogs to control "child" windows and JInternalFrames for separate components, my clients began to complain! I was quite surprised, as I was doing what I thought was best-practice! But, as they say, "A happy wife is a happy life." Same goes for your clients. Of course, I am a contractor so my end-users have direct access to me, the developer, which is obviously not a common scenario.
So, I'm going to explain the benefits of the multiple JFrame approach, as well as myth-bust some of the cons that others have presented.
Ultimate flexibility in layout - By allowing separate JFrames, you give your end-user the ability to spread out and control what's on his/her screen. The concept feels "open" and non-constricting. You lose this when you go towards one big JFrame and a bunch of JInternalFrames.
Works well for very modularized applications - In my case, most of my applications have 3 - 5 big "modules" that really have nothing to do with each other whatsoever. For instance, one module might be a sales dashboard and one might be an accounting dashboard. They don't talk to each other or anything. However, the executive might want to open both and them being separate frames on the taskbar makes his life easier.
Makes it easy for end-users to reference outside material - Once, I had this situation: My app had a "data viewer," from which you could click "Add New" and it would open a data entry screen. Initially, both were JFrames. However, I wanted the data entry screen to be a JDialog whose parent was the data viewer. I made the change, and immediately I received a call from an end-user who relied heavily on the fact that he could minimize or close the viewer and keep the editor open while he referenced another part of the program (or a website, I don't remember). He's not on a multi-monitor, so he needed the entry dialog to be first and something else to be second, with the data viewer completely hidden. This was impossible with a JDialog and certainly would've been impossible with a JInternalFrame as well. I begrudgingly changed it back to being separate JFrames for his sanity, but it taught me an important lesson.
Myth: Hard to code - This is not true in my experience. I don't see why it would be any easier to create a JInternalFrame than a JFrame. In fact, in my experience, JInternalFrames offer much less flexibility. I have developed a systematic way of handling the opening & closing of JFrames in my apps that really works well. I control the frame almost completely from within the frame's code itself; the creation of the new frame, SwingWorkers that control the retrieval of data on background threads and the GUI code on EDT, restoring/bringing to front the frame if the user tries to open it twice, etc. All you need to open my JFrames is call a public static method open() and the open method, combined with a windowClosing() event handles the rest (is the frame already open? is it not open, but loading? etc.) I made this approach a template so it's not difficult to implement for each frame.
Myth/Unproven: Resource Heavy - I'd like to see some facts behind this speculative statement. Although, perhaps, you could say a JFrame needs more space than a JInternalFrame, even if you open up 100 JFrames, how many more resources would you really be consuming? If your concern is memory leaks because of resources: calling dispose() frees all resources used by the frame for garbage collection (and, again I say, a JInternalFrame should invoke exactly the same concern).
I've written a lot and I feel like I could write more. Anyways, I hope I don't get down-voted simply because it's an unpopular opinion. The question is clearly a valuable one and I hope I've provided a valuable answer, even if it isn't the common opinion.
A great example of multiple frames/single document per frame (SDI) vs single frame/multiple documents per frame (MDI) is Microsoft Excel. Some of MDI benefits:
it is possible to have a few windows in non rectangular shape - so they don't hide desktop or other window from another process (e.g. web browser)
it is possible to open a window from another process over one Excel window while writing in second Excel window - with MDI, trying to write in one of internal windows will give focus to the entire Excel window, hence hiding window from another process
it is possible to have different documents on different screens, which is especially useful when screens do not have the same resolution
SDI (Single-Document Interface, i.e., every window can only have a single document):
MDI (Multiple-Document Interface, i.e., every window can have multiple documents):
I'd like to counter the "not user friendly" argument with an example that I have just been involved with.
In our application we have a main window where the users run various 'programs' as separate tabs. As much as possible we have tried to keep our application to this single window.
One of the 'programs' they run presents a list of reports that have been generated by the system, and the user can click on an icon on each line to pop open a report viewer dialog. This viewer is showing the equivalent of the portrait/landscape A4 page(s) of the report, so the users like this window to be quite big, almost filling their screens.
A few months ago we started getting requests from our customers to make these report viewer windows modeless, so that they could have multiple reports open at the same time.
For some time I resisted this request as I did not think this was a good solution. However, my mind was changed when I found out how the users were getting around this 'deficiency' of our system.
They were opening a viewer, using the 'Save As' facility to save the report as a PDF to a specific directory, using Acrobat Reader to open the PDF file, and then they would do the same with the next report. They would have multiple Acrobat Readers running with the various report outputs that they wanted to look at.
So I relented and made the viewer modeless. This means that each viewer has a task-bar icon.
When the latest version was released to them last week, the overwhelming response from them is that they LOVE it. It's been one of our most popular recent enhancements to the system.
So you go ahead and tell your users that what they want is bad, but ultimately it won't do you any favours.
SOME NOTES:
It seems to be best practice to use JDialog's for these modeless windows
Use the constructors that use the new ModalityType rather than the boolean modal argument. This is what gives these dialogs the task-bar icon.
For modeless dialogs, pass a null parent to the constructor, but locate them relative to their 'parent' window.
Version 6 of Java on Windows has a bug which means that your main window can become 'always on top' without you telling it. Upgrade to version 7 to fix this
Make an jInternalFrame into main frame and make it invisible. Then you can use it for further events.
jInternalFrame.setSize(300,150);
jInternalFrame.setVisible(true);
It's been a while since the last time i touch swing but in general is a bad practice to do this. Some of the main disadvantages that comes to mind:
It's more expensive: you will have to allocate way more resources to draw a JFrame that other kind of window container, such as Dialog or JInternalFrame.
Not user friendly: It is not easy to navigate into a bunch of JFrame stuck together, it will look like your application is a set of applications inconsistent and poorly design.
It's easy to use JInternalFrame This is kind of retorical, now it's way easier and other people smarter ( or with more spare time) than us have already think through the Desktop and JInternalFrame pattern, so I would recommend to use it.
Bad practice definitely. One reason is that it is not very 'user-friendly' for the fact that every JFrame shows a new taskbar icon. Controlling multiple JFrames will have you ripping your hair out.
Personally, I would use ONE JFrame for your kind of application. Methods of displaying multiple things is up to you, there are many. Canvases, JInternalFrame, CardLayout, even JPanels possibly.
Multiple JFrame objects = Pain, trouble, and problems.
I think using multiple Jframes is not a good idea.
Instead we can use JPanels more than one or more JPanel in the same JFrame.
Also we can switch between this JPanels. So it gives us freedom to display more than on thing in the JFrame.
For each JPanel we can design different things and all this JPanel can be displayed on the single JFrameone at a time.
To switch between this JPanels use JMenuBar with JMenuItems for each JPanelor 'JButtonfor eachJPanel`.
More than one JFrame is not a good practice, but there is nothing wrong if we want more than one JFrame.
But its better to change one JFrame for our different needs rather than having multiple JFrames.
If the frames are going to be the same size, why not create the frame and pass the frame then as a reference to it instead.
When you have passed the frame you can then decide how to populate it. It would be like having a method for calculating the average of a set of figures. Would you create the method over and over again?
It is not a good practice but even though you wish to use it you can use the singleton pattern as its good. I have used the singleton patterns in most of my project its good.
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 wanted to ask for a tip. How would you struct your application if you had a JFrame with many JPanels which have like ten JTextFields Labels, and an Edit Button.
Would you put all the code in the JFrame or would you extend from JPanel and include all of them in the JFrame?
What about the buttons? I want to use the MVC pattern, how would you handle the actionlisteners? Are each of them an own controller or would you use only one controller for all of them?
I think it's first of all a question of style and personal preference. It also depends on what your application should do and how.
If your JPanels all are very similar in a certain way it would probably make sense to extend from JPanel. For example if every panel had 10 Buttons where Button 1 does always action xyz() for its corresponding model-object (especially when this object is the same for all buttons of 1 JPanel) and Button 2 does abc() ...
If the JPanels are not strongly correlated in such a way I would place my code rather in the JFrame or in a third Object which sets the whole GUI up from outside.
It's similar with the actionlisteners. If you have very few actions I would probably go for just one controller-object for ease of use (not many files). If you have a lot of different actions I would group similar actions into one controller-object per group of actions.
That said it probably is best to start with a simple approach (YAGNI) where you do everything from the JFrame / third object and have one actionlistener and then refactor when you feel that splitting things up gives you a cleaner or more flexible design.
We are going to use Swing for our next project which will be a lightweight desktop app.
I've been reading the Swing tutorials on Oracle's website and have started to get the hang of it.
I was told that instead of switching JFrame I need to work within one JFrame and switch JPanels.
My questions to you would be the following.
Can I create the JPanel designs (or their templates) in design mode (WYSIWYG editor) and call jframe.setContentPane(nameOfJPanel) or do I do them programatically in code?
Secondly, how do I structure my code... If I dynamically add new JPanels and bind their events to an event handler.. all my logic and code will be in one HUGE class with tens of methods. I just don't know how to proceed and nowhere can I find an example with multiple (more than 6 let's say) panels on the internet.
To WYSIWYG or not WYSIWYG
This is a debatable question at the best of times.
I encourage all my junior developers to start out hand coding UIs as it teaches them important basics about how to use layout managers and how to handle compound layouts.
This tends to take longer as you need to verify the layout with each change.
I personally use the form editor in Netbeans for most of my general work, but will hand tweak UI's
Structure
Think about boundaries of responsibility, reuse and reduce strategies.
What you don't want is some huge master class that does EVERYTHING. It will be difficult to maintain and update (I live with this horror every day).
Instead, identify the distinct areas of responsibility and either use getters and setters or models to move the data around the application. The more you can decouple your code, the easier it will be to update and modify.
Identify like work and model it as interfaces and abstract classes where you can. Basically where ever you start thinking about coping code is probably a good indication that your design is off and you should consider implementing abstract classes to cover the overlap.
Take advantage of the Action API for replicating commonly used concepts (copy and paste is an example of this. You would want menu items, possible toolbar items and maybe even popup items, these can all be handled by the same Action class).
Separate the data from view. As I said before, take advantage of models. The data shouldn't care how it is collected or modified, only that it can be. Equally, the view shouldn't care about how the data is managed, only that it is.
If possible, define interfaces between the separate areas of your application. This way you can further decouple of the application and no one part becomes reliant on any one implementation (hello my world :P)
Don't be tempted to simply dig through a component hierarchy to gain access to that field, it will produce a nightmare if you need to change the code!!
The JFrame will be the main window of your app and the panels will be the brick composing it.
You should create each panel in its own class and you can arrange them by functionality in packages. You'll have panels for holding content of logical part of your application and panels that contains real stuff.
A logical panel could be the main view and the menu bar. An application panel would be a form, a menu, a canvas...
You'll have to put application panels inside logical panel and to change the content of the logical in response to users actions.
You should study how layouts work in order to compose the view inside the JFrame and to layout components inside panels.
For example the BorderLayout is a classic when defining the main area of an application:
- menu and toolbar on top
- browser on the left
- status bar at the bottom
- main panel on the center
You can use WYSIWYG editor, but avoid doing all design inside the same class. Else you'll have an horrible HUGE class. Create your panels in separate classes and compose them in your main view.
You can use empty panels as placeholder to help you create the structure of your application.
You'll have to bind your domain data to the view in order to not mix the two layer.
Bind means that you will write a way to go from a java bean to a form and the reverse.
Basic binding is handwritten, but some tools exists to do that.
If it is a small application, it is maybe better for you to handwrite everything.
Building a Swing application can be very tricky (you'll have to know about the event dispatch thread, layout management, event management, widgets (label are trivial, but JTable can be very complicated to handle);
I'll recommend to find a book about the topic, and to find some open source swing application in order to study how it structured, before you start your project.
This is how I organize my code:
class Panel1 extends JPanel{
//code for panel1 and its Components
}
class Panel2 extends JPanel{
//code for panel2 and its components
}
// and it follows.
class ApplicationFrame extends JFrame{
/// LOGIC to switch between panels
}
class Main{
//contains main() function
}
Any HAND-CRAFTED GUI code, is better than a COMPUTER GENERATED WYSIWYG -APP Code.
Set up:
I have a mainPanel with a tabbedPane on it, i have a separate JPanel 'extra', extra creates an objects and i wish to pass that object back through to the mainPanel where i can actually use it/add it to the data structure.
Frame > Panel > TabbedPane > Panel (Separate Class, instantiated as new object)
I tried to add a listener in mainPanel that checks if a boolean in PanelExtra changes and then runs a method etc, but it didn't work.
I would make a method in mainPanel to accept the object but i don't know how to refer back to it. (getRootPane() didn't return anything)
Also im not sure if im using correct terminology, while i was taught Java in a command line Unix environment, Swing is very new to me.
I tried Listeners, Observers and am currently considering an object created at root and passed DOWN through all objects (As java passes by reference, i could pass information back as far as i want) If that isn't an entirely stupid idea, let me know and we can all go about our lives. If there is a better way to do it that'd be great.
(File overview)
[programApp]>[programView>tabbedPane]>[panel]
Panel is created using new, and exists in a separate class.
I want to pass data back from Panel to programView (projectNameView as it is in netbeans)
I will attempt to add as much information as i can.
You can use the MVC-pattern for that.
Actually there are couple of variants depending on your preferences or exact task.
For very simple case you can just use class with static fields to pass objects.
Another way is to define your own listeners like:
private myPanel extends JPanel implements Notification {
...
and where you create that panel:
myPanel.addNotificationReciever(mainPanel);
Later you just call fireNotification or whatever and implement similar listener for your mainPanel.
SirVaulterScoff gave the best answer in my opinion, but I thought I'd add some more (can't add comments yet, so I'm creating a new answer).
You should also read the Observer-Observable pattern (Wikipedia article), which is used along with the MVC pattern. It will be useful when linking your MVC classes together, to make sure everything is as loosely coupled as possible.
As a side comment: MVC is really a pattern you should focus on if you are to create applications with a user interface. It will save you many headaches, and will make your application easier to maintain and extend.