I've five lists (enclosed in a jscrollpane) added to a jpanel in a group layout. The problem with the lists is that when a scrollbar appears automatically, the border on the bottom/top disappears (lists 2,3,4). How do I make sure that all lists look the same w.r.t border just like the first/last lists?
I've tried setting viewportborder using setViewPortBroder, but it doesn't change things much. 2,3,4 appear with light border while the rest of the lists have double borders.
EDIT
Adding code sample:
Each list you see is created using this code:
MyJList jList = new MyJList(value);
jList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
jList.setModel(listModel);
jList.setMinimumSize(new Dimension(135, 300));
jList.setMaximumSize(new Dimension(135, 300));
jList.clearSelection();
jList.setSelectionBackground(Color.darkGray);
jList.setSelectionForeground(Color.white);
jList.setBorder(new LineBorder(Color.darkGray, 1));
jList.setFixedCellHeight(30);
jList.setFixedCellWidth(100);
Font font = jList.getFont();
jList.addListSelectionListener(new ListListener());
return jList;
MyList is an extension of JList. It does nothing special, other than storing some domain related metadata. And, then lists are added to the middle panel like this:
private void layoutLists(JLabel[] labels, JList[] lists) {
panel.removeAll();
panel.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.NONE;
JScrollPane[] jScrollPanes = new JScrollPane[lists.length];
for (int index = 0; index < lists.length; index++) {
jScrollPanes[index] = new JScrollPane(lists[index]);
jScrollPanes[index].setBorder(BorderFactory.createEmptyBorder());
jScrollPanes[index].setMinimumSize(new Dimension(135, 300));
jScrollPanes[index].setMaximumSize(new Dimension(135, 300));
jScrollPanes[index].setPreferredSize(new Dimension(135, 300));
}
for (int index = 0; index < labels.length; index++) {
gbc.gridx = index;
gbc.gridy = 0;
gbc.insets = new Insets(8, 8, 8, 8);
panel.add(labels[index], gbc);
gbc.gridy = 1;
if (index == labels.length - 1) {
gbc.insets = new Insets(8, 8, 8, 13);
}
panel.add(jScrollPanes[index], gbc);
}}
The explanation of the top/bottom part of the inner (JList) border not being visible is that ... they are not visible if the vertical scrollBar appears (the list is scrolled off)
If you insist, either:
switch the borders - empty on the list itself and lineBorder on the scrollPane or
set the viewportBorderProperty of the scrollPane to the lineBorder
Beware: it's not recommended to fiddle with the default LAF settings - where-to or not the components have a border should be left to the ui to guarantee consistent visuals across your application. Nor does it look exactly good to have the left border line beside (either outside or inside) the scrollPane's vertical scrollbar.
Edit
Just noticed that you already tried the second option (and are not satisfied with the result :-) But then: where do you want the vertical border line if the scrollBar is visible? Anyway, back to the beware: the outcome is highly LAF dependent ...
Related
So I have a JPanel that is split into 2 other separate JPanels (although this is mostly irrelevant). On the left side I have a GridBagLayout that I have organized to have a JLabel at the top, and a JTextArea below it, however the JTextArea isn't directly beneath the JLabel. Instead there is this empty space and I can't figure out why it's there or how to fix it. I'm fairly new to Java in general and GridBagLayout so I could be missing something, but I've tried several things to get it to work. I have the code for this below along with a visual representation of what it's doing. Any help is appreciated.
CODE
//LEFT SIDE
GridBagConstraints leftGBC = new GridBagConstraints();
JPanel leftSide = new JPanel(new GridBagLayout());
leftSide.setBorder(new EmptyBorder(inset, inset, inset, inset));
Font titleFont = bb5.comfortaa.deriveFont(Font.PLAIN, 16f);
leftGBC.gridx = 0;
leftGBC.gridy = 0;
leftGBC.weightx = 1;
leftGBC.weighty = 1;
leftGBC.anchor = GridBagConstraints.NORTH;
JLabel leftTitle = new JLabel("Objective");
leftTitle.setFont(titleFont);
leftTitle.setBorder(BorderFactory.createMatteBorder(0, 0, 2, 0, Color.BLACK));
leftGBC.fill = GridBagConstraints.HORIZONTAL;
leftSide.add(leftTitle, leftGBC);
leftGBC.gridy = 1;
leftGBC.anchor = GridBagConstraints.NORTH;
JTextArea objectiveArea = new JTextArea(objectiveText);
objectiveArea.setBackground(leftTitle.getBackground());
objectiveArea.setEditable(false);
objectiveArea.setFocusable(false);
objectiveArea.setFont(bb5.samsung1.deriveFont(16f));
objectiveArea.setLineWrap(true);
objectiveArea.setWrapStyleWord(true);
leftSide.add(objectiveArea, leftGBC);
VISUAL
leftGBC.weightx = 1;
leftGBC.weighty = 1;
Read the section from the Swing tutorial How to use GridBagLayout. The tutorial explains how the weightx/weighty constraints work. Those values indicate how to allocate "extra space" to each cell. So it would appear that both the label and text area getting extra space. I would guess you want 0 for the label.
If this doesn't help (and in the future when you ask a question), post a proper SSCCE that demonstrates the problem.
I'm really struggling with creating a complicated layout. Here is a picture of what I want in the end:
(source: fbcdn.net)
I've attempted to divide and conquer, creating small panels and putting those in other panels. At first I figured a borderlayout for the main container panel which is in the initial JFrame, with a bunch of GridBagLayouts for the details in those panes. When that wasn't working, I figured I would try my hand at an all out GridBagLayout. Right now my goal is to get the top group of character and location panels/cards to be displayed in their correct aspect ratio (about 4:3) and have them resize correctly (maintaining aspect ratio as best as possible) as the window is resized. What I am getting is a super small square panel for each card when the window first comes up. I want them to start in the aspect ratio (4:3) to begin with.
Am I going about this correctly?
Should I stick with all GridBagLayouts?
If not, what combinations of layouts do you see that may work?
Lastly and probably most importantly, how come they do not start out with the correct gridwidth or gridheight?
It would be nice if all the cards maintained a 4:3 or 3:4 aspect ratio when the window is near a 4:3.
public class OverPower {
public static void main(String[] args) {
JFrame table = new JFrame();
table.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
table.setLayout(new BorderLayout());
JPanel contentPane = new OppCharsPanel();
table.setContentPane(contentPane);
table.setLocationByPlatform(true);
table.pack();
table.setLocationRelativeTo(null);
table.setVisible(true);
}
}
public class OppCharsPanel extends JPanel {
public OppCharsPanel() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(20, 15, 20, 15);
gbc.fill = GridBagConstraints.BOTH;
gbc.gridwidth = 4;
gbc.gridheight = 3;
gbc.weightx = 4.0;
gbc.weighty = 3.0;
//back row
gbc.gridx = 4;
gbc.gridy = 0;
JPanel oppHomebase = new JPanel();
oppHomebase.setBackground(Color.RED);
this.add(oppHomebase, gbc);
gbc.gridx = 8;
gbc.gridy = 0;
JPanel oppReserve = new JPanel();
oppReserve.setBackground(Color.RED);
this.add(oppReserve, gbc);
//front row
gbc.gridx = 0;
gbc.gridy = 3;
JPanel oppBattlesite = new JPanel();
oppBattlesite.setBackground(Color.RED);
this.add(oppBattlesite, gbc);
gbc.gridx = 4;
gbc.gridy = 3;
JPanel oppChar1 = new JPanel();
oppChar1.setBackground(Color.RED);
this.add(oppChar1, gbc);
gbc.gridx = 8;
gbc.gridy = 3;
JPanel oppChar2 = new JPanel();
oppChar2.setBackground(Color.RED);
this.add(oppChar2, gbc);
gbc.gridx = 12;
gbc.gridy = 3;
JPanel oppChar3 = new JPanel();
oppChar3.setBackground(Color.RED);
this.add(oppChar3, gbc);
}
}
Start by breaking down each layout section into it's individual requirements and focus on those needs, for example...
Area #1
Okay, so basically, this has three main components (each coloured section is it's own panel), which could be used with a BorderLayout
Area #2
So here, you have another three areas/panels, because of the different requirements for vertical space, I might be tempted to use a GridBagLayout, this would allow you to define more space to the two top components then the bottom one...
Area #3
So, again three main areas. Here I'd be tempted to use a BorderLayout again. For the indivdual containers, I might use a GridBagLayout or Rob Camick's WrapLayout (for laying out the images within each of the three areas)
Scaling
Don't worry about the layout manager trying to maintain the aspect ratio, give enough information to the layout manager so that it make better choices, overriding the getPreferredSize and getMinimumSize methods of the image components and providing appropriate sizing hints. Within these image components, I would make sure that the image is scaled to the proper aspect ratio and rendered correctly
I'm a bit confused, is it possible to have multiple GridBagConstraints?
I have two panels using GridBagLayout, both affected by the same constraints. This gives me an issue when it comes to putting smaller components next to larger ones as illustrated below. The size of the panel on the left, means the cell on that row is very large, centering the panel on the right and it's components. I've tried using separate constraints for each panel but I haven't seen any differences, I think I'm doing something wrong.
How can I achieve two panels positioned next to each other, however have the components of each influenced by separate constraints?
Here's what I currently have:
Created with:
// layout
GridBagConstraints c = new GridBagConstraints();
// components
JPanel supplier = new JPanel(new GridBagLayout());
// grab the suppliers
Suppliers.Supplier[] suppliers = new Suppliers.Supplier[Suppliers.supplier.size()];
for (int i = 0; i < Suppliers.supplier.size(); i++) {
suppliers[i] = Suppliers.supplier.get(i);
}
JPanel resultsPanel = new JPanel();
JScrollPane scrollpane = new JScrollPane(resultsPanel, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollpane.setPreferredSize(new Dimension(120, 300));
// style properties
c.gridx = 0;
c.gridy = 0;
c.insets = new Insets(10, 10, 10, 10);
supplier.add(scrollpane, c);
int position = 0;
for (int i = 0; i < Suppliers.supplier.size(); i++) {
b_supplierSuppliers.add(new JButton(suppliers[i].getName()));
b_supplierSuppliers.get(i).setActionCommand(suppliers[i].getId());
b_supplierSuppliers.get(i).addActionListener(this);
// style properties
c.gridx = 0;
c.gridy = position;
c.insets = new Insets(10, 10, 10, 10);
c.gridwidth = 1;
resultsPanel.add(b_supplierSuppliers.get(i), c);
position++;
}
JPanel resultsPaneltwo = new JPanel(new GridBagLayout());
// style properties
c.gridx = 1;
c.gridy = 0;
supplier.add(resultsPaneltwo, c);
// code label
l_supplierCode = new JLabel("Supplier Code");
// style properties
c.gridx = 1;
c.gridy = 0;
c.insets = new Insets(0, 10, 10, 10);
c.gridwidth = 4;
c.fill = 4;
resultsPaneltwo.add(l_supplierCode, c);
However I'm after:
Any help is much appreciated.
First, to answer your initial question. Yes, you should use different GridBagConstraints objects for each component. It's worth noting however that it is not essential to create new ones for each component, and changes to the constraint after it has been assigned to another won't affect the earlier component's position. So, for the sake of readability and later debugging it is worth declaring multiple constraints but it's not essential.
Also, it looks as though you need to specify a weighty for your constraint on your right cell. By default cells are centered in any spare space. In order to specify where that extra space is placed (vertically for y, and horizontally for x), you need to give the constraint a weight value;
c.weighty = 1;
This should make it so all extra vertical space is allocated to that cell's constraint, and as such push the cell to the top. If you create a second constraint and do the following;
c2.weighty = 1;
The extra space would be spread evenly between those two cell's constraints.I hope this helps. Let me know how you get on.
The official Oracle GridBagLayout guide says the following on the weight attributes;
weightx, weighty
Specifying weights is an art that can have a
significant impact on the appearance of the components a GridBagLayout
controls. Weights are used to determine how to distribute space among
columns (weightx) and among rows (weighty); this is important for
specifying resizing behavior. Unless you specify at least one non-zero
value for weightx or weighty, all the components clump together in the
center of their container. This is because when the weight is 0.0 (the
default), the GridBagLayout puts any extra space between its grid of
cells and the edges of the container.
Generally weights are specified with 0.0 and 1.0 as the extremes: the
numbers in between are used as necessary. Larger numbers indicate that
the component's row or column should get more space. For each column,
the weight is related to the highest weightx specified for a component
within that column, with each multicolumn component's weight being
split somehow between the columns the component is in. Similarly, each
row's weight is related to the highest weighty specified for a
component within that row. Extra space tends to go toward the
rightmost column and bottom row.
I am trying to achieve a layout similar to that of a carousel. It needs to have images added horizontally with a checkbox field in the second row. I have a panel within a jscrollpane and individual images are added to the panel as labels. Please see screen shot.
screenshot
When I scroll the pane , the first row containing the images stays well within the panel..but if you notice the second row of checkboxes , it scrolls out of the panel. Here is the code ...
JLabel lab1=new JLabel();
for (int ii=0; ii<imageFiles.length; ii++) {
GridBagConstraints constraint = new GridBagConstraints();
lab1 = new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);
constraint.gridx = ii;
constraint.gridy =0;
jPanel9.add(lab1,constraint);
}
for (int ii=0; ii<imageFiles.length; ii++) {
GridBagConstraints constraint1 = new GridBagConstraints();
constraint1.anchor = GridBagConstraints.SOUTH;
chkbox = new Checkbox("asdasdada");
constraint1.gridx = ii;
constraint1.gridy =1;
jPanel9.add(chkbox, constraint1);
}
Not sure what is wrong..Any help is much appreciated..Thanks..
The problem is that you are mixing AWT components (heavyweight) with Swing components (lightweight). I have 2 recommendations:
Don't mix heavyweight and lightweight components
Try to use lightweight components as much as possible
So in your code, replace Checkbox by JCheckbox and it should work just fine.
I am working on a larger GUI with Java and I am becoming angry on Layout Managers.
I have a "Settings-Panel" with a variable number of JComponents in it (Labels, Buttons, JSpinners, JSliders,...). I just want the following:
JLabel <-> JComponent
JLabel <-> JComponent
JLabel <-> JComponent
...
My Panel has a size of 500px, so that there is enough space for a lot of components. Unfortunately the GridLayout always stretches the size of the Components to the whole Panel, even if I set a MaximumSize for every component. It looks stupid if there are only two buttons each with a height of 250px.
I tried FlowLayout, but I cannot figure out a way to make new lines properly. I tried BoxLayout.Y_AXIS, but the Components are always centered, and Label and Component are not in the same line.
Does anybody know a good and short way with LayoutManagers to handle this properly?
An alternative to other layouts, might be to put your panel with the GridLayout, inside another panel that is a FlowLayout. That way your spacing will be intact but will not expand across the entire available space.
Don't use GridLayout for something it wasn't meant to do. It sounds to me like GridBagLayout would be a better fit for you, either that or MigLayout (though you'll have to download that first since it's not part of standard Java). Either that or combine layout managers such as BoxLayout for the lines and GridLayout to hold all the rows.
For example, using GridBagLayout:
import java.awt.*;
import javax.swing.*;
public class LayoutEg1 extends JPanel{
private static final int ROWS = 10;
public LayoutEg1() {
setLayout(new GridBagLayout());
for (int i = 0; i < ROWS; i++) {
GridBagConstraints gbc = makeGbc(0, i);
JLabel label = new JLabel("Row Label " + (i + 1));
add(label, gbc);
JPanel panel = new JPanel();
panel.add(new JCheckBox("check box"));
panel.add(new JTextField(10));
panel.add(new JButton("Button"));
panel.setBorder(BorderFactory.createEtchedBorder());
gbc = makeGbc(1, i);
add(panel, gbc);
}
}
private GridBagConstraints makeGbc(int x, int y) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = 1;
gbc.gridheight = 1;
gbc.gridx = x;
gbc.gridy = y;
gbc.weightx = x;
gbc.weighty = 1.0;
gbc.insets = new Insets(5, 5, 5, 5);
gbc.anchor = (x == 0) ? GridBagConstraints.LINE_START : GridBagConstraints.LINE_END;
gbc.fill = GridBagConstraints.HORIZONTAL;
return gbc;
}
private static void createAndShowUI() {
JFrame frame = new JFrame("Layout Eg1");
frame.getContentPane().add(new LayoutEg1());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
For more complex layouts I often used GridBagLayout, which is more complex, but that's the price. Today, I would probably check out MiGLayout.
In my project I managed to use GridLayout and results are very stable, with no flickering and with a perfectly working vertical scrollbar.
First I created a JPanel for the settings; in my case it is a grid with a row for each parameter and two columns: left column is for labels and right column is for components. I believe your case is similar.
JPanel yourSettingsPanel = new JPanel();
yourSettingsPanel.setLayout(new GridLayout(numberOfParams, 2));
I then populate this panel by iterating on my parameters and alternating between adding a JLabel and adding a component.
for (int i = 0; i < numberOfParams; ++i) {
yourSettingsPanel.add(labels[i]);
yourSettingsPanel.add(components[i]);
}
To prevent yourSettingsPanel from extending to the entire container I first wrap it in the north region of a dummy panel, that I called northOnlyPanel.
JPanel northOnlyPanel = new JPanel();
northOnlyPanel.setLayout(new BorderLayout());
northOnlyPanel.add(yourSettingsPanel, BorderLayout.NORTH);
Finally I wrap the northOnlyPanel in a JScrollPane, which should behave nicely pretty much anywhere.
JScrollPane scroll = new JScrollPane(northOnlyPanel,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
Most likely you want to display this JScrollPane extended inside a JFrame; you can add it to a BorderLayout JFrame, in the CENTER region:
window.add(scroll, BorderLayout.CENTER);
In my case I put it on the left column of a GridLayout(1, 2) panel, and I use the right column to display contextual help for each parameter.
JTextArea help = new JTextArea();
help.setLineWrap(true);
help.setWrapStyleWord(true);
help.setEditable(false);
JPanel split = new JPanel();
split.setLayout(new GridLayout(1, 2));
split.add(scroll);
split.add(help);
You need to try one of the following:
GridBagLayout
MigLayout
SpringLayout
They offer many more features and will be easier to get what you are looking for.
I used WrapFlowLayout instead
JPanel yourPanel = new JPanel(new WrapFlowLayout(10, 10);