Swing: JscrollPane with autonomous content size - java

I have a panel with layout (for example, BorderLayout) and a JScrollPane on its center. JScrollPane has content inside it (a JPanel)
The thing is, that when this JScrollPane resizes, I do not want its content to resize. For example, if layout increases the JScrollPane, I want its content to be as small it was (and occupy only part of the pane), but it resizes to fit pane.
I also need an opportunity to reduce content inside the pane and increase it manually (there is no problems with increasing, they are in reducing).
So, how can I achieve content size independency? Of course, I need to save scrolling features, if content will be bigger than JScrollPane.
Here is a simple example:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class TestScroll extends JFrame {
public TestScroll() {
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setSize(500, 500);
init();
}
private void init() {
setLayout(new BorderLayout());
// Inner panel
final JPanel innerPanel = new JPanel();
innerPanel.setOpaque(true);
innerPanel.setBackground(Color.BLUE);
innerPanel.setPreferredSize(new Dimension(200, 200));
// Scroll
final JScrollPane scrollPane = new JScrollPane(innerPanel);
add(scrollPane, BorderLayout.CENTER);
// Buttons
JPanel buttonPanel = new JPanel();
JButton extendButton = new JButton("Extend inner panel");
extendButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
innerPanel.setPreferredSize(new Dimension(innerPanel.getWidth() * 2,
innerPanel.getHeight() * 2));
innerPanel.revalidate();
}
});
buttonPanel.add(extendButton);
JButton reduceButton = new JButton("Reduce inner panel");
reduceButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
innerPanel.setPreferredSize(new Dimension(innerPanel.getWidth() / 2,
innerPanel.getHeight() / 2));
innerPanel.revalidate();
}
});
buttonPanel.add(reduceButton);
add(buttonPanel, BorderLayout.NORTH);
setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new TestScroll();
}
});
}
}
So, problem statement:
I do not want inner panel to stretch to the pane (but pane can be resized by outer layout, so the panel must just keep its size).
I want to be able to reduce inner panel manually so it can occupy only a part of the scroll pane.
And, of course, I want to save scrolling functionality when inner panel is larger than scroll pane.

Did you follow Andrew's link about using layout managers to achieve your goal?
Here is another simple example:
//final JScrollPane scrollPane = new JScrollPane(innerPanel);
JPanel outer = new JPanel();
outer.add( innerPanel );
final JScrollPane scrollPane = new JScrollPane(outer);

Related

Resizing JPanel With BorderLayout

I am trying to resize the center panel of my BorderLayout but the size is not changing. It keeps filling the rest of the frame that is available. I have tried setting the preferred size but has no effect. I would like how size of the frame but only need a portion of the center to be actually a panel for later use.
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
public class Gui extends JFrame {
Border blackline = BorderFactory.createLineBorder(Color.black);
private JPanel board;
private JPanel buttons;
private JButton setMissing, by4, by8;
public Gui(){
setUpGui();
}
public void setUpGui(){
this.setSize(1000,1000);
this.setTitle("Comp361 Assignment One");
addButtons();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
board = new JPanel();
board.setPreferredSize(new Dimension(400,400));
this.add(board, BorderLayout.CENTER);
//Sboard.setBackground(Color.Gray);
board.setBorder(blackline);
this.setVisible(true);
}
public void addButtons(){
buttons = new JPanel(new FlowLayout());
setMissing = new JButton("Set X");
by4 = new JButton("4 by 4");
by8 = new JButton("8 by 8");
buttons.add(setMissing);
buttons.add(by4);
buttons.add(by8);
this.add(buttons,BorderLayout.PAGE_START);
}
public static void main (String[] args){
new Gui();
}
}
For extra padding around the central panel, you might put it to a panel with GridBagLayout (with no constraint) to center it, then add the GBL panel to the CENTER of the BorderLayout.

Adding JScrollPane to a JFrame

