Java Observable/Observer vs just passing references - java

I'm trying to get a grasp on a couple concepts. Lets imagine you have a JFrame and in that JFrame there are two panels, we'll say left_half and right_half. If I click a button in right_half, I want something to change in left_half. The issue is that the right half doesn't know the left half exists. So, you could tell the Frame, but technically neither panel knows the Frame exists either, right? The Frame can change the panels, but panels can't change the Frame, or so it seems to me.
So, I pass a reference to the Frame into the panels. Now the right_half can call Frame.setVariable(data) and the Frame can, from that same method, say left_half.setStuff(data). That just seems wrong to me and I have been looking for a way to do it without passing references up and down the hierarchy.
Next, someone says "That's why Observable exists!!" Cool, I think to myself. I then found many confusing examples of how to use Observable that didn't help at all. Finally I see this one, which makes sense.
http://www.javaquizplayer.com/blogposts/blogpost7.html
However, it has this: "observable.addObserver(mainWindow);" mainWindow is the equivalent of Frame in my example above, and it had to pass a reference to attach the Obserable to! So even with Observable, I have to pass references down the hierarchy?
It just seems wrong. If it's not wrong, that's fine... I can do it this way. However, my question once all that back-story is finished is simply this: how are you supposed to pass data between two panels? I'm okay with abstract answers if they're in plain language, I'm okay with code samples if they're short and easy to follow. I'm not a pro Java coder, I can't just search through 29 API pages and 1400 lines of code and just suddenly understand how it works... yet. I'll get there.

