As part of our exam project we need to write a GUI in java, the problem is that the structure has got us stumped.

I'm not asking you to do our work, but if someone could nod us of in the right direction it would really be appreciated.

We want to make a GUI with a JTabbedPane in a JFrame.
The tab pane will have three tabs, all of which will have a list/grapchical rendering of a list in the top, and some input fields at the bottom.
So we thought we'd make a sub-class structure looking something like this:

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.LayoutManager;

import javax.swing.JComponent;

public class TabContent extends Container {
	public TabContent(JComponent tc, JComponent bc) {
		setLayout(new BorderLayout(6, 6));
		add(tc, BorderLayout.CENTER);
		add(bc, BorderLayout.SOUTH);
		
	}
}
import javax.swing.JButton;
import javax.swing.JLabel;

public class ReservationTab extends TabContent {
	public ReservationTab() {
		super(new JButton("Here goes a graph/list component."), new JLabel("Here goes the \"add reservation\" fields."));
	}
}

Then make two more *Tab classes for the other two tabs and add them to the tabbedpane in the same class that makes the JFrame.
Problem is that the text/input fields are depending on data/status from the list.
With this structure the calls between the different components seem rather clumsy.

Any advise on how to structure this?

Recommended Answers

All 18 Replies

Why are you not using JPanels as tabs? You can just add those to the JTabbedPane, and add any components to each tab you want!

You're right :)
But I'm not sure that makes a difference? I still need to define the content of those jpanels somewhere :)

Yes, but I think it will become a lot easier.
Make 1 class, which extends JFrame (or maybe a JPanel you put on the JFrame), and three other classes that extend JPanels. You add those three classes to the first, just like you are doing now.

Now in each of those classes, you can use a Layout manager, to control how all the elements are spaced out in the JPanel. You can also specify it yourself.

For more help, I would need to know what exactly you want in your tabs, and how the input fields should change (change position, become invisible?).

If your tabs are all different then there's no point doing anything other than simple JPanels.
If they all conform to certain style or content standards (eg a background image, or certain controls always in the same place) then its worth creating a subclass of JPanel with all the common elements, and instantiating that for each tab as a starting point.
I can't see any circumstances in which you would benefit from creating different subclasses for each tab.

Sorry about the late response :)
I'm still thinking about going to go with the subclass structure.
The different tabs all have the same layout, with a component in the middle that needs to communicate with the component in the bottom.

JamesCherrill: I think the guide you send me is pretty good actually, but it primarily concerns the MVC structure, which I think we have figured out :)
All the classes I'm talking about would be part of the viewer.
One note though: You may want to quickly list the classes, and their purposes, before writing them out.
I think that would make it much more readable :)

Hiddepolem: I think making a separate class for each tab would make a lot of dupe code though?
Which is actually why I wanted to make a sub-class structure :)

It shouldn't, if the tabs are all different.
You only need to write the methods that need to be changed, compared to the normal JPanel.

All the buttons/textFields can be added, just like you want, what do you want to add in the subclasses?

The specific compnent for each tab :)
It just seems silly to write three classes that looks so much like each other :)

Here's the thing:
We need three tabs, each of them has some search fields in the top, a list/graphic in the middle and either a some info or input fields in the bottom.
The different components needs to be able to communicate with each other internally on a tab, and each tab needs to be able to comunicate with each other (pressing a button on one tab open another with some data sent from the first tab).

Wouldn't the easiest way be to make a super class tab, and define each tab as a subclass? Or am I out of my mind here? :)

Wouldn't the easiest way be to make a super class tab, and define each tab as a subclass? Or am I out of my mind here? :)

You are not out of your mind. That's exactly what I would do (and I suggested something like it in my earlier post), except that there's no value in defining them all as different subclasses. Just create a class with all the common elements, then make the individual tabs instances of that class and add their specific controls as required.

I made this in a few minutes, I hope this is the idea you want. You can edit anything on the JPanels.

Main class:

import javax.swing.*;

public class Test extends JTabbedPane{
	
	public static void main(String[] args) {
		JFrame f = new JFrame("Test");
		f.setVisible (true);
		f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
		f.setBounds (100,100,800,400);
		f.add (new Test());
	}

	Test() {
		add(new Tab1());
		add(new Tab2());
	}

}

Tab1:

import java.awt.*;
import javax.swing.*;

public class Tab1 extends JPanel{
	Tab1() {
		setLayout (new BorderLayout());
		add(new JTextArea (), BorderLayout.CENTER);
		add(new JButton("Hi!"), BorderLayout.SOUTH);
	}	
}

Tab2:

import java.awt.*;
import javax.swing.*;

public class Tab2 extends JPanel{
	Tab2() {
		setLayout (new BorderLayout());
		add(new JTextArea (), BorderLayout.CENTER);
		add(new JButton("Bye"), BorderLayout.SOUTH);
	}	
}

James: I imagine hiddepolen's suggestion matches yours?
But then what then the different tabs need to 'communicate'?
I'd guess the methods for that should be in the Test class?
And there would probably be some duplicate code in the Tab1/Tab2/Tab... classes?

It's very similar, but he uses subclasses for each tab whereas I would create one "template" class, including all the "duplicate" code, and have one instance per tab. Frankly I don't think that either has a decisive advantage over the other, so go with what you fancy.
For communication I would treat the tabs like any other collection of panels or windows - I'd go MVC (Model-View-Controller) with one or more Model (data) classes and one Controller. The Controller has all the code to manage the flow of logic as you open/close windows and move from tab to tab, and all the tabs share an instance of the Model so they all share the same data.

Hmm, is it okay to *nest* mvc structures?
All of this is kindof allready part of a mvc structure :/

Yes.
More specifically:
Controller: yes - high-level controller delegates "tasks" to lower level ones.
View: The whole point is to remove the need for any direct coupling between view classes, so the question of "nesting" doesn't apply here.
Model: The Model is what it is - but some subsets of the application may only use part of it.
So, in summary, "nesting" really only applies to Controllers, where its often a good idea.

Not to ignore your answer, but if we make a class for the jtabbedpane, and from within that add the three tabs (defined in three classes).
Would it then be okay to instantiate the tabs with handles to the tabbedpane class in the constructor, so that they could ask the tabbedpane to switch tab and send data to the other tabs?
Its very high coupling, but it seems to me like making a separate control class for the ui would give the same coupling :)

Unless things get particularly complicated I can see no reason why the tabbedpane class can't also be the controller. In smaller apps it's quite common to see the formal MVC structure being simplified into just a couple of classes. It's still a lot better then a free-for-all spaghetti architecture!

Great :)
How about the handles then? It seems like bad form to pass a reference to the tabbedpane class to the tab classes?
But I need them to have handles to it :)

On the contrary, it's absolutely essential. Every view class instance needs a reference to the controller class instance so it can pass requests back up to the controller.

ps: Normally its the controller that creates the new view window/tab, and passes a reference to itself as a param to the constructor. The other common parameter is a ref to the Model instance that this view is expected to work with. So somewhere in the controller you usually see something like:

JComponent aView = new OneOfMyViews(this, theModel);

commented: Thank, this has been bugging me for a looong time :) +3

Right, I just wanted to apologize for leaving this thread. That's actually not like me at all.
The inputs in this thread was a great help at a time where my group and I where in a almost panic like state, so thank you both very, very much :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.