GridBagLayout Alignment Issue with Button expanding Column Width - java

I am trying to create an interface with some JLabels icons ( box icons )and an exit button. The thing is that, when I place the button under the labels, they split, according to the button's position like this:
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.VERTICAL; // Adding space before the labels
c.gridy = 0;
c.weighty = 1;
add(new JLabel(" "), c);
for(int i = 0; i < label.length; i++){ // Adding the JLabels
c.fill = GridBagConstraints.NONE;
c.weighty = 0;
c.gridy = 1;
c.gridx++;
add(label[i], c);
}
// Adding the button
c.gridy ++;
c.gridx = 2; // Changing the value of gridx, will move the button to that location and it will split another jlabel.
c.weighty = 0.09;
add(eButton, c);
revalidate();
repaint();

GridBagLayout works a lot like a grid paper, it has rows and columns, components are placed within those cells; you can specify how additional space is distributed and components are aligned within those cells.
Each row and column is sized based on the layout requirements of the other components in that row/column, this means that a component may have more space than it needs, because some other component in the same row/column needs more space to be laid out.
You can also allow a component to span across multiple rows/columns, allowing to occupy more space.
So, basically, what you need to do is tell the button that it can occupy all the columns for it's row (or at least the 5 columns which is occupied by the labels). You will need to then tell the button that it needs to be aligned to the center of it's area.
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 javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
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 {
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.VERTICAL; // Adding space before the labels
c.gridy = 0;
c.weighty = 1;
for (int i = 0; i < 5; i++) { // Adding the JLabels
c.fill = GridBagConstraints.NONE;
c.weighty = 0;
c.gridy = 1;
c.gridx++;
c.insets = new Insets(4, 4, 4, 4);
JLabel label = new JLabel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(20, 20);
}
};
label.setBorder(new LineBorder(Color.DARK_GRAY));
add(label, c);
}
c.gridy++;
c.gridx = 0;
c.gridwidth = GridBagConstraints.REMAINDER;
c.anchor = GridBagConstraints.NORTH;
// c.weighty = 0.09;
add(new JButton("Exit"), c);
}
}
}
Take a closer look at How to Use GridBagLayout for more details

Related

Debugging GridBagLayout - components clumped to center

I'm trying to get the following layout
Label..................NumericField
Label2................NumericField
Label3333..........NumericField
Basically the (.) dots would be empty space. I had tried GridBagLayout with making the label's gridwidth as 5 and the NumericField's gridwidth as 1. I'm posting the code below. But I don't see the desired result and I see all components aligned at the center instead of Labels being at left border and NFs being at right border.
For Labels:
GridBagConstraints localC = new GridBagConstraints();
localC.anchor = GridBagConstraints.FIRST_LINE_START;
//localC.fill = GridBagConstraints.HORIZONTAL;
localC.weightx = 1.0;
localC.weighty = 1.0;
localC.gridx = 0;
localC.gridy = 0;
localC.gridheight = 1;
localC.gridwidth = 5;
localC.insets = new Insets(0, 0, 0, 0);
For NumericFields
localC.anchor = GridBagConstraints.RELATIVE;
localC.weightx = 0.5;
localC.weighty = 0.5;
localC.gridx = 1;
localC.gridy = 0;
localC.gridheight = 1;
localC.gridwidth = 1;
I'm new to JAVA and struggling with layouts generally.
Add a value to the Insets right property, which will add that number of pixels to the right side of the column. You could also use GridBagConstraints#anchor set to GridBagConstraints.WEST, which will force the components in the columns to be positioned on the left hand side of the "column", this ensures that when a component in the column is wider, they won't be laid out in the middle of the resulting space.
gridwidth determines how a given cell will span across multiple columns, but if there are no other components in the resulting columns, they are discard (defaulted to 0), so in your layout, it's meaningless.
See How to Use GridBagLayout more details
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
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 Test {
public static void main(String[] args) {
new Test();
}
public Test() {
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 {
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.WEST;
gbc.insets = new Insets(0, 0, 0, 12);
add(new JLabel("Label"), gbc);
gbc.gridy++;
add(new JLabel("Label2"), gbc);
gbc.gridy++;
add(new JLabel("Label3333"), gbc);
gbc.gridx = 1;
gbc.gridy = 0;
gbc.insets = new Insets(0, 0, 0, 0);
add(new JTextField(10), gbc);
gbc.gridy++;
add(new JTextField(10), gbc);
gbc.gridy++;
add(new JTextField(10), gbc);
}
}
}