The observable pattern (in the form of event listeners) is OK and is good practice. You see, even though RightPanel knows someone might be listening to all its events, it does not know who is listening. Well, technically, it could go through all its listeners and use reflection to find out who they are; now, that would be bad practice.
As it is, RightPanel knows someone might be listening to it, and that's all. Components are always aware someone might be listening, since the whole Swing is based on it. What matters is that RightPanel compiles without LeftPanel (or frame), and is completely decoupled from it, except via the listener interface. Not only cool, but standard.
As a side note, your class structure does not have to mirror your nesting panel hierarchy. Depending on what you are doing, it may be entirely fine to control behavior of both left and right panels from inner classes within Frame. (Personally, I'd use a JPanel, not a JFrame, since it allows for more flexibility, but this can be easily refactored). Otherwise, you risk splitting your View/Controller into too many closely coupled classes, and that would violate encapsulation and cause a lot of boilerplate code. Normally, I don't code big fat classes and try to refactor them into smaller ones; Swing is usually an exception. Better one big fat class than a maze of densely coupled classes. Unless of course you have a reusable component or some piece of functionality that can be clearly and intuitively decoupled; not just a couple of buttons or checkboxes that have no meaning in and of themselves. The simple fact that some subcomponents are situated within a certain panel in a component tree should not be a major factor IMHO.
For that matter, I usually don't nest JPanels; I use MigLayout and make all components into siblings. Matter of taste! I'd just encourage you to check out MiGLayout first and see whether you like it.

Related

JFrame vs Container

I read that the window that appears using the JFrame class is a Container with the predefined features (minimize, closing), but I found people who were not using the JFrame class but other classes (one of them the Container) which was far more hard.
Why do they do it that way? Is it because the JFrame class always has a predefined window that you can manipulate some aspects of it but the Container and the other classes give you more freedom of how you can create a window?
For an example to my question (I don't know if its real or not) in the JFrame class the close button always go to right to corner of the window but if I do it the other way you can put it everywhere you like. (If it can be answered with a yes or no).
So my qusetion is why they do it that way
There are two "main" reasons why. First is about overall good programming.
We tend to recommend avoiding extending from classes to which we are not adding any new functionality or repeatable features. If the whole reason for extending from JFrame is just so you can display some components, then it's really not a good choice or starting point.
JFrame is also a complex, compound component. That is, it's actually made up of a number of other layered components which work together to provide an overall experience.
*From How to Use Root Panes
This means that there is a lot of added complexity you'd have to be willing to manage if you extended from this class, a lot of overhead just to display a few components.
In principle, it's better to use composition over inheritance, which leads into the second point.
Extending from any class locks you into that classes use case. In the case of JFrame, you can only ever display what ever is managed by the class via a JFrame, there is no flexibility or entry point for re-usablility.
If, instead, you started with a base class of, say JPanel, you can add that to what ever container you want when ever you want, it increases the flexibility and re-usability of the class over all.
For an exaple to my question(i dont know if its real or not) in the JFrame class the close button always go to right to corner of the window but if i do it the other way you can put it everywhere you like.(If it can be answered with a yes or no)
Yes and no. The frame border is defined by the look and feel delegate, so you're not actually starting at the right place to begin with anyway.
Most look and feel delegates delegate the frame border to the native platform, in the case of Windows, yes, the close button is on the right, on Mac it's on the left.
In any case, it's better to support user expectations, placing the close button in an unusual place might make the UI "pretty", but diminishes the user experience - as a general guide line, don't diminish the user experience, no matter how awesome your program or UI, user's won't like you for it - but that is a (very broad) question for another day

How do I make one component visible in more than one pane in a JTabbedPane?

I was wondering if there was a way to make one component (in this case a JPanel) visible in more than one of the tabs.
I have a simple JFrame which is completely filled with a JTabbedPane. Each tab has a slightly different function, which is why they're in different tabs. However, they each output the same type of information. I was wondering if there was a way to make it so the same output panel could be seen in all the tabs, without having to create one panel for each tab.
I realize that it is impossible to add one component multiple times (and have it display independently each time), which is why I'm not optimistic about this being possible, however if it is, it would make my code much cleaner. In the case that this is not possible, I am completely open to alternate suggestions that achieve a similar result. I am in the very beginning of my project, so it won't be too difficult to change things.
This image gives a rough idea of what I'm trying to make it look like:
I have searched around for anyone dealing with this issue, however I have had little luck finding anything relevant. If I missed something, I apologize for wasting your time.

Syntax of establishing JFrame. Which is correct?

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.

Java graphic as an object/class

I'm sorry this is probably way too basic to be on here, but it's a subject I've been struggling with for about a month now and I don't know where else to go (as far as I know there is no "noob overflow", lol).
I'm trying to create a class that would:
1. put an image on a window (a JFrame, JPanel or other container)
2. be able to support keyboard and mouse listeners
3. could have multiple instances in the same container
So anyway I've tried all the usual places - Google, YouTube, the official Java site (sorry forgot the URL) and of course here on Stack Overflow - but haven't been able to find anything even remotely similar to what I'm trying to do.
Of course, I've also considered the possiblity that maybe it can't be done at all. There doesn't seem to be any kind of standard "JImage" or "JGraphic" that works like JButton or JLabel, and for whatever reason graphics requires a completely different list of (extremely involved) processes and procedures. As an example, in this post: How to "really" draw images in a Java app - it took me 60+ lines of code and 2 classes to just come close. That project didn't work in the end because for some reason it would only let me create one instance (even it you created 2-4 in the main method, it would only display the last one you told it to add).
But anyway, assuming that I'm not trying to "re-invent the wheel" here and it is actually possible (in Java), does anyone have an idea as to how (or at least know of a better site to study it)? Unfortunately most of the sites I've visited tend to assume you know all the inner workings of images (I know what a pixel is but that's about it - Buffers, Rastars etc. are still beyond me). It would be absolutely outstanding if there were a site that would explain it in layman's terms, if such a site exists. Thanks in advance.
Just use a plain old JLabel.
Regarding your requirements:
put an image on a window (a JFrame, JPanel or other container).
You can give a JLabel an ImageIcon of the image of interest and it will display it. This can then be easily placed in any other container such as a JPanel or JFrame.
be able to support keyboard and mouse listeners
Any component that extends JComponent, such as a JLabel allows for use of MouseListener, MouseMotionListener and can listen for keyboard input via Key Bindings.
could have multiple instances in the same container
You can add as many as you'd like to any container. Just be cognizant and respectful of the layout managers in use.

What's so special about CardLayout vs manual adding/removal of JPanels?

There have been many times on StackOverflow where a user asks a question like this...
I have a main JPanel that contains a child JPanel. When the user clicks a
button, the child JPanel should change to a different JPanel. How can I
achieve this.
More often than not, the user has actually tried to implement this problem, but can't get it working.
Whenever I answer this question, I tell them to do something like this (put simply)...
JPanel myFrame = new JPanel();
myFrame.remove(oldPanel);
myFrame.add(newPanel);
I see this as quite a legitimate answer, and I personally have used this in many of my own Java projects without problem. However, I always get downvotes for my answer, and everyone just says "Use a CardLayout".
So my question is, why is everyone so fascinated with CardLayout, to the point where my answer deserves a downvote? Why should I choose to use a CardLayout rather than adding/removing panels using my code above?
As a further question, would you still be suggesting CardLayout for interfaces that have dynamic JPanels. For example, most of my programs implement a custom plugin framework where there could be many hundreds of JPanels, but I only load and display the panels as they are actually required. For the normal use of the program, most of the panels would never actually be loaded or required. For this type of scenario, would my coding approach be the best solution, as I understand that CardLayout would require me to actually create all of the JPanels even though most will never be used?
With CardLayout, it's easier to have loose coupling (though not impossible with roll your own)
With CardLayout, the preferredSize of the card-holder is that of the largest card it holds.
CardLayout is harder to fark-up, and allows almost trivial contiguous component swapping its next() and prev() methods.
You can easily associate the desired component with a constant -- no need to have to create a Map<String, Component> for this purpose as it's already there for you. I've not infrequently used enums for this.
No need to remember to call repaint() and revalidate() when swapping components.
It's built for and allows for easy re-use of components.
CardLayout has been thoroughly tested and proven to work. It correctly acquires the component-tree lock and performs component validation in order to ensure that nothing can go wrong. Your solution, while it may work most of the time, will fail under certain circumstances.
This all boils to reinventing the wheel: Why would you want to when such a time-tested class is already available?

Categories