I want to add JPanel containers to a JScrollPane and add this scroll pane to a JFrame. But when I add multiple panels to the scroll pane this happens. The gap between the scroll pane and the top bar increases. I use BoxLayout as layout manager for all the components that I use.
Here is my take on laying out this GUI. Some notes:
Rather than use a BoxLayout in the JScrollPane it puts a GridLayout in the PAGE_START of a BorderLayout. This is fine for when it's OK to stretch the elements in the scroll pane to the full width of the GUI. Stick to a BoxLayout (which I rarely use) or a GridBagLayout if it's necessary to keep the elements at their preferred size.
This strategy of layout is basically 'divide and conquer' in that it starts with the smallest sub-divisions of the GUI (e.g. the FlowLayout for the buttons) and then adds those containers to larger containers with different layouts and constraints (e.g. adding that button panel to the LINE_END of a BorderLayout - to push I to the right of the GUI) as needed for the overall effect.
I'd also consider using a JList (using a panel for the renderer) in the scroll pane. It depends on the use as to whether that makes sense.
Note that this code is an MRE. An MRE should have everything that's needed (including imports, a class structure and the main method) for another person to compile and run the code.
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.ActionEvent;
// ref: https://stackoverflow.com/a/70934802/418556
public class ScrollPaneTestGUI {
int elementCount = 1;
JPanel elementsPanel = new JPanel(new GridLayout(0,1,2,2));
public ScrollPaneTestGUI() {
initGUI();
}
private void initGUI() {
// this will become the content pane of the frame
JPanel gui = new JPanel(new BorderLayout(4,4));
gui.setBorder(new EmptyBorder(4,4,4,4));
JPanel pageStartPanel = new JPanel(new BorderLayout(2,2));
gui.add(pageStartPanel, BorderLayout.PAGE_START);
pageStartPanel.add(new JLabel("LINE START label"), BorderLayout.LINE_START);
// default flow layout is good for this one
JPanel buttonPanel = new JPanel();
pageStartPanel.add(buttonPanel, BorderLayout.LINE_END);
buttonPanel.add(new JButton("Does Nothing"));
Action addToScrollAction = new AbstractAction("Add to scrollPane") {
#Override
public void actionPerformed(ActionEvent e) {
elementsPanel.add(getPanelForScroll());
elementsPanel.revalidate();
}
};
JButton addToScrollButton = new JButton(addToScrollAction);
buttonPanel.add(addToScrollButton);
JPanel scrollPanel = new JPanel(new BorderLayout());
scrollPanel.add(elementsPanel, BorderLayout.PAGE_START);
gui.add(new JScrollPane(scrollPanel,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER)
);
for (int ii=0; ii<2; ii++) {
elementsPanel.add(getPanelForScroll());
}
JFrame frame = new JFrame("ScrollPane GUI");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setContentPane(gui);
frame.pack(); // sets the GUI to the exact size needed
frame.setMinimumSize(frame.getSize());
frame.setVisible(true);
}
private JPanel getPanelForScroll() {
JPanel p = new JPanel();
p.add(new JLabel("Panel " + elementCount++));
p.setBorder(new EmptyBorder(10,200,10,200));
p.setBackground(Color.GREEN);
return p;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
new ScrollPaneTestGUI();
}
};
SwingUtilities.invokeLater(r);
}
}

A panel using FlowLayout cannot contain JScrollPanes?

