Java/Swing GUI best practices (from a code standpoint) [closed] - java

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 11 years ago.
Improve this question
As a contrast to this wiki, I am looking for the proper way to implement Swing GUI controls from a coding standpoint.
I have been on a quest to learn Java and its GUI tools but I find internet tutorial after internet tutorial that throws everything in main and I know this isn't right.
I've also tried RAD systems like Netbeans and other "visual" editors but by the time I get to coding I've got a heap of code that I don't know half of what it does, so I'm intent on learning to hand code swing, and I know the basic controls and layout, but want to do it the right way.
Is there a model or standard I'm missing?
example questions...
do I extend JFrame and create my own frame object? (I would assume yes)
do I encapsulate the main menu inside that frame object? or do I create its own? etc...
How to I separate "View" logic from "Application" logic?
Basically, I'm looking for what the industry standard is, on how to organize GUI code.

Since there seems to be some argument about what constitutes "best practices", I'll give you what I have found works best for me, and my reasoning:
1.
Each window should extend either JFrame or JDialog (depending on the type of window). This makes it easy to control the properties of the window without specifying a specific object every time. This is more of the general case, though, as I have been known to do it both ways.
2.
The main() method should be in a separate class. This increases the likelihood of being able to use your window classes elsewhere, as they are not tied to specific implementations. Technically it doesn't make a difference, but application startup code just doesn't belong in a window.
3.
Listeners should be in anonymous inner classes. Your top-level class should not implement any listeners. This prevents hacks like calling the listener methods from anywhere except the object to which they are attached.
Here is a simple application with a single frame to demonstrate these practices:
public class Main {
public static void main(String[] args) {
final String text = args[0];
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
final MyWindow wnd = new MyWindow(text);
wnd.setVisible(true);
}
});
}
}
public class MyWindow extends JFrame {
public MyWindow(String text) {
super("My Window");
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
MyWindow.this.setVisible(false);
MyWindow.this.dispose();
}
});
final JButton btn = new JButton(text);
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(MyWindow.this, "Button Pressed", "Hey", JOptionPane.INFORMATION_MESSAGE);
}
});
setLayout(new FlowLayout());
add(btn);
pack();
}
}

I agree with all of Jonathan's points.
Each window should extend either JFrame or JDialog...
The main() method should be in a separate class...
Listeners should be in anonymous inner classes...
I would also like to add the following:
Use GridBagLayout (GBL) judiciously. GBL is a powerful Layout Manager, difficult to learn, but quite powerful.
Consider hand coding all your UI. I'm personally not a fan of the code that is produced by visual editors. But, with that said I have not used a visual editor in several years (2000ish). They might be better at this point.
Use JPanels judiciously. Look at your ui and determine which components should behave the same as the screen size changes and then group those components together on a JPanel. Consider using JPanels inside of JPanels to get your correct resizing behavior.
I normally take a slightly different approach on having my components handle events then Jonathan does, but I believe his approach is a bit cleaner then mine.
Also, really study the use of MVC and Layered Architecture. It is truly best not to be mixing UI and Business Logic together.

Related

Why is my JAVA GUI opening multiple windows?

