How to implement pages in Java Swing app.? - java

I have some experience in Java creating Apps and would like to learn more, and so have decided to create an application that will have different pages. For example the initial frame will show a menu of buttons that will lead to different frames, showing different components and layouts.
I'm not too sure the best practice of implementing pages. I think I could store the JFrame windows in a list, then use a button handler class to maybe change the visibility of the different frames, only allowing the relevant frame to be visible when the user clicks on a button. I think this method could work, but is there a more efficient/practical way of doing this?
I am aware of CardLayout, however for this program I am trying to learn MigLayout; so that won't be possible (as far as I'm aware). I hope this question is not too vague, I'd just like to know the best practice when it comes to creating applications in Java with different pages.

Can use Tabbed Panes, it is the best for storing pages.
https://docs.oracle.com/javase/tutorial/uiswing/components/tabbedpane.html
Also I noticed that you need to consider top level containers properly, because you don't need to create every time a JFrame for each Page, at least if it was necessary(For example: an editor, create a new window so you need to create a new JFrame, in your case I don't think so) so please consider the link below.
https://docs.oracle.com/javase/tutorial/uiswing/components/toplevel.html

JInternalFrame is a part of Java Swing . JInternalFrame is a container that provides many features of a frame which includes displaying title, opening, closing, resizing, support for menu bar, etc. Internal frames with components example
Code to create multiple internal frames:
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
class solution extends JFrame {
// frame
static JFrame f;
// label to diaplay text
static JLabel l, l1;
// main class
public static void main(String[] args) {
// create a new frame
f = new JFrame("frame");
// set layout of frame
f.setLayout(new FlowLayout());
// create a internal frame
JInternalFrame in = new JInternalFrame("frame 1", true, true, true, true);
// create a internal frame
JInternalFrame in1 = new JInternalFrame("frame 2", true, true, true, true);
// create a Button
JButton b = new JButton("button");
JButton b1 = new JButton("button1");
// create a label to display text
l = new JLabel("This is a JInternal Frame no 1 ");
l1 = new JLabel("This is a JInternal Frame no 2 ");
// create a panel
JPanel p = new JPanel();
JPanel p1 = new JPanel();
// add label and button to panel
p.add(l);
p.add(b);
p1.add(l1);
p1.add(b1);
// set visibility internal frame
in.setVisible(true);
in1.setVisible(true);
// add panel to internal frame
in.add(p);
in1.add(p1);
// add internal frame to frame
f.add(in);
f.add(in1);
// set the size of frame
f.setSize(300, 300);
f.show();
}
}

Related

GUI, JComboBox and opening a new window

