I'm wondering about the standard practice with inner classes (in Java but I suppose it applies to all OO languages).
So I have a JFrame subclass ControllerWindow that contains a JPanel subclass MapPanel which I draw onto (so it needs to overwrite paintComponent method) and which needs to implement a mouse listener. My current solution which works is to have MapPanel in a seperate class implementing MouseListener but when I showed this to the guy who runs my course the other day he seemed to think (we have a bit of a language barrier) this should be in an inner class in ControllerWindow or at least the MouseListener should be an inner class.
So my question is what would be the standard solution here, to put a MouseListener in the inner class, the JPanel in a different inner class or still in its seperate class? The JPanel implementing MouseListener in one inner class? And why?
The most important thing to me is that it works but I'd like to know about and understand the standard practices behind these things if possible.
EDIT: Very simplified version of current code below.
class ControllerWindow extends JFrame{
...
MapPanel drawPanel = new MapPanel();
...
}
and a separate class:
class MapPanel extends JPanel implements MouseListener{
...
public void paintComponent(Graphics g){
...//fillRects etc.
}
//MouseListener methods
public void mouseReleased(MouseEvent e){
requestFocus();
...
repaint()
...
}
public void mousePressed(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
public void mouseClicked(MouseEvent e){}
}
Also could this be a situation where it would be acceptable to put both classes in the same file? I don't envisage using MapPanel for anything other than ControllerWindow.
It is common to use anonymous inner classes as event listeners because the code is usually quite simple (so a separate class may be overkill) and keeping the handler code "close" to the code that registers the listener can improve readability for people trying to understand your code, since all code related to the event is in one place.
EDIT: This is particularly true for classes that implement only one listener method. Perhaps less true for multi-method interfaces like MouseListener, since a class that implements the full interface will be more verbose.
I think it's somewhat arbitrary how you go about it (as Tom Hawtin commented, GUI standards=mud), since you're trading off complexity in the number of classes versus complexity in a single class. If you want to produce code simply for a demonstration, a single file might be easiest. If you want code that you're going to put into production and modify/maintain over time, abstracting out into different classes is almost certainly the way you want to go.
For example, if you embed MapPanel as an inner class in ControllerWindow, and then later want to replace it with a different type of MapPanel, you've got a massive update to ControllerWindow rather than just swapping out MapPanel for a different component type.
With the MouseListener, I'd be inclined to include it in MapPanel if it's handling events specifically for that component (that is, if only the MapPanel "knows" what a click means, it should be the one to process that click). I definitely wouldn't put it in ControllerWindow, since then you're "leaking" implementation detail from MapPanel. (The only case I can think of: in addition to your MapPanel, you have multiple panels type that all need to respond to clicks in the same way, so rather than implementing in each panel you could have the ControllerWindow do it. But even then, I'm not sure the code should be in ControllerWindow).
Whether MapPanel's mouse listener is an inner class implementation of MouseListener, or whether MapPanel implements it (as in your code above) probably comes down to a question of which style you prefer.
inner class would be better if it has a simpler syntax.
button1.click( function(event){ do something x... } );
button2.click( function(event){ do something y... } );
radio2.check ( function(event){ do something z... } );
java 7 may give us something like that and change the whole situation. as it is now, using a lot of annonymous inner classes can mess up the code and make it impossible to read. you should choose whichever style that makes your code beautiful and legible.
Because of multiple event handling requirement anonymous inner classes are required. Anonymous class can be written anywhere like in a class, in a method, in the argument. Therefore to abstain from creating many classes for each listener anonymous is preferred.
I found this article useful:
http://www.retrologic.com/innerclasses.doc3.html
In general, when you need to use a method pointer; extend adapter classes as inner classes to simplify your code.
Related
I'm fairly new to programming and definitely new to Java. I'm teaching myself before I begin courses this fall in computer science and I have a curiosity about syntax that I have seen from two different authors.
In one book, a JFrame is usually established by making the class an extension of JFrame
public class MyClass extends JFrame {
etc
However, another author, and also questions on this site usually establish a frame inside of the class as such:
public class MyClass {
JFrame frame = new JFrame();
Firstly, what are the advantages of one over the other?
It seems to me, and I'm hardly an expert, that making a class an extension of JFrame would make it easier to set parameters of the frame and also to add components to it.
IE in the extension format, you simply say
add(component);
However, in the other format, on must type:
frame.getContentPane().add(component);
which seems more tedious.
Can someone please explain succinctly the reason behind this or if it is simply a matter of preference. I have looked into this and have been unable to get a straight forward answer.
There are philosophical and practical reasons many (including I) prefer the latter:
Prefer composition over inheritance in general.
Only extend a class if you plan to alter its innate behavior (i.e., override one or more of its methods).
By not extending JFrame, it is easier to create classes that maximize cohesion and minimize coupling, and to write clean MVC-based code. A more important example of this concept is to avoid having your GUI code (your view code) implement any listener interfaces (your control code). It's OK for baby programs, but not for grown-up code that has the potential of getting complex.
By not extending a large and complex class such as JFrame, you reduce the risk of difficult to debug hidden override malbehaviors. Try extending JFrame or JPanel and giving the class a getX() and getY() method to see what I mean!
If you're using an IDE that gives suggestions of methods available to objects of your class, you greatly reduce the number (and complexity) of possible suggested methods if you don't override a huge complex class such as JFrame.
By gearing your Swing GUI's to create JPanels rather than override JFrame, you greatly increase the flexibility of how that GUI can be used. Now it can be placed in a JDialog, JOptionPane, a JApplet, inside of another JPanel as part of a more complex GUI or as part of a CardLayout view swap.... and I can go on and on.
On the same token as above, many of my GUI's do just that, create JPanels, that I can test in isolation by putting them in JFrames in small test programs before adding them to the greater whole of the application.
Traditionally you're not creating a special type of frame, so you shouldn't extend JFrame.
You're creating a JFrame and putting content in it, so the latter method is preferrable.
I.e. it's from an object oriented point of view it's cleaner to USE a JFrame, instead of extending one.
When dedicating a class to a particular Swing component, is it better to extend that particular component, or construct it internally and provide a reference?
public class Foo extends JComponent{
}
OR
public class Foo{
public JComponent getComponent(){
}
}
EDIT
This is what I mean by dedicating
public class Foo{
private static Foo INSTANCE;
public static Foo getInstance(){
if(INSTANCE == null){
INSTANCE = new Foo();
}
}
public void createAndShowComponent(){
//do stuff
}
}
Inside createAndShowComponent(), I create a JComponent with all its components and their respective listeners without exposing the internals of the component I just created.
+1 for Composition over extension. It makes the API much cleaner since you only expose what methods are important for your new component
I agree with jzd it all depends.
Technically speaking, if you are dealing with GUI in my opinion it is best to build components when you need them, by extending for example JComponent. This way you can simply reuse them.
Personally I would never use the 2nd option in my class. I would only have a class return another component only if there is a very good reason for doing so, e.g. to enable user to modify a button look in your complex calendar component.
For a very simple reason each component class should know what it has this component for, and it should control the view accordingly to what is happening. Thus you would have appropriate methods.
I would say extending it would be better. Being able to use all its properties and using it like it is that object makes it a lot simpler to use. Just my personal Opinion. Both ways are good.
If you are dedicating the entire class to it. Might as well make it that by inheritence.
If your object IS a component, than extend it. If not, then use composition.
It really depends on what you are doing. If you want to include your new class on a JPanel for example, you will need to extend the component. If your code can add the component to the correct place on the GUI, then you don't have to extend it.
I would say none of them. Swing components are very (very) rich and can be customized for visualisation (L&F) and behaviour (events) in any manner. Another point is to create a group of different components and lay them out in a JPanel.
For decently sized projects I've been told that when you have classes extending JPanels that the best practice is to use nested classes to implement the listeners. For example I could have a class FactoryScreen that extends JPanel, and have a nested class FactoryScreenBrain that implements all the necessary listeners.
I've never been able to get a good explanation for specific benefits or disadvantages to encapsulating my classes in this fashion, and until now have always just had classes that both extend JPanel and implement listeners. Can someone provide me some guidance on this?
Having inner classes for your listeners makes the purpose of all those listeners very clear. It can also sometimes avoid many if checks at the expense of a bit more coding.
If you have a panel
public class MyPanel extends JPanel implements ActionListener
...
button1.addActionListener(this);
button2.addActionListener(this);
checkbox1.addActionListener(this);
timer3.addActionListener(this);
public void actionPerformed(ActionEvent e)
{
if(e.getSource() == button1)
else...
... //potentially many elses
}
it's very difficult to see exactly what is going on in your actionPerformed because it handles so many different events at once. Having a panel:
public class MyPanel extends JPanel
...
button1.addActionListener(new ButtonListener());
button2.addActionListener(new ButtonListener());
checkbox1.addActionListener(new CheckBoxListener());
timer3.addActionListener(new TimerListener());
private class TimerListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
//do stuff related only to timers
}
}
Now if your timer has an issue you can easily identify the class with the problem.
Even more importantly, on the grand scale, it makes your code more readable. If somebody else wants to work on this class and they need to fix event handling with the timer, they don't have to search through your ifs to find the part with the timer logic.
I think that anything is better than having a class extend a Swing Component and implement a listener as it gives the class too much disparate responsibilities and sets one up for creating the dreaded switch-board listeners. I try to use anonymous inner listeners that call methods from a separate control class. That way I divide out the responsibilities and can more easily test the behaviors of each class in isolation.
Good question, by the way.
If you extend a component and implement one or more listeners, it's tempting to add the listener(s) in the constructor. This potentially exposes a reference to an incompletely constructed object—sometimes called an escaped this. Working exclusively on the EDT mitigates the risk; but an anonymous inner class can further reduce it. Problems from reflection or indirect exposure remain.
Note: This is for a SWING course I am taking.
I have an assignment to make a simple graphics package (draw circles, squares, etc).
I was thinking of having multiple dialog boxes for entering the shape parameters, i.e:
Point has x,y
Circle has x,y,radius
Rectangle has x,y,width,height
etc.
I was thinking of creating a super dialog class with X,Y and extending it to allow for Width,Height or Radius etc.
For example, the rectangleDialog would invoke the super constructor with the additional parameters required:
public abstract class XYDialog extends JFrame {
public XYDialog(PARAMETERS ... params) {
// build the dialog by iterating through PARAMETERS
}
}
public class RectangleDialog extends XYDialog {
public RectangleDialog() {
super(PARAMETERS.WIDTH, PARAMETERS.HEIGHT);
}
}
then the super class is responsible for building the GUI
Does this seem like a reasonable approach? Does this make sense?
Thanks
Yes, I think it's a good solution. But, as stated before, reconsider the naming of your classes. If you extend a JFrame, call it SomethingFrame. If PARAMETERS is a normal class, it should not be in capitals.
I would also suggest extending JPanel instead of JFrame, and let the one instatiating these classes determine if to put them in a JFrame or a JDialog. A JFrame creates a whole new window, and you normally only have one main window for your application, whereas dialogs and panels are created on the fly.
After some advice on using jpanel - I'm new to java and playing around with the GUI elements.
Bascially what I'm curious about is if I can set up a Jpanel in one class, then somehow add labels etc to the that container, but from another class.
Is this possible ? or do i have to set the entire GUI up in one class, but then I guess I would have the same issue, if I wanted to update those fields I had set up in the main class from another class?
Apologies I don't really have any code that's usefull to demostrate here - I'm just trying to get the idea going, working out if its possible before I go ahead. And I'm not even sure if this is possible. Any advice would be greatly appreciated.
Thanks
As long as you have a reference to the JPanel, you can add whatever GUI-element you want, by calling add(JComponent comp) on the JPanel.
So, you can do something like this:
class Panel extends JPanel{
...
}
class Main{
public Main(JPanel thePanel){
thePanel.add(new JButton("Hello"));
}
}
Was this what you were looking for?
You can also update the fields added to the panel from another class, if you have a public accessor-method set up, in the class. So in your panel class, you have a method:
public JButton getButton(){
return button;
}
Then you can access the button from whatever class with a reference to your panel class, like this:
panel.getButton().setText("Some text");
Note that the button could just as well be public, then you could simply call the method directly: panel.button.setText("Some text"); but this is not considered good code, as it violates some general good OOP practices, not relevant to mention here.