I'm new to GUI's so sorry if the error is really blatant.
I'm trying to create a simple window with a couple of buttons, but every time I run the code, it opens four windows instead of just one. Any help would be appreciated.
public class CISUC extends JFrame implements Serializable {
//interface
JFrame mainFrame;
JPanel mainPanel;
JButton createProject, manageProject,listActive, listUnfinished,listaFinished;
public CISUC(){
//interface
mainFrame = new JFrame();
mainFrame.setResizable(false);
mainPanel = new JPanel();
mainPanel.setLayout(new GridLayout(2,3));
createProject= new JButton("Create Project");
mainPanel.add(createProject);
manageProject = new JButton("Manage Project");
mainPanel.add(manageProject);
listActive = new JButton("List Active Projects");
mainPanel.add(listActive);
listUnfinished = new JButton("List Unfinished Projects");
mainPanel.add(listUnfinished);
listFinished = new JButton("Listar Finished");
mainPanel.add(listFinished);
mainFrame.setSize(800, 500);
mainFrame.add(mainPanel);
mainFrame.setVisible(true);
}
public static void main(String[] args) {
CISUC cisuc = new CISUC();
}
}
As ohers already said to you, there is nothing wrong with the number of Frames opened, i just tried the code and it opens a single JFrame.
In my opinion there are a few mistakes in your code: you don't need to extend JFrame and implement serializable for this purpose... this way you are making your application heavier because of unused inherithed (unused) fields and methods from parent class. Moreover (as others already told you), there is no close operation linked to your JFrame, so when you press the X button your application just keep running until you shut down your computer.
To avoid this jut add the following statement:
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
I suggest you to put main method, main Object, and JPanel in separate
classes, making your application easier to read, debug, and maintain. If you are planning to have many funcionalities it can be a good idea to have a custom class extending JFrame, where you can assemble different custom GUI objects, each one extending a Swing/AWT component.. and finally call them in you main object or directly in main class! There is no limit to this, but use inheritance wisely: many classes mean much more boilerplate code... there is always a tradeoff!
Another great idea should be to put graphics initialization (size,
colours, etc...) in a separate method outside from constructor. Just
create something like `private void initializeGraphics(){...}
Other to this, you can do the same when mapping actionListeners to
buttons, putting them in separate named classes or at least in a
separate method like private void addListeners(){...}, and just
call this at the end of your constructor code.
I'm telling you this because when using Swing it's very easy to have something like 5000 lines of unreadable and unmaintainable code if you start adding everyting in the same place!
Good luck with your application :)
PS: take a look to MigLayout... i think you are going to like it, even it could seem a bit complicated at the beginning.

NetBeans inserts main() method in every added frame

When adding new class extending JFrame (or java.awt.Frame) the class is added with main() method inside like this:
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new NewFrame5().setVisible(true);
}
});
}
Every JFrame class has its own main method and I guess all classes starts simultaneously.
How do I add frames without main methods?
Firstly, see The Use of Multiple JFrames, Good/Bad Practice?. Generally, recommended not to do it. See accepted answer for other possibilities (for example a JDialog)
As for your main concern, there's no way around netbeans creating the main method for top level containers like JFrame and JDialog. The logic seems right in the case of JFrame, as an application should only have one JFrame as the main top-level container for the application, but I'm not sure the logic behind the JDialog having a main method (as the dialog is usually run in the same JVM as the main JFrame). The only thing I can think is that the JDialog is created with a main for development purpopsed, if you want to test the dialog in stand-alone mode. But ultimately, you should delete the main method of the JDialog should you choose to use one.
Going back to the first point about multiple JFrames, other options I might recommend
Use a JDialog. Yes you will have to delete the main method, when going into production, as the dialog will be instantiated within the context of the main JVM and generally shouldn't run its own process.
Another option, depending on your requirements is to use a Cardlayout which will let you switch between views/panels (You can create JPanel forms in netbeans). See How to Use CardLayout in Netbeans GUI Builder for a working guide. And the official How to use CardLayout tutorial
An aside, if you are a beginner, I strongly suggest you put aside the builder tool and learn to hand code first. There may be many tutorials teaching you how to use the builder tool, but they may miss out on important concept in the swing architecture and swing in general. IMO this will greatly affect your understanding of how and why things work with the builder, causing a lot a headache when trying to debug. Keep Creating a GUI With JFC/Swing, the official tutorial handy and go through it.

Extends JFrame vs. creating it inside the program

When making an application using Swing, I've seen people do one of the two things to create a JFrame. Which is a better approach and why?
I'm a beginner at Java and programming. My only source of learning is books, YouTube and Stack Overflow.
import {imports};
public class GuiApp1 {
public static void main(String[] args) {
new GuiApp1();
}
public GuiApp1() {
JFrame guiFrame = new JFrame();
guiFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
guiFrame.setTitle("Example GUI");
guiFrame.setSize(300,250);
................
}
AND
import {imports};
public class GuiApp1 extends JFrame {
public Execute() {
getContentPane().setBackground(Color.WHITE);
getContentPane().setLayout(null);
setSize(800, 600);
.............
}
public static void main(String[] args) {
Execute frame1 = new Execute();
frame1.setVisible(true);
}
}
Thoughts:
Avoid extending JFrame as it ties your GUI to being, well a JFrame. If instead you concentrate on creating JPanels instead, then you have the freedom to use these JPanels anywhere needed -- in a JFrame, or JDialog, or JApplet, or inside of another JPanel, or swapped with other JPanels via a CardLayout.
Avoid inheritance in general, especially of complex classes. This will prevent pernicious errors, such as inadvertent method overrides (try creating a JFrame or JPanel that has a getX() and getY() method to see what I mean!).
Avoid inheritance of complex classes if you are using an IDE: If you override a complex class, when you call methods on objects of these classes, you will have many, too many, choices of methods offered to you.
Encapsulation is good, is and allows for creation of safer code. Expose only that which needs to be exposed, and control that exposure as much as possible.
Prefer composition over inheritance.
The 2nd example uses inheritance, but for no good reason, since it does not change the functionality of JFrame.
As an aside, if those are examples of code you are seeing, find a new source1 supplementary. Even in the few code lines shown, each does highly questionable things. E.G.
Neither GUI is created on the Event Dispatch Thread.
getContentPane().setBackground(Color.WHITE);
getContentPane().setLayout(null);
setSize(800, 600);
The first part of the 1st line (getContentPane()) has not been necessary since Java 1.5
The second line uses a null layout, which will break in more ways I can count or describe.
The third line should best be replaced with pack();
JFrame guiFrame = new JFrame();
guiFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
guiFrame.setTitle("Example GUI");
guiFrame.setSize(300,250);
The first and 3rd lines could be contracted to: JFrame guiFrame = new JFrame("Example GUI");
The 2nd line is better set to guiFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
The 3rd line again sets a size to the frame.
Supplement
Having mentioned you do search SO, here is a tip. Check out the posts of the top 15 providers of answers in the Swing top users. Whatever advice/code you glean from these people, would commit few if any of the mistakes in those code samples. Some don't often (or ever) provide self contained examples like a few of us commonly do (and don't look to those examples necessarily for OO design as opposed to just technique), but whatever code they provide, or advice they give, should be highly considered.
Personally, the first approach (creating an instance of JFrame) is preferred, I prefer this because...
It doesn't lock your application into a dedicated container...you see a lot of people wanting to add applets to frames and frames to applets, if they had simple put the majority of there GUI in a JPanel to start with, they wouldn't have these issues.
It also means that the UI you create is much more flexible. For example, you can re-use it, either in the current application or future applications, you don't lock yourself in.
The main gripe I have with extending JFrame is, you're not actually adding any new features or functionality to it, which could be effectively re-used beyond using setVisible
The other issue I have with extending JFrame is people then promptly override paint, which is really, really bad. There are so many issues with doing this it's simply painful to have to repeatedly list them...
So...for more 2 cents worth. Create an instance of JFrame and add your content to it. If required, create a static method call showMyAwesomeGUI which does it for you...
The first approach is better.
Typically you are not adding any new functionality to the frame so creating a direct instance of the class makes sense.
Go for the first approach.
Because with that you can have more frames to be created. Because the application can have more than one window. As in the second case you can't create more frames.
It does not matter.
There are reasons why you might do one or the other, but absent any of those reasons it makes no difference whatsoever.
Now, if you were writing something that might operate from the command line or might be a GUI program, obviously you could want a 'main' class that was not a GUI class.
If you worked in a programming shop where one or the other was the standard, by all means follow the standard. There is no right answer to this one, and in fact very little to choose between them.

Creating a Button in Java [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking us to recommend or find a tool, library or favorite off-site resource are off-topic for Stack Overflow as they tend to attract opinionated answers and spam. Instead, describe the problem and what has been done so far to solve it.
Closed 8 years ago.
Improve this question
I am fairly new to programming as I am only in a Computer Science class in high school. I have thought of the idea of creating a chess program that basically simulates a game of chess. To do this I figured I would have the users click on the spot that they would want to move to.
I have looked all over the internet, including java's API's, and I have found some very useful information. After all of this however, I am still very confused about all of the different methods and classes as well as interfaces to use to create and use Buttons in Java. Although this isn't a question about code(Sorry), I was wondering if anybody knew of any tutorials that would be suitable for my situation. All I am looking for is something that can show me how to create and use a simple, one function button. Preferably, it would be nice if it describes all of the methods so that I actually understand what I am doing.
Again, sorry this isnt a question about code. I couldn't think of a better place to ask this question, than Stack Overflow so please do not down-vote this "question".
Thanks
Here is a totally self contained example (with some code comments to help you understand what is going on):
//Here I am using Swing and AWT (a rather standard way to manage UI elements in Java though technically not the only way)
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
//Here is a base class that extends JFrame, JFrames are containers for Swing UI widgets that are represented as windows when executed
public class ButtonExample extends JFrame {
private static final long serialVersionUID = 1L;
public static void main(String[] args) {
//Creatign the frame
ButtonExample frame = new ButtonExample();
//Creating the button with the label "Click me!"
JButton button = new JButton("Click me!");
//Adding an action listener so we can assign some logic to be executed when this button is clicked on (this is using an anonymous inner class in future versions of Java this will be replaced by the MUCH cleaner Lamba approach, keep an eye out for that)
button.addActionListener(new ActionListener() {
//Keep a variable to store how many times the button is clicked. This shows that the action listener stays running in between clicks)
private int count = 0;
//While technically optional thew #Override annotation helps if you update interfaces, get into the habit of doing this to make future work easier, things like Eclipse will insert it for you
#Override
public void actionPerformed(ActionEvent e) {
//Bump up the count variable
this.count++;
//And print it to System.out
System.out.println("Pressed "+this.count + " times");
}
});
//Add the button (with it's listener) to the frame
frame.add(button);
//Tell Swing to resize the frame to fit the requested size of all of it's contained widgets
frame.pack();
//Tell Swing to show the frame
frame.setVisible(true);
}
}
Try:
JButton button = new JButton("Click me");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//Do what you like here after button is clicked, for example:
System.out.println("Button clicked");
}
});
someJPanel.add(button);
To make such application - you will need lot's of knowledge. Also it should look nice, so lot's of work with graphics in Java..
Try to read this documentation: Here You Are
There, you can download, launch the example, so you can see, try every button..

Lag before JFrame event handlers are added?

I'm working on a simple Java swing project. This is the code of the main class (name changed):
public class MainProg
{
private static MainProg program;
//mainWin is a JFrame
private MainWindow mainWin;
//Event handler class which extends MouseAdapter
private TrayManager trayMgr;
public static void main(String[] args)
{
program = new MainProg();
}
public MainProg()
{
mainWin = new MainWindow();
trayMgr = new TrayManager();
mainWin.startBtn.addMouseListener(trayMgr);
mainWin.setVisible(true);
}
}
As is clear, when the program starts, in main() it creates a new instance of the MainProg class, which then calls the constructor. In the constructor, it creates a new instance of the JFrame mainWin. It then attaches an event handler to a button on mainWin.
In the event handler class trayMgr, the only method is mouseClicked() which does nothing
except a System.out.println('Clicked');
The issue is, when I run this program in Netbeans, the JFrame is shown right away, but I seem to have to click the button 2-3 times before the message is printed in the console.
Is this just something specific to Netbeans, or do I have to change something to make the event handler be set before the window is made visible?
Your threading issue is not likely one that is causing your current problem, but there's the theoretic potential for problems, and I've seen some real problems associated with some of the more touchy look and feels. Quite simply you should queue your code that starts your GUI onto the Swing event thread. You do this by doing:
public void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(
public void run() {
program = new MainProg();
}
));
}
Someone else recommended using invokeAndWait(...) instead of invokeLater(...) but this can be risky especially if you inadvertently make this call from within the Swing event thread itself. For your situation you're better off using invokeLater(...).
But again, I think the main problem with the code you have shown was inappropriate use of MouseListener where an ActionListener should have been used. Learning to code any GUI library can be quite tricky, and for that reason, you can't assume anything. Check out the tutorials and learn from the experts. Also if you are considering coding Swing for the long haul, consider ditching the NetBean's code-generation utilities and learn first to code Swing by hand. You won't regret doing this.
Since you asked, the code I posted here is a Java SSCCE on a different topic. invokeLater is a way of running computations on the EDT. (There is also invokeAndWait, which would work fine here, but under some other conditions can cause a deadlock.)
In fact this example is perhaps a bit over-conservative. Some references say you can run Swing from the main thread the call to show() or setVisible(). However I have a program that misbehaves under Java 7 when I try that.

Categories