I am building a toolbar for a program using GridBagLayout, but even using weightx and fill, the components are not the sizes they should be and they are not filling the JPanel.
For instance, when the total size of jidest.x_size is 1920, the total size of the components is 1776
package jide.parts;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import jide.jidest;
#SuppressWarnings("serial")
public class BottomBar extends JPanel implements MouseListener{
JPanel charCountPanel = new JPanel();
JPanel lineCountPanel = new JPanel();
JPanel cursorPositionPanel = new JPanel();
JPanel spacer1 = new JPanel();
JPanel spacer2 = new JPanel();
JPanel spacer3 = new JPanel();
JPanel morespace = new JPanel();
JLabel charCount = new JLabel("charcount");
JLabel lineCount = new JLabel("linecount");
JLabel cursorPosition = new JLabel("TEST:TEST");
public BottomBar(){
this.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
charCountPanel.setToolTipText("Click here for more complete stats");
lineCountPanel.setToolTipText("Click here for more complete stats");
setPreferredSize(new Dimension((int) jidest.x_size,20));
setBackground(Color.red);
cursorPositionPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
cursorPositionPanel.add(cursorPosition);
//cursorPositionPanel.setSize(50,20);
lineCountPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
lineCountPanel.add(lineCount);
//lineCountPanel.setSize(50,20);
charCountPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
charCountPanel.add(charCount);
//charCountPanel.setSize(50,20);
morespace.setSize((int) (jidest.x_size-156),20);
//add(cursorPositionPanel);
spacer1.setBackground(Color.BLACK);
//spacer1.setSize(1,20);
spacer2.setBackground(Color.BLACK);
//spacer2.setSize(1,20);
spacer3.setBackground(Color.BLACK);
//spacer3.setPreferredSize(new Dimension(1,20));
//size is 156, width is 7
gbc.fill=GridBagConstraints.BOTH;
gbc.weighty=1;
gbc.gridx = 1;
gbc.weightx=(1.0)/jidest.x_size;
add(spacer1,gbc);
gbc.gridx=2;
gbc.weightx=(50.0)/jidest.x_size;
add(cursorPositionPanel,gbc);
gbc.gridx=3;
gbc.weightx=(1.0)/jidest.x_size;
add(spacer2,gbc);
gbc.gridx=4;
gbc.weightx=(50.0)/jidest.x_size;
add(lineCountPanel,gbc);
gbc.gridx=5;
gbc.weightx=(1.0)/jidest.x_size;
add(spacer3,gbc);
gbc.gridx=6;
gbc.weightx=(50.0)/jidest.x_size;
add(charCountPanel,gbc);
gbc.gridy = 0;
gbc.gridx=0;
gbc.weightx=(jidest.x_size-153)/jidest.x_size;
add(morespace,gbc);
System.out.println((spacer1.getWidth()+cursorPositionPanel.getWidth()+spacer2.getWidth()+lineCountPanel.getWidth()+spacer3.getWidth()+morespace.getWidth())+" should be " + jidest.x_size);
}
#Override
public void mouseClicked(MouseEvent arg0) {
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent arg0) {
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
}
In future, please post an MCVE. This works to spread the components across the width of the bar.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class BottomBarGUI {
private JComponent ui = null;
BottomBarGUI() {
initUI();
}
public void initUI() {
if (ui != null) {
return;
}
ui = new JPanel(new BorderLayout(4, 4));
ui.setBorder(new EmptyBorder(4, 4, 4, 4));
ui.add(new BottomBar());
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
BottomBarGUI o = new BottomBarGUI();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}
class BottomBar extends JPanel {
JPanel charCountPanel = new JPanel();
JPanel lineCountPanel = new JPanel();
JPanel cursorPositionPanel = new JPanel();
JPanel spacer1 = new JPanel();
JPanel spacer2 = new JPanel();
JPanel spacer3 = new JPanel();
JPanel morespace = new JPanel();
JLabel charCount = new JLabel("charcount");
JLabel lineCount = new JLabel("linecount");
JLabel cursorPosition = new JLabel("TEST:TEST");
public BottomBar() {
this.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
gbc.gridy = 0;
gbc.weightx = .5;
charCountPanel.setToolTipText("Click here for more complete stats");
lineCountPanel.setToolTipText("Click here for more complete stats");
setBackground(Color.red);
cursorPositionPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
cursorPositionPanel.add(cursorPosition);
lineCountPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
lineCountPanel.add(lineCount);
charCountPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
charCountPanel.add(charCount);
spacer1.setBackground(Color.BLACK);
spacer2.setBackground(Color.BLACK);
spacer3.setBackground(Color.BLACK);
gbc.fill = GridBagConstraints.BOTH;
gbc.weighty = 1;
gbc.gridx = 0;
add(spacer1, gbc);
gbc.gridx = 1;
add(cursorPositionPanel, gbc);
gbc.gridx = 2;
add(spacer2, gbc);
gbc.gridx = 3;
add(lineCountPanel, gbc);
gbc.gridx = 4;
add(spacer3, gbc);
gbc.gridx = 5;
add(charCountPanel, gbc);
gbc.gridx = 0;
}
}
Related
I have simple GUI that is supposed to show some informations. I created menu of multiple JTabbedPanes and the tabs are stacking on each other as intended. I am trying to remove borders on left, right and bottom sides of each tab so it doesn't look stacked. I haven't found anything that would solve my problem, is there actually a way to do it?
Thank you for answer in advance.
Here is screen shot:
Here is my code:
import java.awt.*;
import java.awt.event.*;
import java.io.FileNotFoundException;
import javax.swing.*;
public class Convertor implements ItemListener {
public void addComponentToPane(Container pane) throws FileNotFoundException {
//main panel containing all below
JPanel mainPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
//Menu panel
JPanel menuPanel = new JPanel();
menuPanel.setMinimumSize(new Dimension(1200, 30));
menuPanel.setMaximumSize(new Dimension(1200, 30));
menuPanel.setPreferredSize(new Dimension(1200, 30));
menuPanel.setBackground(Color.BLUE);
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 0;
gbc.weighty = 0;
gbc.ipadx = 0;
gbc.ipady = 0;
gbc.insets = new Insets(0, 0, 0, 0);
gbc.gridx = 0;
gbc.gridy = 0;
mainPanel.add(menuPanel, gbc);
//Menu panel buttons
JButton importButton = new JButton("Import");
importButton.setPreferredSize(new Dimension(75, 20));
menuPanel.add(importButton, BorderLayout.EAST);
JButton button2 = new JButton("XXX");
button2.setPreferredSize(new Dimension(75, 20));
menuPanel.add(button2, BorderLayout.EAST);
//PAYER PANEL CONTAINER - containing payer panel
JPanel payerPanelContainer = new JPanel(new BorderLayout());
//payerPanelContainer.setBackground(Color.RED);
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 0;
gbc.weighty = 1;
gbc.ipadx = 0;
gbc.ipady = 0;
gbc.insets = new Insets(0, 0, 0, 0);
gbc.gridx = 0;
gbc.gridy = 1;
mainPanel.add(payerPanelContainer, gbc);
//PAYER PANEL
JPanel payerPanel = new JPanel(new GridBagLayout());
payerPanel.setBackground(Color.YELLOW);
payerPanelContainer.add(payerPanel);
//PAYER PANEL TABBED PANE
JTabbedPane payerTabbedPane = new JTabbedPane();
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1;
gbc.weighty = 1;
gbc.ipadx = 0;
gbc.ipady = 0;
gbc.insets = new Insets(0, 0, 0, 0);
gbc.gridx = 0;
gbc.gridy = 0;
payerPanel.add(payerTabbedPane, gbc);
//Create payer tabs
JPanel payerTab1 = new JPanel(new BorderLayout());
payerTabbedPane.addTab("Payer 1", payerTab1);
JPanel payerTab2 = new JPanel(new BorderLayout());
payerTabbedPane.addTab("Payer 2", payerTab2);
//create MSISDN tabbed pane in each payer tab
JTabbedPane msisdnTabbedPane1 = new JTabbedPane();
payerTab1.add(msisdnTabbedPane1);
//create MSISDN tabs
JPanel generalTabPayer1 = new JPanel(new BorderLayout());
msisdnTabbedPane1.addTab("GENERAL", generalTabPayer1);
JPanel msisdnTab1 = new JPanel(new BorderLayout());
msisdnTabbedPane1.addTab("MSISDN 1", msisdnTab1);
JPanel msisdnTab2 = new JPanel(new BorderLayout());
msisdnTabbedPane1.addTab("MSISDN 2", msisdnTab2);
JPanel msisdnTab3 = new JPanel(new BorderLayout());
msisdnTabbedPane1.addTab("MSISDN 2", msisdnTab3);
//create MSISDN options tabbed pane
JTabbedPane msisdnOptionsTabbedPane1 = new JTabbedPane();
msisdnTab1.add(msisdnOptionsTabbedPane1);
//create MSISDN options tabs
JPanel msisdnOptionsTab1 = new JPanel(new BorderLayout());
msisdnOptionsTabbedPane1.addTab("Option 1", msisdnOptionsTab1);
JPanel msisdnOptionsTab2 = new JPanel(new BorderLayout());
msisdnOptionsTabbedPane1.addTab("Option 2", msisdnOptionsTab2);
//add main panel to window
pane.add(mainPanel);
}
private static void createAndShowGUI() throws FileNotFoundException {
//Create and set up the window.
JFrame frame = new JFrame("CSV Reader");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
Convertor demo = new Convertor();
demo.addComponentToPane(frame.getContentPane());
//Display the window.
frame.pack();
frame.setSize(1206, 800);
frame.setMinimumSize(new Dimension(1206, 800));
frame.setMaximumSize(new Dimension(1206, 800));
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
createAndShowGUI();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
#Override
public void itemStateChanged(ItemEvent arg0) {
// TODO Auto-generated method stub
}
}
It's possible, but it's hard. The only way to do it is to provide your own UI for the tabbed pane. Here is the example, which is not completly satisfied your requirements, but it can show the way, which you must go (sorry, but I cann't provide a complete solution, because it could be time expansive).
import java.awt.Graphics;
import java.awt.Insets;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import javax.swing.plaf.metal.MetalLookAndFeel;
import javax.swing.plaf.metal.MetalTabbedPaneUI;
public class BorderlessTabsExample implements Runnable {
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(MetalLookAndFeel.class.getName());
} catch (Exception e) {
// Nothing
}
SwingUtilities.invokeLater(new BorderlessTabsExample());
}
#Override
public void run() {
JTabbedPane tabber = new JTabbedPane();
tabber.addTab("First", new JLabel("First"));
tabber.addTab("Second", new JLabel("Second"));
tabber.addTab("Third", new JLabel("Third"));
// set the UI which will paint your tabs
tabber.setUI(new MetalBorderlessTabbedPaneUI());
JFrame frm = new JFrame("Tabber test");
frm.add(tabber);
frm.setSize(500, 400);
frm.setLocationRelativeTo(null);
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.setVisible(true);
}
private static class MetalBorderlessTabbedPaneUI extends MetalTabbedPaneUI {
#Override
protected void installDefaults() {
super.installDefaults();
if (contentBorderInsets != null) {
contentBorderInsets = new Insets(contentBorderInsets.top, 0, 0, 0);
}
}
#Override
protected void paintContentBorderRightEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) {
// Do nothing
}
#Override
protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) {
// Do nothing
}
#Override
protected void paintContentBorderLeftEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) {
// Do nothing
}
}
}
public class InputURL {
public InputURL() {
input();
}
private static JFrame mainFrame = Launcher.returnFrame();
private static JPanel mainPanel;
private void input(){
//Defining a Panel on which everything will be set
mainPanel = new JPanel();
mainPanel.setLayout(new GridBagLayout());
//To put the GridBagLayout Constraints
GridBagConstraints c = new GridBagConstraints();
//Set Panel Size
mainPanel.setSize(Constants.windowWidth,Constants.windowHeight);
//Setting the Input Box
JTextField inputURL = new JTextField();
c.fill = GridBagConstraints.CENTER;
c.ipady = 50;
c.weightx = 0.0;
c.gridwidth = 3;
c.gridx = 0;
c.gridy = 1;
mainPanel.add(inputURL, c);
//Adding the start button
JButton submitURL = new JButton(Constants.SUBMIT_URL_BUTTON);
submitURL.addActionListener(new ActionListener() {
//The action performed by the start button
public void actionPerformed(ActionEvent e)
{
//Execute when button is pressed
}
});
//The placement of the button
c.fill = GridBagConstraints.VERTICAL;
c.ipady = 50;
c.weightx = 0.0;
c.gridwidth = 3;
c.gridx = 0;
c.gridy = 2;
mainPanel.add(submitURL, c);
//Adding the components on Panel to Frame
mainFrame.add(mainPanel);
}
}
The ouput and expected output can be viewed here. Need help regarding the Output. E.G.:
I've tried using GridBagConstraints and for some reason I cannot play much with the UI.
A lot will come down to you final needs, for example, this just makes use of some of the basic properties of GridBagConstraints
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestLayout {
public static void main(String[] args) {
new TestLayout();
}
public TestLayout() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextField inputURL;
private JButton submitURL ;
public TestPane() {
inputURL = new JTextField(20);
submitURL = new JButton("Submit the URL");
submitURL.setMargin(new Insets(10, 10, 10, 10));
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets = new Insets(10, 10, 10, 10);
add(new JLabel("Header"), gbc);
gbc.gridy++;
gbc.insets = new Insets(0, 10, 20, 10);
add(inputURL, gbc);
gbc.gridy++;
gbc.insets = new Insets(0, 0, 0, 0);
gbc.weighty = 1.0;
add(submitURL, gbc);
}
}
}
A more complex solution might make use of compound layouts, using a mixture of BorderLayout, GridLayout and GridBagLayout
For example...
public class TestPane extends JPanel {
private JTextField inputURL;
private JButton submitURL ;
public TestPane() {
setLayout(new BorderLayout());
JLabel header = new JLabel("Header");
header.setHorizontalAlignment(JLabel.CENTER);
header.setBorder(new EmptyBorder(10, 10, 10, 10));
add(header, BorderLayout.NORTH);
inputURL = new JTextField(20);
submitURL = new JButton("Submit the URL");
submitURL.setMargin(new Insets(10, 10, 10, 10));
JPanel content = new JPanel(new GridLayout(2, 1));
JPanel field = new JPanel(new GridBagLayout());
field.add(inputURL);
content.add(field);
JPanel actions = new JPanel(new GridBagLayout());
actions.add(submitURL);
content.add(actions);
add(content);
}
}
While it might sound stupid, spend more time focusing on the actual workflow of the user, this will lead you to the best layout decisions, rather then focus on the physical layout itself
I've found myself writing up quite a few programs recently which all need to display some collection of data. So far the best looking approach I've thought of is make small JPanels which contain data on each item in the collection and put them all in a big JPanel which I then put in a JScrollPane. It works and looks just as intended but there's one issue: I can't seem to get the smaller JPanels to start at the top of the bigger JPanel.
The problem is only apparent when I've got a small number of small JPanels (green) added into the bigger JPanel (red).
Described below is the method I used to produce the above and I'd like to know if there's a better way I could do it (where the list starts at the top like it should):
I created a class which extends JPanel and in it add all data I want to display. We'll call it "SmallPanel.java". I don't set the size of it (that comes later).
In my main window's class (which extends JFrame):
private JScrollPane scrollPane;
private JPanel panel;
...
scrollPane = new JScrollPane();
getContentPane().add(scrollPane);
panel = new JPanel();
panel.setLayout(new GridBagLayout());
scrollPane.setViewportView(panel);
...
private void addPanel()
{
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = panel.getComponentCount(); //The new JPanel's place in the list
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.anchor = GridBagConstraints.PAGE_START; //I thought this would do it
gbc.ipady = 130; //Set the panel's height, the width will get set to that of the container JPanel (which is what I want since I'd like my JFrames to be resizable)
gbc.insets = new Insets(2, 0, 2, 0); //Separation between JPanels in the list
gbc.weightx = 1.0;
SmallPanel smallPanel = new SmallPanel();
panel.add(smallPanel, gbc);
panel.revalidate();
panel.invalidate();
panel.repaint(); //Better safe than peeved
}
Call the addPanel() method every time I want to add a panel.
EDIT
Final solution (based on MadProgrammer's answer below):
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.border.BevelBorder;
public class ListPanel extends JPanel
{
private static final long serialVersionUID = 1L;
private JPanel fillerPanel;
private ArrayList<JPanel> panels;
public ListPanel(List<JPanel> panels, int height)
{
this(panels, height, new Insets(2, 0, 2, 0));
}
public ListPanel(List<JPanel> panels, int height, Insets insets)
{
this();
for (JPanel panel : panels)
addPanel(panel, height, insets);
}
public ListPanel()
{
super();
this.fillerPanel = new JPanel();
this.fillerPanel.setMinimumSize(new Dimension(0, 0));
this.panels = new ArrayList<JPanel>();
setLayout(new GridBagLayout());
}
public void addPanel(JPanel p, int height)
{
addPanel(p, height, new Insets(2, 0, 2, 0));
}
public void addPanel(JPanel p, int height, Insets insets)
{
super.remove(fillerPanel);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = getComponentCount();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.anchor = GridBagConstraints.PAGE_START;
gbc.ipady = height;
gbc.insets = insets;
gbc.weightx = 1.0;
panels.add(p);
add(p, gbc);
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = getComponentCount();
gbc.fill = GridBagConstraints.VERTICAL;
gbc.weighty = 1.0;
add(fillerPanel, gbc);
revalidate();
invalidate();
repaint();
}
public void removePanel(JPanel p)
{
removePanel(panels.indexOf(p));
}
public void removePanel(int i)
{
super.remove(i);
panels.remove(i);
revalidate();
invalidate();
repaint();
}
public ArrayList<JPanel> getPanels()
{
return this.panels;
}
public static void main(String[] args)
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setMinimumSize(new Dimension(500, 500));
f.setLocationRelativeTo(null);
f.getContentPane().setLayout(new BorderLayout());
final ListPanel listPanel = new ListPanel();
for (int i = 1; i <= 10; i++)
listPanel.addPanel(getRandomJPanel(), new Random().nextInt(50) + 50);
JButton btnAdd = new JButton("Add");
btnAdd.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent paramActionEvent)
{
listPanel.addPanel(getRandomJPanel(), new Random().nextInt(50) + 50);
}
});
JButton btnRemove = new JButton("Remove");
btnRemove.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent paramActionEvent)
{
listPanel.removePanel(0);
}
});
f.getContentPane().add(btnRemove, BorderLayout.NORTH);
f.getContentPane().add(btnAdd, BorderLayout.SOUTH);
JScrollPane scrollPane = new JScrollPane();
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
scrollPane.setViewportView(listPanel);
f.getContentPane().add(scrollPane, BorderLayout.CENTER);
f.setVisible(true);
}
public static JPanel getRandomJPanel()
{
JPanel panel = new JPanel();
panel.setBorder(new BevelBorder(BevelBorder.LOWERED, null, null, null, null));
panel.add(new JLabel("This is a randomly sized JPanel"));
panel.setBackground(new Color(new Random().nextFloat(), new Random().nextFloat(), new Random().nextFloat()));
return panel;
}
}
The best solution I've found is to use VerticalLayout from the SwingLabs SwingX (which can be downloaded from here) libraries.
You "could" use a GridBagLayout with an invisible component positioned at the end, whose weighty property is set to 1, but this is a lot more additional work to manage, as you need to keep updating the x/y positions of all the components to keep it in place...
Updated with GridBagLayout example
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class VerticalLayoutExample {
public static void main(String[] args) {
new VerticalLayoutExample();
}
public VerticalLayoutExample() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
final TestPane pane = new TestPane();
JButton add = new JButton("Add");
add.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
pane.addAnotherPane();
}
});
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new JScrollPane(pane));
frame.add(add, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JPanel filler;
private int y = 0;
public TestPane() {
setBackground(Color.RED);
setLayout(new GridBagLayout());
filler = new JPanel();
filler.setOpaque(false);
GridBagConstraints gbc = new GridBagConstraints();
gbc.weighty = 1;
gbc.gridy = 0;
add(filler, gbc);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 400);
}
public void addAnotherPane() {
JPanel panel = new JPanel(new GridBagLayout());
panel.add(new JLabel("Hello"));
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridy = y++;
gbc.weightx = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.insets = new Insets(4, 4, 4, 4);
add(panel, gbc);
GridBagLayout gbl = ((GridBagLayout)getLayout());
gbc = gbl.getConstraints(filler);
gbc.gridy = y++;
gbl.setConstraints(filler, gbc);
revalidate();
repaint();
}
}
}
This is just a concept. As camickr has pointed out, so long as you know the last component, you can adjust the GridBagConstraints of the component so that the last component which is in the list has the weighty of 1 instead...
As you can, you can override some of the things GridBagLayout does, for example, instead of using the preferred size of the panel, I've asked GridBagLayout to make it fill the HORIZONTAL width of the parent container...
You can use a vertical BoxLayout.
Just make sure the maximum size of the panel is equal to the preferred size so the panel doesn't grow.
Edit:
Since your class already has a custom panel all you need to do is override the getMaximumSize() method to return an appropriate value. Something like:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class VerticalLayoutExample2 {
public static void main(String[] args) {
new VerticalLayoutExample2();
}
public VerticalLayoutExample2() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
final TestPane pane = new TestPane();
JButton add = new JButton("Add");
add.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
pane.addAnotherPane();
}
});
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new JScrollPane(pane));
frame.add(add, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JPanel filler;
private int y = 0;
public TestPane() {
setBackground(Color.RED);
setLayout(new GridBagLayout());
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
setBorder( new EmptyBorder(4, 4, 4, 4) );
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 400);
}
public void addAnotherPane() {
SmallPanel panel = new SmallPanel();
panel.setLayout( new GridBagLayout() );
panel.add(new JLabel("Hello"));
add(panel);
add(Box.createVerticalStrut(4));
revalidate();
repaint();
}
}
static class SmallPanel extends JPanel
{
#Override
public Dimension getMaximumSize()
{
Dimension preferred = super.getPreferredSize();
Dimension maximum = super.getMaximumSize();
maximum.height = preferred.height;
return maximum;
}
}
}
I know you mentioned you don't want to use a lib, but you can also look at Relative Layout. It is only a single class. It can easily mimic a BoxLayout but is easier to use because you don't need to override the getMaximumSize() method or add a Box component to the panel to give the vertical spacing.
You would set it as the layout of your panel as follow:
RelativeLayout rl = new RelativeLayout(RelativeLayout.Y_AXIS);
rl.setFill( true ); // fills components horizontally
rl.setGap(4); // vertical gap between panels
yourPanel.setLayout(rl);
yourPanel.add( new SmallPanel(...) );
yourPanel.add( new SmallPanel(...) );
I want to have a JFrame, where on the left and the right there is a border that has the color black and a width of withfOfJFrame/10.
Now, my try at it looks like this:
JFrame f = new JFrame();
f.setSize(800, 600);
f.setLayout(new BorderLayout());
JPanel leftBorder = new JPanel();
JPanel rightBorder = new JPanel();
leftBorder.setBackground(Color.black);
rightBorder.setBackground(Color.black);
leftBorder.setSize(f.getWidth()/10, f.getHeight());
rightBorder.setSize(f.getWidth()/10, f.getHeight());
JPanel center = new JPanel();
center.setBackground(Color.red);
f.add(leftBorder, BorderLayout.WEST);
f.add(center, BorderLayout.CENTER);
f.add(rightBorder, BorderLayout.EAST);
f.setVisible(true);
This adds a black border on the left and the right, but that border has a fixed size and doesn't recalculate when resizing the window. The size isn't even 1/10 of 800 (the beginning width of the JFrame).
What am I doing wrong? Or is there even a better way to do this?
You may achieve the desired result with a GridBagLayout and appropriate weights:
public class Snippet {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel leftBorder = new JPanel();
JPanel rightBorder = new JPanel();
leftBorder.setBackground(Color.black);
rightBorder.setBackground(Color.black);
JPanel center = new JPanel();
center.setBackground(Color.red);
f.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
gbc.weighty = 1.0;
gbc.gridy = 0;
gbc.gridwidth = 1;
gbc.gridheight = 1;
gbc.gridx = 0;
gbc.weightx = 0.1;
f.add(leftBorder, gbc);
gbc.gridx = 1;
gbc.weightx = 0.8;
f.add(center, gbc);
gbc.gridx = 2;
gbc.weightx = 0.1;
f.add(rightBorder, gbc);
f.pack();
f.setVisible(true);
}
});
}
}
A ComponentListener works well for this.
Addendum: The Flank panel needs to revalidate() itself explicitly in response to any size change.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
/** #see http://stackoverflow.com/a/14588506/230513 */
public class Test {
private static final int W = 320;
private static final Center center = new Center();
private static class Center extends JPanel {
public Center() {
setBackground(Color.red);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(W, 3 * W / 4);
}
};
private static class Flank extends JPanel {
private Dimension d = new Dimension(W / 10, 0);
public Flank() {
setBackground(Color.black);
Test.center.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
d = new Dimension(e.getComponent().getWidth() / 10, 0);
revalidate();
}
});
}
#Override
public Dimension getPreferredSize() {
return d;
}
}
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new Flank(), BorderLayout.WEST);
f.add(center, BorderLayout.CENTER);
f.add(new Flank(), BorderLayout.EAST);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Test().display();
}
});
}
}
I'm not exactly new to java (I've been using it for a year now) but this is my first go at swing. I'm trying to make a very simple chat client to learn both socket and swing at once. My question is "What must I do to align my panels correctly?". I've tried a lot of things (Though I don't have it in my code). Usually I work something like this out on my own, but I'm to the point I need to ask for help. Do I need to change the wieghtx, weighty? What I want the client to look like is something like this.
This is what it currently looks like.
Here is my code.
package com.client.core;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Window extends JFrame{
private int screenWidth = 800;
private int screenHeight = 600;
public Window(){
//Initial Setup
super("NAMEHERE - Chat Client Alpha v0.0.1");
setResizable(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(screenWidth,screenHeight);
GridBagConstraints c = new GridBagConstraints();
//Main Panel
JPanel window = new JPanel();
window.setLayout(new GridBagLayout());
window.setBackground(Color.black);
//Panels
JPanel display = new JPanel();
JPanel chat = new JPanel();
chat.setLayout(new GridBagLayout());
JPanel users = new JPanel();
display.setBackground(Color.blue);
c.gridx = 0;
c.gridy = 0;
c.insets= new Insets(5,5,5,5);
window.add(display, c);
chat.setBackground(Color.red);
c.gridx = 0;
c.gridy = 3;
c.gridheight = 2;
c.gridwidth = 1;
c.insets= new Insets(5,5,5,5);
window.add(chat, c);
users.setBackground(Color.green);
c.gridx = 2;
c.gridy = 0;
c.insets= new Insets(5,5,5,5);
window.add(users, c);
//Buttons
//Text fields
JTextArea text = new JTextArea("DEREADFADSFEWFASDFSADFASDF");
c.gridx = 0;
c.gridy = 0;
chat.add(text);
JTextField input = new JTextField("type here to chat", 50);
c.gridx = 0;
c.gridy = 1;
c.insets= new Insets(5,5,5,5);
chat.add(input);
add(window);
}
static class ActLis implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}
}
If you wanted something like this as an output :
You can take help from this code example, though you can remove the last ButtonPanel if you don't need that :
package to.uk.gagandeepbali.swing.messenger.gui;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.JTextField;
public class ChatPanel extends JPanel
{
private JButton backButton;
private JButton exitButton;
private JButton sendButton;
private JTextPane chatPane;
private JTextPane namePane;
private JTextField chatField;
private GridBagConstraints gbc;
private final int GAP = 10;
private final int SMALLGAP = 1;
public ChatPanel()
{
gbc = new GridBagConstraints();
}
protected void createGUI()
{
setOpaque(true);
setBackground(Color.WHITE);
setLayout(new BorderLayout(5, 5));
JPanel centerPanel = new JPanel();
centerPanel.setOpaque(true);
centerPanel.setBackground(Color.WHITE);
centerPanel.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, 0, GAP));
centerPanel.setLayout(new GridBagLayout());
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridwidth = 5;
gbc.weightx = 0.8;
gbc.weighty = 1.0;
gbc.fill = GridBagConstraints.BOTH;
gbc.anchor = GridBagConstraints.FIRST_LINE_START;
chatPane = new JTextPane();
JScrollPane scrollerChat = new JScrollPane();
scrollerChat.setBorder(BorderFactory.createTitledBorder("Chat"));
scrollerChat.setViewportView(chatPane);
centerPanel.add(scrollerChat, gbc);
gbc.gridx = 5;
gbc.gridwidth = 2;
gbc.weightx = 0.2;
namePane = new JTextPane();
JScrollPane scrollerName = new JScrollPane(namePane);
scrollerName.setBorder(BorderFactory.createTitledBorder("Names"));
centerPanel.add(scrollerName, gbc);
gbc.gridx = 0;
gbc.gridy = 5;
gbc.gridwidth = 5;
gbc.weightx = 0.8;
gbc.weighty = 0.1;
gbc.fill = GridBagConstraints.HORIZONTAL;
chatField = new JTextField();
chatField.setOpaque(true);
chatField.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createTitledBorder("")
, BorderFactory.createEmptyBorder(SMALLGAP, SMALLGAP, SMALLGAP, SMALLGAP)));
centerPanel.add(chatField, gbc);
gbc.gridx = 5;
gbc.gridwidth = 2;
gbc.weightx = 0.2;
sendButton = new JButton("Send");
sendButton.setBorder(BorderFactory.createTitledBorder(""));
centerPanel.add(sendButton, gbc);
JPanel bottomPanel = new JPanel();
bottomPanel.setOpaque(true);
bottomPanel.setBackground(Color.WHITE);
bottomPanel.setBorder(
BorderFactory.createTitledBorder(""));
bottomPanel.setLayout(new BorderLayout());
JPanel buttonPanel = new JPanel();
buttonPanel.setOpaque(true);
buttonPanel.setBackground(Color.WHITE);
buttonPanel.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, 0, GAP));
backButton = new JButton("Back");
exitButton = new JButton("Exit");
buttonPanel.add(backButton);
buttonPanel.add(exitButton);
bottomPanel.add(buttonPanel, BorderLayout.CENTER);
add(centerPanel, BorderLayout.CENTER);
add(bottomPanel, BorderLayout.PAGE_END);
}
public JTextPane getChatPane()
{
return chatPane;
}
public JTextPane getNamePane()
{
return namePane;
}
public JTextField getChatField()
{
return chatField;
}
public JButton getExitButton()
{
return exitButton;
}
public JButton getBackButton()
{
return backButton;
}
public JButton getSendButton()
{
return sendButton;
}
}
What you could do, and probably gives the desired result
JPanel somethingHere = ...;
JPanel chat = ...;
JPanel userList = ...;
JPanel leftPanel = new JPanel( new BorderLayout() );
leftPanel.add( somethingHere, BorderLayout.CENTER );
leftPanel.add( chat, BorderLayout.SOUTH );
JPanel total = new JPanel( new BorderLayout() );
total.add( leftPanel, BorderLayout.CENTER );
total.add( userList, BorderLayout.EAST );
Way simpler then messing with GridBagLayout
Here is what I came out with thus far. The red box is where I plan to add a simple 2D avatar interface with LWJGL.
Here is the code for it
package com.client.core;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
public class Window extends JFrame{
private int screenWidth = 800;
private int screenHeight = 600;
public Window(){
//Initial Setup
super("NAMEHERE - Chat Client Alpha v0.0.1");
setResizable(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(screenWidth,screenHeight);
//Main Panels
JPanel window = new JPanel(new BorderLayout());
JPanel center = new JPanel(new BorderLayout());
JPanel right = new JPanel(new BorderLayout());
//Panels
JPanel display = new JPanel( new BorderLayout());
display.setBackground(Color.red);
JPanel chat = new JPanel();
chat.setLayout(new BoxLayout(chat, BoxLayout.Y_AXIS));
chat.setBackground(Color.blue);
JPanel users = new JPanel(new BorderLayout());
users.setBackground(Color.green);
//TextFields
JTextArea chatBox = new JTextArea("Welcome to the chat!", 7,50);
chatBox.setEditable(false);
JTextField chatWrite = new JTextField();
JScrollPane userList = new JScrollPane();
JTextField userSearch = new JTextField(10);
userList.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
users.add(userList);
users.add(userSearch, BorderLayout.NORTH);
chat.add(chatBox);
chat.add(chatWrite);
chat.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
//Menu bar
JMenuBar menu = new JMenuBar();
JMenu file = new JMenu("File");
JMenuItem exit = new JMenuItem("Exit");
JMenuItem ipconnect = new JMenuItem("Connect to IP");
file.add(ipconnect);
file.add(exit);
menu.add(file);
//Main window adding
right.add(users);
center.add(display, BorderLayout.CENTER);
center.add(chat, BorderLayout.SOUTH);
window.add(center, BorderLayout.CENTER);
window.add(right, BorderLayout.EAST);
window.add(menu, BorderLayout.NORTH);
add(window);
//Listeners
chatWrite.addKeyListener(new KeyLis());
ipconnect.addActionListener(new ActLis());
exit.addActionListener(new ActLis());
}
static class KeyLis implements KeyListener{
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ENTER){
System.out.println("Message recieved.");
}
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
}
static class ActLis implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand() == "Exit"){
System.exit(0);
} else if(e.getActionCommand() == "Connect to IP"){
System.out.println("Connecting....");
JFrame frameip = new JFrame();
JPanel panelip = new JPanel();
JButton buttonip = new JButton("Hello");
frameip.add(panelip);
panelip.add(buttonip);
JDialog ippop = new JDialog(frameip, "Enter IP", false);
}
}
}
}
I had to build a similar layout using a GridBagLayout. The code below shows how I achieved it.
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GridBagLayoutTest {
public GridBagLayoutTest() {
JFrame jframe = new JFrame();
jframe.setLayout(new GridBagLayout());
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setSize(800, 600);
jframe.setVisible(true);
// Left
JPanel leftPanel = new JPanel(new GridBagLayout());
leftPanel.setBackground(Color.YELLOW);
GridBagConstraints gridBagConstraints = new GridBagConstraints();
gridBagConstraints.fill = GridBagConstraints.BOTH;
gridBagConstraints.weightx = .7f;
gridBagConstraints.weighty = 1f;
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
jframe.add(leftPanel, gridBagConstraints);
JPanel leftTopPanel = new JPanel(new FlowLayout());
leftTopPanel.setBackground(Color.RED);
GridBagConstraints gridBagConstraints0 = new GridBagConstraints();
gridBagConstraints0.fill = GridBagConstraints.BOTH;
gridBagConstraints0.weightx = 1f;
gridBagConstraints0.weighty = .7f;
gridBagConstraints0.gridx = 0;
gridBagConstraints0.gridy = 0;
leftPanel.add(leftTopPanel, gridBagConstraints0);
JPanel leftMiddlePanel = new JPanel(new FlowLayout());
leftMiddlePanel.setBackground(Color.BLACK);
gridBagConstraints0 = new GridBagConstraints();
gridBagConstraints0.fill = GridBagConstraints.BOTH;
gridBagConstraints0.weightx = 1f;
gridBagConstraints0.weighty = .2f;
gridBagConstraints0.gridx = 0;
gridBagConstraints0.gridy = 1;
leftPanel.add(leftMiddlePanel, gridBagConstraints0);
JPanel leftBottomBottomPanel = new JPanel(new FlowLayout());
leftBottomBottomPanel.setBackground(Color.PINK);
gridBagConstraints0 = new GridBagConstraints();
gridBagConstraints0.fill = GridBagConstraints.BOTH;
gridBagConstraints0.weightx = 1f;
gridBagConstraints0.weighty = .1f;
gridBagConstraints0.gridx = 0;
gridBagConstraints0.gridy = 2;
leftPanel.add(leftBottomBottomPanel, gridBagConstraints0);
// Right
JPanel rightPanel = new JPanel();
rightPanel.setBackground(Color.GREEN);
gridBagConstraints = new GridBagConstraints();
gridBagConstraints.fill = GridBagConstraints.BOTH;
gridBagConstraints.weightx = .3f;
gridBagConstraints.weighty = 1f;
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
jframe.add(rightPanel, gridBagConstraints);
}
public static void main (String args[]) {
new GridBagLayoutTest();
}