GridBagLayout elements behaviour when resizing window

I'm new to Java Swing and was trying to make a simple layout (I thought), but I have a lot of problems reaching the behavior I want. Here's my code :
setSize(800, 600);
setLocationRelativeTo(null);
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
equipementPanel.setPreferredSize(new Dimension(275, 300));
grillePanel.setPreferredSize(new Dimension(300, 600));
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0; c.gridy = 0;
c.anchor = GridBagConstraints.NORTHWEST;
c.gridwidth = 1; c.gridheight = 1;
c.weightx = 0.0; c.weighty = 0.0;
this.add(equipementPanel, c);
c.fill = GridBagConstraints.BOTH;
c.gridx = 0; c.gridy = 1;
c.anchor = GridBagConstraints.SOUTHWEST;
c.gridwidth = 1; c.gridheight = 2;
c.weightx = 0.0; c.weighty = 0.0;
this.add(informationPanel, c);
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 1; c.gridy = 0;
c.anchor = GridBagConstraints.NORTHEAST;
c.weightx = 1.0; c.weighty = 1.0;
this.add(grillePanel, c);
c.fill = GridBagConstraints.BOTH;
c.gridx = 1; c.gridy = 1;
c.anchor = GridBagConstraints.SOUTHEAST;
c.weightx = 1.0; c.weighty = 0.0;
this.add(commandePanel, c);
this.validate();
Screen of my laptop is a good result of what I want.
equipementPanel = green
grillePanel = gray
But on my bigger screen...it is the gray one that should stretch. Red it's okay.
And a total disaster when I size it down .
What I want it to do is
The Gray should not have fixed height and width.
The Yellow should always have the fixed height but not width.
The Red should always have fixed width but not height.
The Green should always have both fixed.
The smallest the window could become would be set to the height of the Green + Yellow one. and width of Green + whatever nice to display.
I know that the weird behavior with the small window is because I go under 300 + 600 of my preferred size...but I need to fix some size somewhere!?!?
If I can reach the same behavior with another layout, I'd be glad to try it. If I change and use some ScrollPanel, does that change anything?
I added a mcve :
MCVE.JAVA
package mcve;
import java.awt.EventQueue;
public class MCVE {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
mcve.gui.MainWindow mainWindow = new mcve.gui.MainWindow();
mainWindow.setVisible(true);
});
}
}
MainWindow.Java
package mcve.gui;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
public class MainWindow extends JFrame
{
public MainWindow()
{
this.setExtendedState(JFrame.MAXIMIZED_BOTH);
this.setLayout(new GridBagLayout());
initComponents();
}
private void initComponents()
{
setSize(800, 600);
setLocationRelativeTo(null);
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
GrillePanel grillePanel = new GrillePanel();
CommandePanel commandePanel = new CommandePanel();
InformationPanel informationPanel = new InformationPanel();
EquipementPanel equipementPanel = new EquipementPanel();
equipementPanel.setPreferredSize(new Dimension(275, 300));
grillePanel.setPreferredSize(new Dimension(300, 600));
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0; c.gridy = 0;
c.anchor = GridBagConstraints.NORTHWEST;
c.gridwidth = 1; c.gridheight = 1;
c.weightx = 0.0; c.weighty = 0.0;
this.add(equipementPanel, c);
c.fill = GridBagConstraints.BOTH;
c.gridx = 0; c.gridy = 1;
c.anchor = GridBagConstraints.SOUTHWEST;
c.gridwidth = 1; c.gridheight = 2;
c.weightx = 0.0; c.weighty = 0.0;
this.add(informationPanel, c);
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 1; c.gridy = 0;
c.anchor = GridBagConstraints.NORTHEAST;
c.weightx = 1.0; c.weighty = 1.0;
this.add(grillePanel, c);
c.fill = GridBagConstraints.BOTH;
c.gridx = 1; c.gridy = 1;
c.anchor = GridBagConstraints.SOUTHEAST;
c.weightx = 1.0; c.weighty = 0.0;
this.add(commandePanel, c);
this.validate();
}
}
the 4 panel
package mcve.gui;
import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
public class InformationPanel extends JPanel
{
public InformationPanel()
{
setBackground(Color.red);
setBorder(BorderFactory.createLineBorder(Color.black));
setVisible(true);
}
}
package mcve.gui;
import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
public class GrillePanel extends JPanel
{
public GrillePanel()
{
setBackground(Color.lightGray);
setBorder(BorderFactory.createLineBorder(Color.black));
setVisible(true);
}
}
package mcve.gui;
import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
public class EquipementPanel extends JPanel
{
public EquipementPanel()
{
setBackground(Color.green);
setBorder(BorderFactory.createLineBorder(Color.black));
setVisible(true);
}
}
package mcve.gui;
import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
public class CommandePanel extends JPanel
{
public CommandePanel()
{
setBackground(Color.yellow);
setBorder(BorderFactory.createLineBorder(Color.black));
setVisible(true);
}
}
There are two basic issues (as I see it)...
One, you are trying to manage a complex layout within a single layout manager, which is pretty hard at the best of times.
Two, you don't seem to understand what the layout manager will do when the available size of the component drops below it's preferred size, which is, in the case of GridBagLayout, revert to it's minimum size...
You can overcome some of this through the use of weights (weightx/weighty), but sometimes, you just need to provide a hard value for the minimum size as well...
Without knowing your exact needs (and you're going to need to make decisions about which components are more important), this is a rough example...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class LayoutTest {
public static void main(String[] args) {
new LayoutTest();
}
public LayoutTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JPanel greenPane = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(275, 300);
}
#Override
public Dimension getMinimumSize() {
return getPreferredSize();
}
#Override
public Color getBackground() {
return Color.GREEN;
}
};
JPanel redPane = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 600);
}
#Override
public Dimension getMinimumSize() {
return getPreferredSize();
}
#Override
public Color getBackground() {
return Color.RED;
}
};
JPanel left = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 1;
gbc.weighty = 0.25;
gbc.fill = GridBagConstraints.BOTH;
left.add(greenPane, gbc);
gbc.gridy++;
gbc.weighty = 0.75;
left.add(redPane, gbc);
JPanel yellowPane = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(600, 50);
}
#Override
public Dimension getMinimumSize() {
return getPreferredSize();
}
#Override
public Color getBackground() {
return Color.YELLOW;
}
};
JPanel grayPane = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 600);
}
#Override
public Dimension getMinimumSize() {
return getPreferredSize();
}
#Override
public Color getBackground() {
return Color.GRAY;
}
};
JPanel center = new JPanel(new GridBagLayout());
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1;
gbc.weighty = 1;
center.add(grayPane, gbc);
gbc.gridy++;
gbc.weighty = 0;
center.add(yellowPane, gbc);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(left, BorderLayout.WEST);
frame.add(center);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
Swing layout managers are quite decent, but unfortunetly they can make a lot of troubles. I think that the only layout managers that are actually usable are BorderLayout, GroupLayout and only in some cases GridBayLayout. In most cases I have found they are useless.
Why dont you try to use 3rd party layout managers? From my experience I can tell thal MigLayout is more than great. It is very flexible and have decent API. You will get desired layout composition in no time. I am using it in all desktop projects.