That's what I did at first.
public class MyFrame extends JFrame {
public MyFrame() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setPreferredSize(new Dimension(500 ,300));
setResizable(false);
pack();
setLocationRelativeTo(null);
initComponents();
}
private void initComponents() {
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
for (int i=0; i < 100; i++)
panel.add(new JLabel("some text"));
JScrollPane scrollPane = new JScrollPane(panel,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
// Here I create a JPanel to replace the contentPane of JFrame
JPanel contentPane = new JPanel();
contentPane.add(scrollPane);
setContentPane(contentPane);
}
If instead I replace the last 3 lines with this:
getContentPane().add(scrollPane);
everything is ok. But as I did before, the vertical scrollbar is not showing up. What is causing this? Is setting a JPanel as contentPane wrong?
Update:
If contentPane changes to BorderLayout everything work fine.
// Here I create a JPanel to replace the contentPane of JFrame
JPanel contentPane = new JPanel(new BorderLayout());
contentPane.add(scrollPane);
setContentPane(contentPane);
So the problem is default FlowLayout?
Solved:
The problem is FlowLayout. It wraps around JScrollPane and hides the Toolbars. using
scrollPane.setPreferredSize(new Dimension(500, 400)); // longer space in x-axis
solves it.
Answer:
JSrollPane should not be used inside a Container that uses FlowLayout.
First of all - there is nothing bad in using your own component as content pane. But default content pane is also a JPanel instance so there is actually no point to replace it with your own panel, unless you want to use non-panel content pane or customized panel component.
This is how the default content pane looks like:
/**
* Called by the constructor methods to create the default
* <code>contentPane</code>.
* By default this method creates a new <code>JComponent</code> add sets a
* <code>BorderLayout</code> as its <code>LayoutManager</code>.
* #return the default <code>contentPane</code>
*/
protected Container createContentPane() {
JComponent c = new JPanel();
c.setName(this.getName()+".contentPane");
c.setLayout(new BorderLayout() {
/* This BorderLayout subclass maps a null constraint to CENTER.
* Although the reference BorderLayout also does this, some VMs
* throw an IllegalArgumentException.
*/
public void addLayoutComponent(Component comp, Object constraints) {
if (constraints == null) {
constraints = BorderLayout.CENTER;
}
super.addLayoutComponent(comp, constraints);
}
});
return c;
}
This method is taken from JRootPane. It is basically a simple JPanel with a but customized layout manager as you can see.
Now, you have a few problems in your example.
First is the order of calls - you are sizing frame before adding content into it. Simply change the order and you will see your scrollpane:
public class MyFrame extends JFrame
{
public MyFrame ()
{
super();
// Add components first
initComponents ();
// Setup frame after so it fits its new content
setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
setPreferredSize ( new Dimension ( 500, 300 ) );
setResizable ( false );
pack ();
setLocationRelativeTo ( null );
}
private void initComponents ()
{
JPanel panel = new JPanel ();
panel.setLayout ( new BoxLayout ( panel, BoxLayout.Y_AXIS ) );
for ( int i = 0; i < 100; i++ )
{
panel.add ( new JLabel ( "some text" ) );
}
JScrollPane scrollPane =
new JScrollPane ( panel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER );
// Here I create a JPanel to replace the contentPane of JFrame
JPanel contentPane = new JPanel ();
contentPane.add ( scrollPane );
setContentPane ( contentPane );
}
public static void main ( String[] args )
{
SwingUtilities.invokeLater ( new Runnable ()
{
public void run ()
{
new MyFrame ().setVisible ( true );
}
} );
}
}
It will still look different because your new JPanel () uses FlowLayout by default, instead of BorderLayout used by default content pane component:
Simply set BorderLayout and you will have the result you want to see:
JPanel contentPane = new JPanel ( new BorderLayout () );
Have a look at Rob Camick's WrapLayout, which is an extension of FlowLayout
import java.awt.*;
import javax.swing.*;
public class TestWrapLayout {
public TestWrapLayout () {
ImageIcon icon = new ImageIcon(getClass().getResource("/resources/stackoverflow2.png"));
JPanel panel = new JPanel(new WrapLayout());
for (int i = 1; i <= 250; i++) {
JLabel iconlabel = new JLabel(icon);
iconlabel.setLayout(new BorderLayout());
JLabel textlabel = new JLabel(String.valueOf(i));
textlabel.setHorizontalAlignment(JLabel.CENTER);
textlabel.setForeground(Color.WHITE);
textlabel.setFont(new Font("impact", Font.PLAIN,20));
iconlabel.add(textlabel);
panel.add(iconlabel);
}
JFrame frame = new JFrame();
frame.add(new JScrollPane(panel));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new TestWrapLayout();
}
});
}
}
You must update your frame after adding your panel using pack() function. When you do
getContentPane().add(scrollPane);
the function add does that for you (ref)
Firstly, what was the reason to create the second panel? There
is already the first panel that has BoxLayout as the layout
manager set. Simply setting the scroll pane having the first panel
as parent works as expected.
You either call
setContentPane(scrollPane);
or
add(scrollPane);
Now I am going to explain what caused this unexpected behaviour. This
is a quirk that sometimes happens to those who use nesting technique
when building their layouts. When nesting is used, the layouts may
influence each other.
By choosing another layout -- FlowLayout -- as the underlying base layout,
you caused the first panel to be displayed in its preferred size. Instead
of one panel, you have now two panels, the base panel influences the
panel with labels -- it controls how it is sized. The FlowLayout
shows all its children in preferred size; it does not honour mimimum nor
maximum sizes. So the (first) visible panel is sized to show all its labels;
this is how preferred size is calculated -- just big enough to show all its
children. However, with 100 labels, it is very big; the layout is broken. It is
vertically so big that we cannot practically get to the bottom of the window.
So with our visible panel showing all its labels, what's the purpose of showing
a verticall scrollbar? No need for one, since all labels are "visible" (placed on
the window area), though the desing is broken.
So the problem does not lie with the scrollbars; they work normally. If you
set (in your example) the vertical scrollbar policy to VERTICAL_SCROLLBAR_ALWAYS
you will see the scrollbar there but without a slider, since all labels are "visible"
and there is nothing to be scrolled. (Scrollbars show items that are hidden from the
layout.) The issue lies in the fact that FlowLayout shows its components in the preferred size only.
The following is a fixed code example that works as expected:
package com.zetcode;
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
public class MyFrame extends JFrame {
public MyFrame() {
initComponents();
setTitle("Scrollbar");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setPreferredSize(new Dimension(300, 200));
pack();
setLocationRelativeTo(null);
}
private void initComponents() {
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
for (int i=0; i < 100; i++)
panel.add(new JLabel("some text"));
JScrollPane scrollPane = new JScrollPane(panel,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
setContentPane(scrollPane);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
MyFrame ex = new MyFrame();
ex.setVisible(true);
}
});
}
}

