The first strategy when working with Swing is to keep things simple. There are a bunch of different JComponents in Swing, and many in AWT. Pick only those needed, and understand their basic purposes. Yes- they have many methods inherited from parent classes. However, think back to abstraction and encapsulation. It isn't important to understand the inner workings of each JComponent, only how to work with them as needed. In other words, don't get bogged down with the thousand methods the JFrame class has. Only worry about the five or six you actually need to work with.
The second strategy is to use inheritance where appropriate. Extending certain GUI Components allows for cleaner organization of code. Let's take a look at a less OO use of GUI Components to create a simple JFrame:
public class MyDemoGUI{
private JFrame frame;
private JPanel panel;
private JButton button;
public MyDemoGUI(){
frame = new JFrame();
frame.setSize(400,400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new JPanel();
button = new JButton("Click me");
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
JOptionPane.showMessageDialog(null, "You clicked the JButton");
}
});
panel.add(button);
frame.add(panel);
frame.setVisible(true);
}
}
On a first glance, this isn't too ugly. However, it presents some problems. First, we don't have direct access to the JFrame. So what happens when we want to hide this JFrame based on the results of another JFrame? Yes, getter and setter methods can be used. However, inheritance is useful here to provide direct access to the JFrame without use of an Object to act as a middle man. Let's look at the refactored code:
public class MyDemoGUI extends JFrame{
private JPanel panel;
private JButton button;
public MyDemoGUI(){
this.setSize(400,400);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
panel = new JPanel();
button = new JButton("Click me");
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
JOptionPane.showMessageDialog(null, "You clicked the JButton");
}
});
panel.add(button);
this.add(panel);
this.setVisible(true);
}
}
The other case I want to make for inheritance is for clean organization of the code base. A common mistake made when developing GUIs is to customize multiple Components significantly in one class. This leaves a single class of significant length that is difficult to maintain. Creating methods to create these Components and initialize them is a common way to organize them. A rule of thumb is that if a Component warrants its own method to initialize it, then it warrants its own class.
The benefit of this is twofold. First, it makes it easier to find the code for the specific Component when modifying it. The second is that it reduces the amount of code used in the other GUI classes. Consider the following class:
public class MyFrame extends JFrame{
private JPanel mainPanel, northPanel, southPanel, eastPanel, westPanel;
private JButton clickMe, displayDialog;
private JLabel northRegion, southRegion, eastRegion, westRegion;
public MyFrame(){
this.setSize(400,400);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
northPanel = new JPanel();
clickMe = new JButton("Click Me");
clickMe.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
JOptionPane.showMessageDialog(null, "I've been clicked");
}
});
northRegion = new JLabel("North Region");
northPanel.add(clickMe);
northPanel.add(northRegion);
mainPanel.add(northPanel, BorderLayout.NORTH);
southPanel = new JPanel();
southRegion = new JLabel("South Region");
southPanel.add(southRegion);
mainPanel.add(southRegion, BorderLayout.SOUTH);
eastPanel = new JPanel();
displayDialog = new JButton("Display Dialog");
displayDialog.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
JOptionPane.showMessageDialog(null, "Displaying the dialog");
}
});
eastRegion = new JLabel("East region");
eastPanel.add(displayDialog);
eastPanel.add(eastRegion);
mainPanel.add(eastRegion, BorderLayout.EAST);
westPanel = new JPanel();
westRegion = new JLabel("West Region");
westPanel.add(westRegion);
mainPanel.add(westRegion, BorderLayout.WEST);
this.add(mainPanel);
this.setVisible(true);
}
}
At a glance, this code doesn't look too troublesome to work with. As this JFrame continues to be developed, it gets more difficult to cleanly add on to each JPanel for the BorderLayout regions. While the JPanels can be compartmentalized better in the class with helper methods to initialize them, the helper methods themselves can grow quite bulky. For this reason, it is better to create subclasses for the JPanels if they will contain more than a small handful of JComponents. While a few JComponents on each JPanel isn't a pain to maintain, having a bunch of JComponents, listener code, and possibly custom painting creates a code-base more warranted for its own class. Plus, it makes each JPanel more modular and reusable.
Conclusion- This tutorial is far from comprehensive, as the Java GUI is far too bulky for any single tutorial. It also does not thoroughly cover the GUI Components used, as many other tutorials do. However, this tutorial should be used when learning GUI Programming to help when organizing one's code so as not to get overwhelmed by the Swing API.








MultiQuote






|