I am new to Java and especially new to GUI and it's super confusing to me right now.
I'm making a program for class that is supposed to have a menu (JComboBox I'm assuming) that opens a new window when an option is selected. I am just working on the first option where you click "The Matrix" and a new window pops up with two buttons called "Red Pill" & "Blue Pill" and thats where I've hit a wall.
I got to the point where I am able to create a new window (not sure if this is even the right route to take for opening the new window) but, When I try to add Buttons to the new pop up window nothing shows up....
Thanks for any help or pointers in the right direction!
public class MultiForm extends JFrame{
private JComboBox menu;
private JButton bluePill;
private JButton redPill;
private static String[] fileName = {"", "The Matrix", "Another Option"};
public MultiForm() {
super("Multi Form Program");
setLayout(new FlowLayout());
menu = new JComboBox(fileName);
add(menu);
TheHandler handler = new TheHandler();
menu.addActionListener(handler);
}
private class TheHandler implements ActionListener{
public void actionPerformed(ActionEvent event) {
********************************************************************
//Create a new window when "The Matrix" is clicked in the JCB
JFrame newFrame = new JFrame();
JPanel panel = new JPanel();
newFrame.setLayout(new FlowLayout());
newFrame.setSize(500, 300);
newFrame.setDefaultCloseOperation(newFrame.EXIT_ON_CLOSE);
Icon bp = new ImageIcon(getClass().getResource("Blue Pill.png"));
bluePill = new JButton("Blue Pill", bp);
newFrame.add(bluePill);
Icon rp = new ImageIcon(getClass().getResource("Red Pill.png"));
redPill = new JButton("Red Pill", rp);
newFrame.add(redPill);
add(panel);
newFrame.setVisible(true);
}
}
public static void main(String[] args) {
MultiForm go = new MultiForm();
go.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
go.setSize(400, 200);
go.setVisible(true);
}
}
I tried doing newFrame.add(BluePill) and it created a button that was the size of the entire window and it would not allow me to add both buttons that way
That's because the frame uses a BorderLayout by default. Unless you specify otherwise, the component's will be added to the CENTER position, BUT, BorderLayout will only allow a single component to be managed at each of the it's five available positions, so you are only seeing the last component you added.
See How to Use BorderLayout for more details
so I figured that wasn't the correct way
It's the right approach, you just need to use a layout manager which can accommodate more components or change the position which you are adding the buttons
In this little example, I've just use a FlowLayout, but you can use what ever is going to give you the effect you desire
JFrame newFrame = new JFrame();
newFrame.setLayout(new FlowLayout());
newFrame.setDefaultCloseOperation(newFrame.EXIT_ON_CLOSE);
bluePill = new JButton("Blue Pill");
newFrame.add(bluePill);
redPill = new JButton("Red Pill");
newFrame.add(redPill);
newFrame.pack();
newFrame.setVisible(true);
As a general rule of thumb, I don't like adding components like this directly to a top level container, I prefer to use a intermediate container, like a JPanel, this gives me more possibilities for re-use, but that's me.
You should also only make the frame visible when it's actually ready, otherwise you may find that some times, the components won't show up
See Laying Out Components Within a Container for more details
You are not using the getContentPane() method from the new JFrame.
You have to actually use getContentPane() first because you're not adding any component to the JFrame itself but to an intermediate "panel".
JFrame newFrame = new JFrame();
JPanel panel = new JPanel();
newFrame.setSize(300, 200);
newFrame.setDefaultCloseOperation(newFrame.EXIT_ON_CLOSE);
bluePill = new JButton("Blue Pill");
panel.add(bluePill);
redPill = new JButton("Red Pill");
panel.add(redPill);
newFrame.getContentPane().add(panel);
newFrame.setVisible(true);
You'll have to add a Layout to the JPanel or/and the JFrame and play with the sizes of the component but with this you're on the right path.
I always put the setVisible method a the end, after adding all the components to the frame.
You made some mistakes.
add(bluePill);
will not do what you want, even if it would, it would still be wrong.
(sounds weird, but I'll explain it)
First the "right" way to do it:
//Create a new window when "The Matrix" is clicked in the JCB
JFrame newFrame = new JFrame();
newFrame.setSize(300, 200);
newFrame.setDefaultCloseOperation(newFrame.EXIT_ON_CLOSE);
bluePill = new JButton("Blue Pill");
newFrame.getContentPane().add(bluePill);
redPill = new JButton("Red Pill");
newFrame.getContentPane().add(redPill);
newFrame.setVisible(true);
Notice I added "newFrame", because you were calling the method of MultiForm.
That's because "add()" is the same as "this.add()" and "this" points to MultiForm. Check it with this line if you want:
System.out.println(this.toString());
The "getContentPane()" is best explained with this image:
You were adding it directly to the JFrame (I don't even know what exactly happens then).
It is also good practice to set the frame visible when it is ready to be visible. Your frame did not contain anything when you made it visible.
Now to the JPanel. A JPanel can hold some elements like JButton,etc. and it can also have a layout. Since you didn't use the JPanel at all, i removed the line from your code. You can still add the JPanel to your ContentPane and add a Layout to the JPanel. (You can also add JPanels to JPanels to create complex layouts)
I hope this was clear for you.

Visualization issue of a simple GUI in Java

I did a very simple GUI in Java but when I run the program, the GUI acts wierd!
As soon as I run the application: the GUI shows like this:
Once I simply minimize it and get it back up, it shows fine, like this:
This is the very simple code:
public class Prova2 {
public static void main(String[] args) {
JFrame frame = new JFrame("A Simple GUI");
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(650, 120);
frame.setLocation(430, 100);
JPanel panel = new JPanel();
frame.add(panel);
JLabel lbl = new JLabel("Select one of the possible choices and click OK");;
lbl.setVisible(true);
panel.add(lbl);
String[] choices = { "CHOICE 1","CHOICE 2", "CHOICE 3","CHOICE 4","CHOICE 5","CHOICE 6"};
JComboBox<String> cb = new JComboBox<String>(choices);
cb.setVisible(true);
panel.add(cb);
JButton btn = new JButton("OK");
panel.add(btn);
}
}
What am I missing in order to show the GUI fine (with all its element displayed) as soon as I run the application?
It's annoying having to necessarily minimize or resize the window in order to show the GUI properly!
I tested your code and the problem is you are setting the visibility on true before you create the items inside your JFrame. So just cut the frame.setVisible(true); and paste it as the last line of the constructor.
also I see you aren't using a layout manager which is heavy recommended. Check this for information.
Use layout manager
Follow a main Swing Toolkit principle: all UI should be manipulated and started on EDT thread ( UI thread ). Here is a very good explanation http://www.pushing-pixels.org/2007/12/06/unwritten-rule-of-working-with-swings-edt.html

Setting JPanel layout

(Say) I've created a JPanel with three buttons. I want to place the buttons as follows (I've done this using netbeans GUI editor. But I need to write the whole GUI manually).
Can some one show me a way to achieve this.
(In words, I need to place some buttons right aligned, some other left aligned.)
I guess you want the Configure button to be as far to the left as possible, and the ok and cancel grouped together to the right. If so, I would suggest using a BorderLayout and place the Configure button in WEST, and a flow-layout for Ok, Cancel and place that panel in the EAST.
Another option would be to use GridBagLayout and make use of the GridBagConstrant.anchor attribute.
Since you're taking the time to avoid the NetBeans GUI editor, here's a nice example for you :-)
Code below:
import java.awt.BorderLayout;
import javax.swing.*;
public class FrameTestBase {
public static void main(String args[]) {
// Will be left-aligned.
JPanel configurePanel = new JPanel();
configurePanel.add(new JButton("Configure"));
// Will be right-aligned.
JPanel okCancelPanel = new JPanel();
okCancelPanel.add(new JButton("Ok"));
okCancelPanel.add(new JButton("Cancel"));
// The full panel.
JPanel buttonPanel = new JPanel(new BorderLayout());
buttonPanel.add(configurePanel, BorderLayout.WEST);
buttonPanel.add(okCancelPanel, BorderLayout.EAST);
// Show it.
JFrame t = new JFrame("Button Layout Demo");
t.setContentPane(buttonPanel);
t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
t.setSize(400, 65);
t.setVisible(true);
}
}