JTable inside JScrollPane inside JPanel with GridBagLayout, doesn't look as it should

First, hier is the Code:
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JComponent;
import javax.swing.JButton;
import javax.swing.JToolBar;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.TableColumn;
#SuppressWarnings("serial")
public class Spielklasse extends JPanel{
private int iEntries = 1;
public Spielklasse(String strTitle){
setLayout(new GridBagLayout());
//dummy to fill vertical space
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 1000;
c.fill = GridBagConstraints.BOTH;
c.weightx=1;
c.weighty=1;
c.gridwidth = 2;
add(new JLabel(" "),c);
}
public void addEntry(JComponent component){
GridBagConstraints c = new GridBagConstraints();
c.anchor = GridBagConstraints.NORTHWEST;
c.gridx = 1;
c.gridy = iEntries;
c.weightx = 1;
c.insets = new Insets(10, 20, 10, 20);
c.fill = GridBagConstraints.HORIZONTAL;
add(component, c);
iEntries++;
}
public static JPanel addExampleTablePanel() {
String[] columnNames = { "first", "second", "third", "fourth", "fifth", "sixth" };
String[][] strArr = new String[100][columnNames.length];
for (int i = 0; i < strArr.length; i++) {
for (int j = 0; j < strArr[0].length; j++) {
strArr[i][j] = i + " xxxxx " + j;
}
}
JTable table = new JTable(strArr, columnNames) {
#Override
public Dimension getPreferredScrollableViewportSize() {
int headerHeight = getTableHeader().getPreferredSize().height;
int height = headerHeight + (10 * getRowHeight());
int width = getPreferredSize().width;
return new Dimension(width, height);
}
};
JScrollPane scrollPane = new JScrollPane(table, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
TableColumn column = null;
for (int i = 0; i < columnNames.length; i++) {
column = table.getColumnModel().getColumn(i);
column.setPreferredWidth(50);
column.setMaxWidth(50);
column.setMinWidth(50);
}
JToolBar toolBar = new JToolBar();
JButton btn = new JButton("test123");
toolBar.add(btn);
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.gridy = 0;
c.weightx = 1;
c.weighty = 1;
c.gridwidth = 1;
c.anchor = GridBagConstraints.LINE_START;
panel.add(toolBar, c);
c.gridy = 1;
panel.add(scrollPane, c);
return panel;
}
public static void main(String[] args) {
Spielklasse mainPanel = new Spielklasse("test");
mainPanel.addEntry(addExampleTablePanel());
mainPanel.addEntry(addExampleTablePanel());
mainPanel.addEntry(addExampleTablePanel());
JFrame frame = new JFrame();
frame.setSize(300, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new JScrollPane(mainPanel));
frame.setVisible(true);
}
}
The class "Spieklasse" should create a JPanel with multiple entries of different types like tables, textboxes etc.
In this example here, just 3 JTable-containing panels should be added.
This JTable is inside a JSrollPane and should have fixed column widths.
This JScrollPane is inside a JPanel, wich contains a Toolbar above the Table to perform some actions etc.
This JPanel is added to the main panel of the type "Spielklasse".
The main panel is inside another JScrolLPane.
Here are the problem:
- The Table-Panel should have a fixed height wich i can set like i want. In the code example, the size is already fixed, but i dont know why and its the wrong size too :-)
- At the table a horizontal scrollbar should appear, when the size of the frame is smaller than the size of the table (all columns together). When the frame is bigger, everying should be stretched horizontal (works already)
I hope my explanation is good enough and someone can help me :-)
edit: updated with improvement of camickr, vertical size problem solved.
the size is already fixed, but i dont know why and its the wrong size too :-)
The size of the scroll pane is determined from the getPreferredScrollableViewportSize() method of JTable.
When the table is created the following is hardcoded in the JTable:
setPreferredScrollableViewportSize(new Dimension(450, 400));
So if you want to control the default width/height of the scroll pane you need to override the getPreferredScrollableViewportSize() method to return a reasonable value. The height should include the column header as well as the number of rows in the table you wish to display.
Maybe something like:
#Override
public Dimension getPreferredScrollableViewportSize()
{
int headerHeight = table.getTableHeader().getPreferredSize().height;
int height = headerHeight + (10 * getRowHeight());
int width = getPreferredSize().width;
return new Dimension(width, height);
}
Edit:
To use the ScrollablePanel you can change your code to:
//public class Table8 extends JPanel{
public class Table8 extends ScrollablePanel{
private int iEntries = 1;
public Table8(String strTitle){
setLayout(new GridBagLayout());
setScrollableWidth( ScrollablePanel.ScrollableSizeHint.FIT );
Another problem is the GridBagLayout. If there is not enough space to display the component at its preferred size, then the component snaps to is minimum size. This causes problems with the scroll pane so you will also need to add:
scrollPane.setMinimumSize( scrollPane.getPreferredSize() );
Or it may be easier to use another layout manager. Maybe a vertical BoxLayout.

Java Swing - realising a layout with LayeredPane

I have a question regarding making a specific Layout, first I'll show examples then I will add some extra clarification.
Layout when Friends and Messages are closed:
Layout when Friends and Messages are opened:
I intend to make this layout with Java Swing.
My intention is to firstly have the Frame divided in three areas, the top menu row, the main panel and the bottom menu row.
I was thinking of using a BorderLayout for this part.
Then the Friends and Messages buttons should be toggle button's, and on toggle they should show an overlay on top of the mainpanel (or whatever is there), containing a friend list and a message area. I realised I need to use a LayeredPane somehow for this.
Another important part is that the Layout should be viewable in any size, that is the user may resize the application and it will be used on a various amount of resolutions, so I don't really want anything with a fixed width and height.
But I am really lost as how to combine this, so therefore I ask your help.
Hopefully I have explained enough about the situation.
Regards.
this could be about overlay, because JPanel can contains other JComponents
use JLayer (Java7) based on JXLayer(Java6),
use GlassPane with JComponents layed to rellative to....
easiest could be to use JDialog(undecorated) layed to Point (setLocation(int, int)), setVisible() must be wrapped into invokeLater
I will use gridBagLayout.
Here is small example including button which hide your yellow panels:
package Core;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Panel;
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;
public class GridBagLayoutDemo {
public static void addComponentsToPane(Container pane) {
pane.setLayout(new GridBagLayout());
add1row(pane);
addmainRow(pane);
addLastRow(pane);
}
private static void addLastRow(Container pane) {
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 3;
c.anchor = GridBagConstraints.PAGE_END;
JPanel bottonPanel = new JPanel();
bottonPanel.setBackground(Color.BLUE);
bottonPanel.setLayout(new GridBagLayout());
pane.add(bottonPanel, c);
JPanel messagePanel = new JPanel();
messagePanel.setBackground(Color.GRAY);
messagePanel.add(new JLabel("MESSAGES"));
c.fill = GridBagConstraints.VERTICAL;
c.anchor = GridBagConstraints.LINE_END;
c.gridx = 0;
c.gridy = 0;
c.weightx = 1;
bottonPanel.add(messagePanel, c);
}
private static void addmainRow(Container pane) {
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.gridx = 0;
c.gridy = 1;
c.weightx = 1;
c.weighty = 1;
c.anchor = GridBagConstraints.CENTER;
JPanel mainManel = new JPanel();
mainManel.setBackground(Color.GREEN);
mainManel.setLayout(new GridBagLayout());
pane.add(mainManel, c);
final JPanel friendListPanel = new JPanel();
friendListPanel.setBackground(Color.YELLOW);
friendListPanel.add(new JLabel("FRIEND LIST"));
c.fill = GridBagConstraints.NONE;
c.gridx = 0;
c.gridy = 0;
c.weightx = 1;
c.weighty = 1;
c.anchor = GridBagConstraints.FIRST_LINE_END;
mainManel.add(friendListPanel, c);
c.fill = GridBagConstraints.NONE;
c.gridx = 0;
c.gridy = 1;
c.weightx = 0;
c.weighty = 0;
c.anchor = GridBagConstraints.CENTER;
JButton button = new JButton("On/Off");
mainManel.add(button, c);
final JPanel messageAreaPanel = new JPanel();
messageAreaPanel.setBackground(Color.YELLOW);
messageAreaPanel.add(new JLabel("MESSAGE PANEL"));
c.fill = GridBagConstraints.NONE;
c.gridx = 0;
c.gridy = 2;
c.weightx = 1;
c.weighty = 1;
c.anchor = GridBagConstraints.LAST_LINE_END;
mainManel.add(messageAreaPanel, c);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
friendListPanel.setVisible(!friendListPanel.isVisible());
messageAreaPanel.setVisible(!messageAreaPanel.isVisible());
}
});
}
private static void add1row(Container pane) {
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 0;
c.anchor = GridBagConstraints.PAGE_START;
Panel headerPanel = new Panel();
headerPanel.setLayout(new GridBagLayout());
headerPanel.setBackground(Color.BLUE);
pane.add(headerPanel, c);
JPanel quitPanel = new JPanel();
quitPanel.setBackground(Color.GRAY);
quitPanel.add(new JLabel("QUIT"));
c.fill = GridBagConstraints.VERTICAL;
c.anchor = GridBagConstraints.LINE_START;
c.gridx = 0;
c.gridy = 0;
c.weightx = 1;
headerPanel.add(quitPanel, c);
JPanel friendsPanel = new JPanel();
friendsPanel.setBackground(Color.GRAY);
friendsPanel.add(new JLabel("FRIENDS"));
c.fill = GridBagConstraints.VERTICAL;
c.anchor = GridBagConstraints.LINE_END;
c.gridx = 1;
c.gridy = 0;
headerPanel.add(friendsPanel, c);
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("GridBagLayoutDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
addComponentsToPane(frame);
// uncoment to use full screen
// frame.setExtendedState(frame.getExtendedState() | JFrame.MAXIMIZED_BOTH);
frame.setSize(new Dimension(400, 400));
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}

Why is my JPanel inside a JScrollPane not scrolling?

I have a JPanel (yellow) placed in JScrollPane.
When I enter some text in JTextPane, it resizes, but the vertical scrollbar is still not active. yelowPanel.getSize() returns the same value it was before.`(You can see it on redPanel).
So how can I refresh yellowPanel? I want to scroll panel vertically.
I tried to:
panelCreating.revalidate();
panelCreating.invalidate();
panelCreating.repaint();
Works only panelCreating.setPreferredSize(new Dimension(333, 777)); but I don't know what size to set. It depends on content.
There is a small example:
package swingtest;
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 javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
public class SwingTest extends JFrame {
public SwingTest() {
initComponents();
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new SwingTest().setVisible(true);
}
});
}
private JPanel panelCenter, panelCreating;
private JScrollPane scrollPaneCreating, scrollPaneCenter;
private JTextPane textPane1, textPane2;
private JButton button1;
private void initComponents() {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setMinimumSize(new Dimension(300, 300));
panelCreating = new JPanel();
panelCreating.setMinimumSize(new Dimension(160, 200));
panelCreating.setPreferredSize(new Dimension(160, 200));
scrollPaneCreating = new JScrollPane(panelCreating,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
textPane1 = new JTextPane();
textPane1.setText("a\na");
textPane2 = new JTextPane();
textPane2.setText("b\nb");
button1 = new JButton("+++");
panelCenter = new JPanel();
panelCenter.setBackground(Color.blue);
scrollPaneCenter = new JScrollPane(panelCenter);
// ----------------- Left Panel Init -----------------------
panelCreating.setLayout(new GridBagLayout());
panelCreating.setBackground(Color.ORANGE);
panelCreating.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
GridBagConstraints c = new GridBagConstraints();
c.insets = new Insets(0, 0, 4, 4);
c.anchor = GridBagConstraints.FIRST_LINE_START;
c.weightx = c.weighty = 0;
c.gridx = 0;
c.gridy = GridBagConstraints.RELATIVE;
c.gridwidth = GridBagConstraints.REMAINDER;
c.gridheight = 1;
c.fill = GridBagConstraints.BOTH;
panelCreating.add(textPane1, c);
button1.addActionListener(new ActionListener() {
int height = 50;
#Override
public void actionPerformed(ActionEvent e) {
textPane1.setText(textPane1.getText() + "\na");
textPane1.setPreferredSize(new Dimension(150, height));
textPane2.setText(textPane2.getText() + "\nb");
textPane2.setPreferredSize(new Dimension(150, height));
height += 30;
panelCreating.revalidate();
panelCreating.repaint();
scrollPaneCreating.revalidate();
}
});
panelCreating.add(button1, c);
panelCreating.add(textPane2, c);
// -------------------------------------------------------
getContentPane().setLayout(new GridBagLayout());
c = new GridBagConstraints();
c.ipadx = c.ipady = 0;
c.insets = new Insets(0, 0, 0, 0);
c.weighty = 0;
c.gridheight = 1;
c.gridx = 0;
c.gridy = 1;
c.gridwidth = 1;
c.weightx = 0;
c.fill = GridBagConstraints.BOTH;
getContentPane().add(scrollPaneCreating, c);
c.gridx = 1;
c.gridy = 1;
c.fill = GridBagConstraints.BOTH;
c.weightx = 1;
c.weighty = 1;
getContentPane().add(scrollPaneCenter, c);
}
}
Yellow panel also uses GridBagLayout.
Sorry for my English
Instead of setting a preferred size on panelCreating, set it on scrollPaneCreating. And don't set a preferred size on the text components, they will grow as you add new lines of text to them. The idea is to have the panel inside the scroll pane grow as large as it needs to, and just restrict the size of the scroll pane itself.
// [...]
panelCreating = new JPanel();
//panelCreating.setMinimumSize(new Dimension(160, 200));
//panelCreating.setPreferredSize(new Dimension(160, 200));
scrollPaneCreating = new JScrollPane(panelCreating,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPaneCreating.setMinimumSize(new Dimension(160, 200));
scrollPaneCreating.setPreferredSize(new Dimension(160, 200));
// [...]
#Override
public void actionPerformed(ActionEvent e) {
textPane1.setText(textPane1.getText() + "\na");
//textPane1.setPreferredSize(new Dimension(150, height));
textPane2.setText(textPane2.getText() + "\nb");
//textPane2.setPreferredSize(new Dimension(150, height));
//height += 30;
// This isn't necessary either
//panelCreating.revalidate();
//panelCreating.repaint();
//scrollPaneCreating.revalidate();
}
Edited to add: another alternative is to set sizes on the JViewport that is attached to the scroll pane. The viewport is where the content is displayed. You can sort of think of the scroll pane as being composed of the viewport plus scrollbars. If the scroll pane is set to a fixed size, then the viewport size is determined by subtracting the scroll bar size. But if the viewport is set to a fixed size, then the scroll pane size is determined by adding the scroll bar size to the viewport size. Setting a fixed size on the viewport is preferable if you want to precisely control how much content should be displayed on screen, because scroll bar sizes can vary by operating system.
scrollPaneCreating.getViewport().setMinimumSize(new Dimension(160, 200));
scrollPaneCreating.getViewport().setPreferredSize(new Dimension(160, 200));
The default layout of JPanel is FlowLayout. Try GridLayout instead. There's a related example here. For example,
panelCreating = new JPanel(new GridLayout());
scrollPaneCreating = new JScrollPane(panelCreating);
Addendum: Also consider nested layouts. The example below uses BoxLayout for the left panel.
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
/** #see https://stackoverflow.com/questions/9184476 */
public class SwingTest extends JFrame {
private static final int N = 8;
public SwingTest() {
initComponents();
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new SwingTest().setVisible(true);
}
});
}
private JPanel panelCenter, panelCreating;
private JScrollPane scrollPaneCreating, scrollPaneCenter;
private void initComponents() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panelCreating = new JPanel();
scrollPaneCreating = new JScrollPane(panelCreating,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
panelCenter = new JPanel();
panelCenter.setBackground(Color.blue);
scrollPaneCenter = new JScrollPane(panelCenter);
// ----------------- Left Panel Init -----------------------
panelCreating.setLayout(new BoxLayout(panelCreating, BoxLayout.Y_AXIS));
panelCreating.setBackground(Color.orange);
panelCreating.setBorder(BorderFactory.createEmptyBorder(N, N, N, N));
panelCreating.add(createTextPane());
panelCreating.add(Box.createVerticalStrut(N));
panelCreating.add(createTextPane());
panelCreating.add(Box.createVerticalStrut(N));
panelCreating.add(createTextPane());
// -------------------------------------------------------
setLayout(new GridLayout(1, 0));
add(scrollPaneCreating);
add(scrollPaneCenter);
pack();
}
private JTextPane createTextPane() {
JTextPane pane = new JTextPane();
pane.setText(""
+ "Twas brillig and the slithy toves\n"
+ "Did gyre and gimble in the wabe;\n"
+ "All mimsy were the borogoves,\n"
+ "And the mome raths outgrabe.");
pane.setBorder(BorderFactory.createEmptyBorder(N, N, N, N));
return pane;
}
}
I fixed your problem adding 1 line.
panelCreating.setPreferredSize(new Dimension((int) panelCreating.getPreferredSize().getWidth(),
(int)(panelCreating.getPreferredSize().getHeight()+30)));
The line must be inserted after the following lines;
#Override
public void actionPerformed(ActionEvent e) {
textPane1.setText(textPane1.getText() + "\na");
textPane1.setPreferredSize(new Dimension(150, height));
textPane2.setText(textPane2.getText() + "\nb");
textPane2.setPreferredSize(new Dimension(150, height));
height += 30;
Explanation:
The grid bag layout do not set it's pane preferred size when you set the preferred size of the textPanes inside it, but the scrollPane only scrolls based on the preferred size of the pane in it. So you must set the new preferred size of the pane every time you change the size of the components in it, then the scrollPane will know exactly what he must do. That's what i did, a add a line that increased the preferred size of creatingPanel, wich is the one inside the scrollPanel

Categories