Dynamic changing of layouts in swing - java

I am almost certain this question was asked before here: Java Swing: How to change GUI dynamically , but I seem to just have some fundamental misunderstanding in how it works.
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
public class JTest extends JFrame
{
public static void main(String[] args)
{
JTest t = new JTest();
}
Container pane;
public JTest()
{
setSize(500,500);
setTitle("JTest");
setDefaultCloseOperation(EXIT_ON_CLOSE);
pane = getContentPane();
pane.setLayout(new GridLayout(1,2));
JButton old = new JButton("old");
old.addActionListener(new OldButton());
pane.add(old);
JScrollPane scroll = new JScrollPane(new JTextArea(50,20));
pane.add(scroll);
setVisible(true);
}
private class OldButton implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
pane.setLayout(new GridLayout(1,2));
JButton old = new JButton("new");
old.addActionListener(new NewButton());
pane.add(old);
JScrollPane scroll = new JScrollPane(new JTextArea(50,20));
pane.add(scroll);
pane.validate();
}
}
private class NewButton implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
pane.setLayout(new GridLayout(1,2));
JButton old = new JButton("old");
old.addActionListener(new OldButton());
pane.add(old);
JScrollPane scroll = new JScrollPane(new JTextArea(50,20));
pane.add(scroll);
pane.validate();
}
}
}
This code should replace the preexisting layout with a new one anytime the button in the corner is pressed, but instead, it just adds the new layout to the frame. Can someone tell me what I'm doing wrong?
EDIT:
Adding some information. A picture for reference:
I'm making a set of components like this inside the scroll pane. whenever I press the "Make new field" button, I want it to add a "field" (the name of the field followed by a textarea or some such) to the set in that scrollpane. This means changing the layout of the area inside the scrollpane to include the new field.