Switching panels and passing data in Swing

I'm just starting out with Swing - I'm sorry if this question is hard to follow, but I feel like this is a very simple thing but it seems surprisingly hard in Swing.
I have a panel with two text fields and a submit button.
I've added a listener on the submit button, when it's clicked I validate the data and such.
Now, I want the frame to display a new panel - get rid of the current panel with the text fields and submit button, and instantiate a new one based on the data entered in the text fields.
How can I send this data back to the frame, so the frame can remove the current panel and replace it with a new, different panel, created with the data from the first panel.
Though it's not what I'm doing, it could be thought of like a login.
Display login panel
Panel gets username and password, validates (validation could be done higher up, too)
If validated, replace login panel with real content panel
This is surprisingly hard to figure out in Swing. Should I be defining my own event type and making the frame a listener for that event?
If I understood your question, you can use callback logic like this;
MyLoginPanel login = new MyLoginPanel(new IMyCallback(){
public void processLogin(){
//frame can remove the current panel and replace it with a new
}
});
MyLoginPanel extended from Jpanel with Constructor public MyLoginPanel(IMyCallback callback)
IMyCallback is an interface which has public void processLogin() method.
You could call callback.processLogin(); from LoginPanel
Does it work for you?
You should look at the java.awt.CardLayout. This Layout can handle multiple panels which are stacked on top of each other. And you can choose which panel should be the topmost and therefore visible.
The following code shows the relevent parts from the tutorial mentioned above:
//Where instance variables are declared:
final static String BUTTONPANEL = "Card with JButtons";
final static String TEXTPANEL = "Card with JTextField";
//Where the components controlled by the CardLayout are initialized:
//Create the "cards".
JPanel card1 = new JPanel();
JPanel card2 = new JPanel();
//Create the panel that contains the "cards".
JPanel cards = new JPanel(new CardLayout());
cards.add(card1, BUTTONPANEL);
cards.add(card2, TEXTPANEL);
and to switch the visible panel:
CardLayout cl = (CardLayout)(cards.getLayout());
cl.show(cards, TEXTPANEL);