How can I align elements in JPanels / JFrames?

I'm completely new to using the GUI in java, so I'm having a bit of trouble figuring out how to align everything that I need to. I have to panels in my JFrame that I need to align (One to the left, one to the right) and a few buttons in one of the panels that I need to be centered in the panel. Here is my code.
package application;
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.io.*;
import java.nio.*;
import java.util.*;
public class Main extends JPanel
{
public static void main(String[] args)
{
//set the ui to the native OS
try
{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}catch(ClassNotFoundException | InstantiationException | IllegalAccessException
| UnsupportedLookAndFeelException e)
{
}
JFrame frame = new JFrame("Application Name");
Menu menu = new Menu();
JPanel iconPanel = new JPanel();
final JPanel grid = new JPanel(new FlowLayout());
JButton firewallButton = new JButton("Firewall");
JButton networkButton = new JButton("Network");
JButton printerButton = new JButton("Printer");
int iconPanelSizeX;
int iconPanelSizeY;
int gridSizeX;
int gridSizeY;
int gridPosition;
//frame setting
frame.setSize(800, 600);
frame.setMinimumSize(new Dimension(800, 600));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
//add grid and iconPanel JPanels to the frame
frame.add(iconPanel);
iconPanel.add(firewallButton);
iconPanel.add(networkButton);
iconPanel.add(printerButton);
frame.add(grid);
//iconPanel settings
iconPanel.setBorder(BorderFactory.createLoweredSoftBevelBorder());
iconPanel.setBackground(Color.gray);
iconPanel.setLayout(new FlowLayout());
iconPanel.setSize(new Dimension(100, 600));
iconPanel.setVisible(true);
//grid setting
grid.setBackground(Color.red);
grid.setSize(new Dimension(700, 600));
grid.setVisible(true);
//this is for resizing components when the user resizes the window
int counter = 0;
while(counter == 0)
{
firewallButton.setSize(new Dimension(iconPanel.getWidth(), 50));
networkButton.setSize(new Dimension(iconPanel.getWidth(), 50));
printerButton.setSize(new Dimension(iconPanel.getWidth(), 50));
iconPanelSizeX = frame.getWidth() / 10;
iconPanelSizeY = frame.getHeight();
gridSizeX = (frame.getWidth() / 10) * 9;
gridSizeY = frame.getHeight();
iconPanel.setSize(new Dimension(iconPanelSizeX, iconPanelSizeY));
grid.setSize(new Dimension(gridSizeX, gridSizeY));
}
}
}
As you can see, the second JPanel (grid) doesn't line up with the right side of the frame, and the buttons inside iconTray don't center either. I realize these are both probably simple layout fixes, but I have no clue where to start.
For simple splitting of JFrame you can use GridLayout with 1 row and 2 colums.
frame.setLayout(new GridLayout(1,2,3,3)); //3,3 are gaps
frame.add(grid);
frame.add(iconPanel);
For centering components in panels you can use FlowLayout which is by default set on JPanels:
Doing it manualy:
grid.setLayout(new FlowLayout()); //Centered components
grid.setLayout(new FlowLayout(FlowLayout.LEFT,3,3)); //Components aligned to left
grid.setLayout(new FlowLayout(FlowLayout.RIGHT,3,3)); //Components aligned to right
This is how it looks:
Also, few observations:
Never call setXXXSize() methods for your components;
Try to avoid calling setSize(); for JFrame, call pack(); instead;
Call setVisible(true); in the end of code;
All your huge code can be "stripped" to this:
import javax.swing.*;
import java.awt.*;
public class Main extends JPanel
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Application Name");
JPanel iconPanel = new JPanel();
JPanel grid = new JPanel(new FlowLayout());
JButton firewallButton = new JButton("Firewall");
JButton networkButton = new JButton("Network");
JButton printerButton = new JButton("Printer");
frame.add(iconPanel);
iconPanel.add(firewallButton);
iconPanel.add(networkButton);
iconPanel.add(printerButton);
grid.setBackground(Color.GREEN);
frame.setLayout(new GridLayout(1,2,3,3));
frame.add(grid);
frame.add(iconPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
how to align buttons vertically?
This example uses a vertical Box in the WEST area of the frame's default BorderLayout:
import java.awt.*;
import javax.swing.*;
/** #see http://stackoverflow.com/a/14927280/230513 */
public class Main {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
display();
}
});
}
private static void display() throws HeadlessException {
JFrame frame = new JFrame("Application Name");
JButton firewallButton = new JButton("Firewall");
JButton networkButton = new JButton("Network");
JButton printerButton = new JButton("Printer");
//iconPanel settings
Box iconPanel = new Box(BoxLayout.Y_AXIS);
iconPanel.add(firewallButton);
iconPanel.add(networkButton);
iconPanel.add(printerButton);
iconPanel.setBackground(Color.gray);
iconPanel.setVisible(true);
frame.add(iconPanel, BorderLayout.WEST);
//grid setting
JPanel grid = new JPanel() {
#Override
// arbitrary placeholder size
public Dimension getPreferredSize() {
return new Dimension(320, 230);
}
};
grid.setBackground(Color.red);
frame.add(grid, BorderLayout.CENTER);
//frame setting
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
I suggest you take some time going through A Visual Guide to Layout Managers. This will help you become familiar with the layout managers which are available with the Standard API. It takes some experience and hard work to figure out which of these is the right tool to get the exact look you want. Once you become comfortable with what is available from the Standard API, you should also look around for third-party Layout Manager APIs which provide other options.
I have to panels in my JFrame that I need to align (One to the left,
one to the right) and a few buttons in one of the panels that I need
to be centered in the panel. Here is my code.
I realize these are both probably simple layout fixes, but I have no
clue where to start.
Use more complex layout than simple FlowLayout which you actually using. I suggest to you use
GridBagLayout
BoxLayout
Check references here

Java CardLayout JPanel moves up, when second JPanel added

I am new to Java and mostly CardLayout. I want to simply switch "windows" represented by JPanels. I read somewhere that job for CardLayout. But my problem is, when add chatPanel to mainPanel (this is the CardLayout one), it shifts the content of connectPanel several pixels to the top, away from its centered position. Is I skip in my code createChatPanel(), its where it should be.
I have this code:
package App;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import Validators.*;
public class GUI {
private JFrame mainFrame = null;
private JPanel mainPanel = null;
private CardLayout cl = new CardLayout();
public GUI(){
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (UnsupportedLookAndFeelException e) {
}
catch (ClassNotFoundException e) {
}
catch (InstantiationException e) {
}
catch (IllegalAccessException e) {
}
mainFrame = new JFrame("MainChat");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setSize(640,480);
mainFrame.setLocationRelativeTo(null);
mainFrame.setResizable(false);
mainFrame.setLayout(new GridBagLayout());
JMenuBar menuBar = new JMenuBar();
JMenu menuFile = new JMenu("Soubor");
JMenu menuHelp = new JMenu("Nápověda");
menuBar.add(menuFile);
menuBar.add(menuHelp);
menuFile.add(new JMenuItem("Nové Připojení"));
menuFile.add(new JSeparator());
menuFile.add(new JMenuItem("Konec"));
menuHelp.add(new JMenuItem("O programu"));
mainFrame.setJMenuBar(menuBar);
createMainPanel();
createConnectPanel();
createChatPanel();
mainFrame.setVisible(true);
}
public void createMainPanel() {
mainPanel = new JPanel(cl);
mainFrame.add(mainPanel);
}
public void createConnectPanel() {
JPanel connectPanel = new JPanel();
mainPanel.add(connectPanel,"connectPanel");
JTextField ip = new JTextField();
ip.setDocument(new JTextFieldLimit(15));
ip.setColumns(11);
JLabel iplabel = new JLabel("IP:");
connectPanel.add(iplabel);
connectPanel.add(ip);
JButton connect = new JButton("Connect");
connect.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
cl.show(mainPanel,"chatPanel");
}
});
connectPanel.add(connect);
}
public void createChatPanel(){
JPanel chatPanel = new JPanel();
mainPanel.add(chatPanel,"chatPanel");
JTextArea chatbox = new JTextArea();
chatbox.setPreferredSize(new Dimension(200,200));
chatPanel.add(chatbox);
}
}
Please, what I messed up? Thanks.
Since you are adding two JPanels to your main JPanel,
these two panels both need to fit within the main panel.
If one of the inner panels is much larger than the other one,
the main panel will adjust to fit the larger one.
E.g. commenting this line:
chatbox.setPreferredSize(new Dimension(200,200));
would cause your text field to stay put. This is because the
chatbox would not cause the container to resize.
Also note that the main panel is not initially the same size as your
main frame, since you have not set the size of the main panel.
If you would set the size of the connectPanel to the same size
as your main frame, the connectPanel would not
be automatically resized when adding the chatPanel (as a
consequence of the mainPanel being resized)
So what you could do is add the middle line in:
JPanel connectPanel = new JPanel();
connectPanel.setSize(640, 480);
mainPanel.add(connectPanel, "connectPanel");
, which probably would solve your problem.
Although this would work, I definitely recommend using
MIG Layout for
all your GUI designing. It will save you plenty of time if
you take an hour to learn it. It will also save you from
having to set sizes manually (and thereby saving you from
having to rewrite half your GUI code with every design change).
If you want a JPanel centered in another, place your connectPanel in another JPanel that acts as a dumb container, and have this container use GridBagLayout. Then if you add the connectPanel to the container without any GridBagConstraints, it will be added to the default position for GridBagLayout which is centered. You can then add this container JPanel to your mainPanel using the same constant that you would have used for your connectPanel.
I would tend to let the layouts determine the size of components and avoid using setSize and even setPreferredSize, and would definitely call pack() on my JFrame prior to setting it visible. You definitely don't want to set the size or preferredSize of your JTextField, but rather set its columns and rows and place it in a JScrollPane, and then add that JScrollPane to the view.
Edit:
Here's an example that shows placement of something like your connect panel at the top, middle and bottom of a small gui. Just press the "Next" button to see what I mean:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class GUI2 extends JPanel {
public static final String CONNECT_NORTH = "connect north";
public static final String CONNECT_CENTER = "connect center";
private static final String CONNECT_SOUTH = "connect south";
private static final String CHAT_PANEL = "chat panel";
private CardLayout cardlayout = new CardLayout();
public GUI2() {
setLayout(cardlayout);
add(createConnectPanel(BorderLayout.NORTH), CONNECT_NORTH);
add(createConnectPanel(BorderLayout.CENTER), CONNECT_CENTER);
add(createConnectPanel(BorderLayout.SOUTH), CONNECT_SOUTH);
add(createChatPanel(), CHAT_PANEL);
}
public void nextPanel() {
cardlayout.next(this);
}
private JPanel createConnectPanel(String borderlayoutLocation) {
JPanel innerPanel = new JPanel();
innerPanel.add(new JLabel("IP:"));
innerPanel.add(Box.createHorizontalStrut(5));
innerPanel.add(new JTextField(11));
innerPanel.add(Box.createHorizontalStrut(5));
innerPanel.add(new JButton(new AbstractAction("Next") {
#Override
public void actionPerformed(ActionEvent arg0) {
GUI2.this.nextPanel();
}
}));
JPanel innerPanel2 = new JPanel(new GridBagLayout());
innerPanel2.add(innerPanel);
JPanel connectPanel = new JPanel(new BorderLayout());
connectPanel.add(innerPanel2, borderlayoutLocation);
return connectPanel;
}
private JPanel createChatPanel() {
JPanel chatPanel = new JPanel(new BorderLayout(5, 5));
chatPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
chatPanel.add(new JScrollPane(new JTextArea(15, 30)), BorderLayout.CENTER);
chatPanel.add(new JTextField(), BorderLayout.SOUTH);
return chatPanel;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createGui();
}
});
}
private static void createGui() {
JFrame frame = new JFrame("App");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new GUI2());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}

Categories