OK -- so it looks like what you want to do (and please correct me if I'm wrong) is to add a new component to a JPanel that is displayed within a JScrollPane. If so, then you do not want to change or swap layouts, and you certainly don't want to keep adding new JScrollPanes. Instead consider doing:
Create one JScrollPane and add to your GUI. Don't re-add this as you'll only need one.
add a JPanel to the JScrollPane's viewport that uses a layout that allows multiple components to be easily added to it. Perhaps a GridLayout or a BoxLayout, depending on what you need.
Also consider not adding the above JPanel directly to the viewport but rather adding it to another JPanel, one that uses BorderLayout, adding the first JPanel to the BorderLayout-using JPanel's BorderLayout.PAGE_START position, and then add this to the JScrollPane's viewport. This way the first JPanel won't stretch to fill the viewport initially.
Then in your button's ActionListener, add your components to the first JPanel by calling .add(...) on it, and then call revalidate() and repaint() on that first JPanel to layout the newly added components and repaint the JPanel and its contents.

Ok, so it turns out this wasn't a layout problem at all. I had failed to realize that setting a new layout doesn't cause the previous layout's components to disappear, you have to remove them before adding the new components. That's why I was getting duplication.
Thanks for pointing me in the right direction, though.

Related

Multiple JPanels in one JFrame not showing top panel

So I'm writing a program in which I wish to have a single JFrame containing a JPanel header in a separate colour and directly underneath have a grid of buttons in a separate JPanel. So far my program works perfectly except for the fact that the header String isn't showing up in the NORTH panel. Instead I'm getting a box containing the set background colour with a small grey box in the centre. I'm wondering if I didn't set the size of the panel correctly?
I have heard this can be accomplished using JLabel, but when I tried to do this, it would not show the background colour that I had set.
So, could anyone please show me how to achieve the following either with the JPanel (preferably because I would like to know how it works and what I'm missing) or with JLabel: filling that little grey box in the middle of the header with a String.
Here is my code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Example {
public static void main(String[] args) {
// Initialize a panel for the header, and mainGrid which will contain buttons
JPanel panel = new JPanel();
JPanel header = new JPanel();
JPanel mainGrid = new JPanel();
// Initialize the header
DisplayPanel message = new DisplayPanel();
header.setBackground(Color.ORANGE);
header.add(message);
// Initialize the mainGrid panel
mainGrid.setLayout(new GridLayout(2,2,2,2));
mainGrid.add(new JButton("1"));
mainGrid.add(new JButton("2"));
mainGrid.add(new JButton("3"));
mainGrid.add(new JButton("4"));
// Add the two subpanels to the main panel
panel.setLayout(new BorderLayout());
panel.add(header, BorderLayout.NORTH); // The issue is this panel isn't displaying the String created in DisplayPanel
panel.add(mainGrid, BorderLayout.CENTER);
// Add main panel to JFrame
JFrame display = new JFrame("Test");
display.setContentPane(panel);
display.setSize(200,100);
display.setLocation(500,200);
display.setVisible(true);
display.setResizable(false);
display.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private static class DisplayPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString("header" , 20, 20); // The string I want to be displayed
}
}
}
I would very much appreciate anyone's help or input as I have only been studying Java for a few months and this is my first post. Thank you in advance.
Also, any general tips on writing that you may have would be greatly appreciated.
I'm wondering if your problem is that you're nesting your message JPanel inside of the header JPanel, and the container header JPanel uses the JPanel default FlowLayout. Thus the component it holds won't expand on its own and will remain trivially small.
Consider either giving the header JPanel a BorderLayout so that message expands inside of it, or
use a JLabel to show your text, not a JPanel's paintComponent method. The JLabel should size itself to be big enough to show its text. If you do this and want it to show a background color, all you have to do is call setOpaque(true) on your JLabel, and you're set.
Actually, if you nest the JLabel, then there's no need to make it opaque. Just do this:
JPanel header = new JPanel();
JPanel mainGrid = new JPanel();
JLabel message = new JLabel("Header", SwingConstants.CENTER);
header.setBackground(Color.ORANGE);
header.setLayout(new BorderLayout());
header.add(message);
I would highly recommend using a GUI builder WYSIWYG IDE, like NetBeans, where you can easily drag and drop components to where they need to be. If you're doing any sort of complex GUI layout, it can be madness (and in my opinion, nonsensical) trying to write and maintain the code.
The layout your trying to implement would be trivial in NetBeans.

Swing GUI with FlowLayout, won't display on JFrame more than last component added

I am trying to display 2 panels that I have created in separate files one at the top and one at the bottom of my GUI with a button group between them. However, the window is only displaying one panel or the button group at a time. The panels and button group are displaying properly but only the last one added to the frame is being displayed at any given execution.
Here is the current code without any layouts...
package UserGUI;
import javax.swing.*;
import java.awt.*;
public class RealFrame extends JFrame {
JButton Close = new JButton("Close");
JButton Proceed = new JButton("Proceed");
AuthorPanel header = new AuthorPanel();
FreeSpacePanel disk = new FreeSpacePanel();
public RealFrame() {
super();
ButtonGroup Ops = new ButtonGroup();
Ops.add(Close);
Ops.add(Proceed);
JPanel OPS = new JPanel();
OPS.add(Close);
OPS.add(Proceed);
add(disk);
add(OPS);
add(header);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500,500);
setVisible(true);
}
}
JFrame uses a BorderLayout by default, so when you do...
add(disk);
add(OPS);
add(header);
You're adding each component to the same location (the CENTRE position), but the BorderLayout will only layout the last one added.
Instead, you should use something more like...
add(disk, BorderLayout.NORTH);
add(OPS);
add(header, BorderLayout.SOUTH);
See How to Use Borders for more details
add(disk);
add(OPS);
add(header);
The default layout manager of the content pane of the JFrame is a BorderLayout. If you don't specify a constraint then the component is added to the BorderLayout.CENTER. Only one component can be added to the CENTER so the only the last component is displayed.
Try:
add(disk, BorderLayout.NORTH);
add(OPS, BorderLayout.CENTER);
add(header, BorderLayout.SOUTH);
to see the difference.
Or try another layout manager on the frame. See How to Use Layout Manager for more information.

JFrame position three buttons one below another in the center