What's wrong with JSplitPanel (or JTabbedPane)?

I have two panels that i wish to display to the user. I decided to add them to a JTabbedPane. I also want to allow the user to have a side by side view of them both at the same time. So I added the two panels to my JTabbedPane and then i created a JSplitPanel as such :
tabs.addTab("Align Image Points", imageControlPanel);
tabs.addTab("Align Map Points", mapControlPanel);
JSplitPane splitPane = new JSplitPane(
JSplitPane.HORIZONTAL_SPLIT, true, imageControlPanel,
mapControlPanel);
tabs.addTab("Side by side view", splitPane);
The resulting JTabbedPane only has one tab! When i remove the JSplitPane everything works ok. Two tabs. I then tried simplifying the problem to post here and i came up with this :
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
public class Test {
public static void main(String[] args) {
JFrame f = new JFrame("Test");
JButton b1 = new JButton("First");
JButton b2 = new JButton("Second");
JSplitPane s = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,true,b1,b2);
JTabbedPane tabs = new JTabbedPane();
tabs.addTab("First", b1);
tabs.addTab("Second", b2);
tabs.addTab("Both", s);
f.getContentPane().add(tabs);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
}
This gave me another problem! It displays 3 tabs but the third tab's split pane displays no buttons!
So my question is What is wrong with JSplitPanel? You can't have it display objects that are already displayed in another tab? It makes no sense. Please help me.
(Note: i don't want to duplicate the components that i am about to display as i want them to be the same reference)
Swing UIs are hierarchical and you can only add a component to the hierarchy once. If you add a component to more than one container you'll get unpredictable results. You are correct to not want to duplicate the components, but you'll need a listener on the JTabbedPane to add and remove each component from the tab or the JSplitView as the selection of the tabs changes.
tabs.addChangeListener( new ChangeListener() {
public void stateChanged(ChangeEvent e) {
// Reorganise the display based on the current tab selection.
}
}
I had the same problem that you had. what I had resolved for this issue, I made the each GUI as MVC pattern(Model-view-controller) that controller knows how to iterative with gui components.
I created a new instance of GUIs(View) on each Tab;however, I injected the same instance of controller for that GUI as constructor parameter since the controller knows how to handle GUI flow and behaviors.
for example,
GUIView1Controller controller1 = new GUIView1Controller();
GUIView2Controller controller2 = new GUIView2Controller();
// Add new instance GUI ; however , use the same instance of controller
JSplitPane s = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,true,
new GUIView1(controller1), new GUIView2(controller2));
JTabbedPane tabs = new JTabbedPane();
tabs.addTab("First", new GUIView1(controller1));
tabs.addTab("Second", new GUIView2(controller2));
tabs.addTab("Both", s );
GUIView1 and GUIView2 will register all GUI listeners to the controller, so the controller will be notified and take an action for the listeners. whatever the GUIView1 on "First" tab is changed, the GUIView1 on "Both" tab also is updated as the same behaviors of the GUIView1 on "First" tab.
The drawback was you have to create a new instance of the GUIView on the tab and JSplitPane; however, the controller can control and share all gui events and behaviors.
I hope it helps.
Tiger.

Categories