So I would like to have three JButtons all on top of each other, but not to large in width or height either. I am not too familiar with Java's layouts, and to be honest I am not too keen on them. Please view the image a code below to explain to me how, thanks.
package com.aqagame.harrykitchener;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
public class Main
{
private JButton playGame, playerNames, exitGame;
public Main()
{
JPanel mainCard = new JPanel(new BorderLayout(8, 8));
playGame = new JButton("Play Game");
playerNames = new JButton("Player Names");
exitGame = new JButton("Exit Game");
mainCard.add(playGame, BorderLayout.NORTH);
mainCard.add(playerNames, BorderLayout.CENTER);
mainCard.add(exitGame, BorderLayout.SOUTH);
JFrame window = new JFrame("Harry's AQA game");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.getContentPane().add(mainCard);
window.setSize(900, 800);
window.setLocationRelativeTo(null);
window.setVisible(true);
}
public static void main(String args[])
{
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Main();
}
});
}
}
Check out the Java Documentation for the different layout managers. I know you're not familiar with them, which is why you should probably start. Once you get used to them there is no end to their benefits. There is a lot of excellent information in the documentation and I am sure you will learn a lot. Personally, I recommend looking at the Box Layout:
Create JPanel that uses a GridLayout and add all the buttons to the panel. The GridLayout will automactially size the buttons to be the same size.
Set the layout manager of your main window to use a GridBagLayout.
add the panel to the main window using the default GridBagConststraints. Then the panel will automatically be centered both horizontally and vertically.
To not use Box or GridBag, I think a combination such as this may work out:
Have main panel (let's call it A) have a BorderLayout
Create another panel (let's call it B), with a FlowLayout, with constructor aligning components to the center
Create another panel (let's call it C), with a GridLayout, 1 column 3 rows
Add each button to a new JPanel with a FlowLayout (1 JPanel per button, so buttons are wrapped by a FlowLayout), and then add each of those JPanels to C
Add C to B
Add B to A (center position)
I think this should cause buttons to be on top of each other with small amount of padding while not being stretched widthwise and while appearing in the center of the screen.

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);
}
}

Aligning JButton to the right

I am creating an interface in java and i want to align the button to the right. I have try but its not working. Can someone tell me how to do it?
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Button_Alignment extends JFrame{
public JPanel header,body,footer;
public JButton add1;
public JButton save;
public Button_Alignment(){
super("BUTTON");
GridLayout g1 = new GridLayout(3,1);
setLayout(g1);
//////
header = new JPanel();
JButton add1 = new JButton("add");
header.add(add1);
JButton save = new JButton("save");
header.add(save);
//////
add(header);
header.setBackground(Color.cyan);
}
public static void main(String[] args){
Button_Alignment ba = new Button_Alignment();
ba.setSize(400, 400);
ba.setVisible(true);
}
}
Your current layout manager (GridLayout) is being created with 3 rows and a single column. Hence, the components you add to the JFrame will appear vertically from top to bottom. Worse still, GridLayout will aportion space equally amongst all 3 components, meaning that your buttons will stretch in both directions, which is almost certainly not what you require.
I would consider using an alternative layout manager. For simple layouts I tend to favour BorderLayout or FlowLayout. For more complex layouts I lean towards GridBagLayout although there are others who prefer MigLayout.
More information here.
Try like this:
JButton save = new JButton ("save");
setLayout (new BorderLayout ());
add (save, BorderLayout.EAST);
you set GridLayout to the JFrame constructor instead of JPanel (JPanel has by default FlowLayout), I think that
header.setLayout(new GridLayout(3,1));
header.add(add1);
header.add(save);
notice ---> but GridLayout in current ComponentOrientations to start from left to right, then 3rd. grid is empty
then only to add JFrame#add(JPanel), in your case
add(header);
A quick and dirty way is to put the button [or a container immediatly wrapping the button, if you want to add other components on the right next to your button] it in a container that uses the BorderLayout and use the BorderLayout.EAST layout constraint for that button [or wrapping container].

Categories