Another question about which layout to use

Hello everyone

I have a small JFrame that needs to display a fix number of data, like this

|--|

| 4394849943 |

| 3453555555 |

| 3534534354 |

| 3453424435 |

| 4353443453 |

|--|

At the moment, I use a JPanel with GridLayout (5, 3), then fill the grid with 3 JLabels in a row, first JLabel is "xxxxxx", second JLabel is "" (spaces), then third JLabel is data "xxx" again. Then set the JPanel to be the content pane of the JFrame

I can get what I want with the above setup, but not really nice. The problem is the 3 "column"s are even. The middle column leaves a big gap, which is undesirable for my app. Is there a way to create grid layout with uneven column?

||

| 439484 9943 |

| 345355 5555 |

| 353453 4354 |

| 345342 4435 |

| 435344 3453 |

||

Could you guys pls tell me what is the best way to achieve the first frame! Any help is appreciated! Thank you in advance!!

[984 byte] By [BuggyVBa] at [2007-11-27 6:42:26]
# 1

arghh, "|" messed up my post i think

Here is the frame that I want

|-|

| 4394849943 |

| 3453555555 |

| 3534534354 |

| 3453424435 |

| 4353443453 |

|-|

and here is the frame I got now. It got even column and left a big gap in the middle, which is undesirable

|--|

| 4394849943 |

| 3453555555 |

| 3534534354 |

| 3453424435 |

| 4353443453 |

|--|

Thanks in advance

BuggyVBa at 2007-7-12 18:12:29 > top of Java-index,Desktop,Core GUI APIs...
# 2
post your code here
dayanandabva at 2007-7-12 18:12:29 > top of Java-index,Desktop,Core GUI APIs...
# 3

Erh... I don't really need coding help... It's more like a design advice, like what layout I should use... But since you asked, here it is

import javax.swing.*;

import java.awt.*;

import javax.swing.border.*;

import javax.swing.Box;

import javax.swing.BoxLayout;

public class DepthForm

{

private static final int MAX_LINE = Share.MAX_DEPTH_LINE;

private static Dimension pSize = new Dimension(100,90);

private JFrame frame = new JFrame();

private JLabel[] bidLev = new JLabel[MAX_LINE];

private JLabel[] bidVol = new JLabel[MAX_LINE];

private JLabel[] askLev = new JLabel[MAX_LINE];

private JLabel[] askVol = new JLabel[MAX_LINE];

private Border leftBorder;

private Border rightBorder;

private JPanel leftPane = new JPanel();

private JPanel rightPane = new JPanel();

public DepthForm()

{

JPanel mainPane = new JPanel();

leftBorder = BorderFactory.createEtchedBorder(EtchedBorder.RAISED);

rightBorder = BorderFactory.createEtchedBorder(EtchedBorder.RAISED);

leftPane.setLayout(new GridLayout(MAX_LINE,3));

leftPane.setBorder(BorderFactory.createTitledBorder(leftBorder, "Bid", TitledBorder.LEFT, TitledBorder.TOP));

rightPane.setLayout(new GridLayout(MAX_LINE,3));

rightPane.setBorder(BorderFactory.createTitledBorder(rightBorder,"Offer", TitledBorder.LEFT, TitledBorder.TOP));

for (int i = 0; i < MAX_LINE; i++)

{

bidLev[i] = new JLabel("<html><font color=blue></font></html>", JLabel.LEFT);

bidVol[i] = new JLabel("", JLabel.RIGHT);

askLev[i] = new JLabel("<html><font color=red></font></html>", JLabel.LEFT);

askVol[i] = new JLabel("", JLabel.RIGHT);

}

for (int i = 0; i < MAX_LINE; i++)

{

JLabel l = new JLabel(" ");

leftPane.add(bidLev[i]);

leftPane.add(l);

leftPane.add(bidVol[i]);

rightPane.add(askLev[i]);

l = new JLabel(" ");

rightPane.add(l);

rightPane.add(askVol[i]);

}

leftPane.setMinimumSize(pSize);

leftPane.setMaximumSize(pSize);

leftPane.setPreferredSize(pSize);

rightPane.setMinimumSize(pSize);

rightPane.setMaximumSize(pSize);

rightPane.setPreferredSize(pSize);

mainPane.add(leftPane);

mainPane.add(rightPane);

frame.setContentPane(mainPane);

frame.setVisible(false);

frame.pack();

frame.setResizable(false);

frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);

}

public void setBidLevLabel(int i, String s)

{

bidLev[i].setText("<html><font color=blue>" + s + "</font></html>");

}

public void setBidVolLabel(int i, String s)

{

bidVol[i].setText(s);

}

public void setAskLevLabel(int i, String s)

{

askLev[i].setText("<html><font color=red>" + s + "</font></html>");

}

public void setAskVolLabel(int i, String s)

{

askVol[i].setText(s);

}

public void setFrameTitle(String s)

{

frame.setTitle(s);

}

public void showDepth()

{

frame.setVisible(true);

}

public void hideDepth()

{

frame.setVisible(false);

}

}

Also, another design question, if I need to display something similar, but instead of only 5 rows, it can be up to 1500 lines (enclosed in a JScrollPane of course), what should I use? JTextArea is good, but it can't color certain part of text... JEditorPane can color text, but I can't append text at the first line... :(

BuggyVBa at 2007-7-12 18:12:29 > top of Java-index,Desktop,Core GUI APIs...
# 4

The posted code is not compileable.

If you need further help then you need to create a

[url=http://homepage1.nifty.com/algafield/sscce.html]Short, Self Contained, Compilable and Executable, Example

Program[/url] (SSCCE) that demonstrates the incorrect behaviour.

Don't forget to use the [url=http://forum.java.sun.com/help.jspa?sec=formatting]Code Formatting Tags[/url]

so the posted code retains its original formatting.

Aniruddha-Herea at 2007-7-12 18:12:29 > top of Java-index,Desktop,Core GUI APIs...
# 5

Oh well, for the purpose of learning. Please put the code in a file called Test.java

import javax.swing.*;

import java.awt.*;

import javax.swing.border.*;

import javax.swing.Box;

import javax.swing.BoxLayout;

public class Test

{

//private static final int MAX_LINE = Share.MAX_DEPTH_LINE;

private static final int MAX_LINE = 5;

private static Dimension pSize = new Dimension(100,90);

private JFrame frame = new JFrame();

private JLabel[] bidLev = new JLabel[MAX_LINE];

private JLabel[] bidVol = new JLabel[MAX_LINE];

private JLabel[] askLev = new JLabel[MAX_LINE];

private JLabel[] askVol = new JLabel[MAX_LINE];

private Border leftBorder;

private Border rightBorder;

private JPanel leftPane = new JPanel();

private JPanel rightPane = new JPanel();

public Test()

{

JPanel mainPane = new JPanel();

leftBorder = BorderFactory.createEtchedBorder(EtchedBorder.RAISED);

rightBorder = BorderFactory.createEtchedBorder(EtchedBorder.RAISED);

leftPane.setLayout(new GridLayout(MAX_LINE,3));

leftPane.setBorder(BorderFactory.createTitledBorder(leftBorder, "Bid", TitledBorder.LEFT, TitledBorder.TOP));

rightPane.setLayout(new GridLayout(MAX_LINE,3));

rightPane.setBorder(BorderFactory.createTitledBorder(rightBorder,"Offer", TitledBorder.LEFT, TitledBorder.TOP));

for (int i = 0; i < MAX_LINE; i++)

{

bidLev[i] = new JLabel("<html><font color=blue></font></html>", JLabel.LEFT);

bidVol[i] = new JLabel("", JLabel.RIGHT);

askLev[i] = new JLabel("<html><font color=red></font></html>", JLabel.LEFT);

askVol[i] = new JLabel("", JLabel.RIGHT);

}

for (int i = 0; i < MAX_LINE; i++)

{

JLabel l = new JLabel(" ");

leftPane.add(bidLev[i]);

leftPane.add(l);

leftPane.add(bidVol[i]);

rightPane.add(askLev[i]);

l = new JLabel(" ");

rightPane.add(l);

rightPane.add(askVol[i]);

}

leftPane.setMinimumSize(pSize);

leftPane.setMaximumSize(pSize);

leftPane.setPreferredSize(pSize);

rightPane.setMinimumSize(pSize);

rightPane.setMaximumSize(pSize);

rightPane.setPreferredSize(pSize);

mainPane.add(leftPane);

mainPane.add(rightPane);

frame.setContentPane(mainPane);

frame.setVisible(false);

frame.pack();

frame.setResizable(false);

frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);

}

public void setBidLevLabel(int i, String s)

{

bidLev[i].setText("<html><font color=blue>" + s + "</font></html>");

}

public void setBidVolLabel(int i, String s)

{

bidVol[i].setText(s);

}

public void setAskLevLabel(int i, String s)

{

askLev[i].setText("<html><font color=red>" + s + "</font></html>");

}

public void setAskVolLabel(int i, String s)

{

askVol[i].setText(s);

}

public void setFrameTitle(String s)

{

frame.setTitle(s);

}

public void showTest()

{

frame.setVisible(true);

}

public void hideTest()

{

frame.setVisible(false);

}

public static void main(String[] args)

{

Test d = new Test();

d.showTest();

d.setBidLevLabel(0,"111111");

d.setBidLevLabel(1,"222222");

d.setBidLevLabel(2,"333333");

d.setBidLevLabel(3,"444444");

d.setBidLevLabel(4,"55555");

d.setBidVolLabel(0,"1111");

d.setBidVolLabel(1,"2222");

d.setBidVolLabel(2,"3333");

d.setBidVolLabel(3,"4444");

d.setBidVolLabel(4,"5555");

d.setAskLevLabel(0,"111111");

d.setAskLevLabel(1,"222222");

d.setAskLevLabel(2,"333333");

d.setAskLevLabel(3,"444444");

d.setAskLevLabel(4,"55555");

d.setAskVolLabel(0,"1111");

d.setAskVolLabel(1,"2222");

d.setAskVolLabel(2,"3333");

d.setAskVolLabel(3,"4444");

d.setAskVolLabel(4,"5555");

}

}

As you can see, each panel is divided into 3 even columns... And texts in 1st column are missing. If I widen the column widths (by increase the panel size), the middle column will become even bigger. I want the middle column (the gap) to be smaller while the other column widths are unchanged.... Which layout should I use to achieve that?

BuggyVBa at 2007-7-12 18:12:29 > top of Java-index,Desktop,Core GUI APIs...
# 6

First of all you should not be manually setting the preferred size of a component. You general logic should be to create the components and set the text of each component. Add the components to your panels and add the panels to the frame and then pack and show the frame. This way the components will be displayed using their preferred sizes.

So what I would do is change your left and right panels to use a BorderLayout. Then I would create a panel using a GridLayout with a single column for the bid labels and another panel using a GridLayout with a single column for the bid values. Add the labels panel to the West and the values panel to the East. Then to control the "gap" between the two columns you can add an Empty Border to one of the panels.

camickra at 2007-7-12 18:12:29 > top of Java-index,Desktop,Core GUI APIs...
# 7

Yeah... I didn't think of using of panels for each columns... Somehow, I avoid using too many panels... But I guess it wouldn't hurt. Thank you very much camickr !

Could you also advice me on how to do do similar things, but for 1500 line instead of 5... I need to add insert new line of data at the first line as well... I'm not sure what the main component I should use for this (beside the JScrollPane :P)

Your input is greatly appreciate!

Message was edited by:

BuggyVB

BuggyVBa at 2007-7-12 18:12:29 > top of Java-index,Desktop,Core GUI APIs...
# 8
> Could you also advice me on how to do do similar things, but for 1500 line instead of 5... Well, I would probably use a JTable. Its much more efficient that creating thousands of components.
camickra at 2007-7-12 18:12:29 > top of Java-index,Desktop,Core GUI APIs...
# 9

[nobr]Here's my humble invention called TableLayout. Usage in your case is as follows:container.setLayout(new TableLayout(new int[] {3, 2}, 10, 0));

This will define a table with 2 columns with 10 pixels between them. The relative cell widths 3 and 2 will automatically stretch to fill the container's size. (I noticed the columns in your little text art drawing are 6 and 4 characters wide)

Here's the class:package digisoft.custom.swing;

import java.awt.Component;

import java.awt.Container;

import java.awt.Dimension;

import java.awt.Insets;

import java.awt.LayoutManager;

import java.io.Serializable;

import java.util.Arrays;

/**

* A Layout Manager which creates a basic table of components. The widths of the

* cells are specified as a ratio array of <code>int</code>. The relative

* widths of the rendered columns will always follow these ratios.<br>

*

* The preferred widths of the columns will be either the sum of the columns

* with configured widths as pixels, or the configured ratios stretched equally

* in such a way that no single component is narrower than it's own preferred

* width, whichever is larger, added to the sum of the gap widths. When the

* width of the parent container is larger, the cells are simply stretched

* linearly according to the configured ratios.

*

* A special case is when a ratio is specified as zero. In these cases, each

* column specified as zero will get such a preferred width that no single

* component inside that column is narrower than it's own preferred width. These

* columns do stretch, however, when the width of the parent container is larger

* than the preferred width, everything is stretched linearly.

*

* For example, a <code>TableLayout</code> with column widths

* <code>{5, 2}</code> filled with equal components with a width of 100 pixels

* will generate a layout with preferred column widths of 250 and 100 pixels

* (ratio 5:2). Setting this layout to a container with an absolute width of 700

* pixels will force the table columns to 500 and 200 pixels wide.<br>

*

* Another example. A <code>TableLayout</code> with column widths

* <code>{0, 200, 0, 120}</code> filled with different components for each

* column with relative widths of 30, 100, 50 and 100 pixels will generate a

* layout with preferred column widths of 30, 200, 50 and 120 pixels (ratio

* x:200:x:120). Setting this layout to a container with an absolute width of

* 800 pixels will force the table columns to 60, 400, 100 and 240 pixels wide.

*

* @author Mark Jeronimus

* @since 1.0

* @see LayoutManager

* @see Component#getPreferredSize()

*

* date 2006/11/24

*/

public class TableLayout implements LayoutManager, Serializable

{

private inthgap;

private intvgap;

private int[]columns;

private int[]colWidths;

private intnumColumns;

private int[]rowHeights;

private intlayoutWidthTotal;

private intwidestColumn;

/**

* Create an empty TableLayout. Call <code>setColumns</code> to start

* using it.

*

* @since 1.0

*/

public TableLayout()

{

this(new int[]{0}, 0, 0);

}

/**

* Create a TableLayout with specified column width ratios.

*

* @param columns

*the column width ratios

* @throws IllegalArgumentException

* when the array is null, the array length is zero or one of

* the array elements is negative

* @since 1.0

*/

public TableLayout(int[] columns)

{

this(columns, 0, 0);

}

/**

* Create a TableLayout with specified column width ratios and gap sizes.

*

* @param columns

*the column width ratios

* @param hgap

*the horizontal space between all columns, in pixels

* @param vgap

*the vertical space between all rows, in pixels

* @throws IllegalArgumentException

* when the array is null, the array length is zero or one of

* the array elements is negative

* @since 1.0

*/

public TableLayout(int[] columns, int hgap, int vgap)

{

this.setColumns(columns);

this.setHgap(hgap);

this.setVgap(vgap);

}

/**

* Set or change the column width ratios.

*

* @param columns

*the column width ratios

* @throws IllegalArgumentException

* when the array is null, the array length is zero or one of

* the array elements is negative

* @since 1.0

*/

public void setColumns(int[] columns)

{

if (columns == null || columns.length == 0)

{

throw new IllegalArgumentException("No columns specified");

}

this.columns = columns;

this.numColumns = this.columns.length;

int widestColumnSize = -1;

this.widestColumn = 0;

for (int i = 0; i < this.numColumns; i++)

{

int w = this.columns[i];

if (w < 0)

{

throw new IllegalArgumentException("Negative column width specified at index " + i);

}

this.layoutWidthTotal += w;

if (w > 0 && widestColumnSize < w)

{

widestColumnSize = w;

this.widestColumn = i;

}

}

this.colWidths = new int[this.columns.length];

}

/**

* Returns the column width ratios. The returned array is a direct reference

* to the contained column array, so care must be taken not to alter any

* elements to illegal values (negative values).

*

* @return the column width ratios

* @since 1.0

*/

public int[] getColumnns()

{

return this.columns;

}

/**

* Set or change the horizontal space between all columns, in pixels

*

* @param hgap

*the horizontal space between all columns, in pixels

* @since 1.0

*/

public void setHgap(int hgap)

{

if (hgap < 0)

{

throw new IllegalArgumentException("Negative hgap specified");

}

this.hgap = hgap;

}

/**

* Get the horizontal space between all columns, in pixels

*

* @return the horizontal space between all columns, in pixels

* @since 1.0

*/

public int getHgap()

{

return this.hgap;

}

/**

* Set or change the vertical space between all rows, in pixels

*

* @param vgap

*the vertical space between all rows, in pixels

* @since 1.0

*/

public void setVgap(int vgap)

{

if (vgap < 0)

{

throw new IllegalArgumentException("Negative vgap specified");

}

this.vgap = vgap;

}

/**

* Get the vertical space between all rows, in pixels

*

* @return the vertical space between all rows, in pixels

* @since 1.0

*/

public int getVgap()

{

return this.vgap;

}

/**

* {@inheritDoc}

*/

@Override

public void addLayoutComponent(String name, Component comp)

{

}

/**

* {@inheritDoc}

*/

@Override

public void removeLayoutComponent(Component comp)

{

}

/**

* {@inheritDoc}

*/

@Override

public Dimension preferredLayoutSize(Container parent)

{

synchronized (parent.getTreeLock())

{

Insets insets = parent.getInsets();

int components = parent.getComponentCount();

int numRows = (components + this.numColumns - 1) / this.numColumns;

this.rowHeights = new int[numRows];

Arrays.fill(this.rowHeights, 0);

int narrowestColumn = this.widestColumn;

int narrowestSize = this.columns[this.widestColumn];

int component = 0;

for (int y = 0; y < numRows; y++)

{

for (int x = 0; x < this.numColumns; x++)

{

Component comp = parent.getComponent(component++);

Dimension d = comp.getPreferredSize();

if (this.columns[x] == 0)

{

if (this.colWidths[x] < d.width)

{

this.colWidths[x] = d.width;

}

}

else if (d.width > this.columns[x] * narrowestSize / this.columns[narrowestColumn])

{

if (this.columns[x] > 0)

{

narrowestColumn = x;

}

narrowestSize = d.width;

}

if (this.rowHeights[y] < d.height)

{

this.rowHeights[y] = d.height;

}

if (component == components)

{

break;

}

}

}

int totalWidth = insets.left + insets.right + (this.numColumns - 1) * this.hgap;

for (int x = 0; x < this.numColumns; x++)

{

if (this.columns[x] != 0)

{

this.colWidths[x] = this.columns[x] * narrowestSize / this.columns[narrowestColumn];

}

totalWidth += this.colWidths[x];

}

int totalHeight = insets.top + insets.bottom + (numRows - 1) * this.vgap;

for (int y = 0; y < numRows; y++)

{

totalHeight += this.rowHeights[y];

}

return new Dimension(totalWidth, totalHeight);

}

}

/**

* {@inheritDoc}

*/

@Override

public Dimension minimumLayoutSize(Container parent)

{

synchronized (parent.getTreeLock())

{

Insets insets = parent.getInsets();

int components = parent.getComponentCount();

int numRows = (components + this.numColumns - 1) / this.numColumns;

int[] colWidths = new int[this.numColumns];

System.arraycopy(this.columns, 0, colWidths, 0, this.numColumns);

int[] rowHeights = new int[numRows];

Arrays.fill(rowHeights, 0);

int component = 0;

for (int y = 0; y < numRows; y++)

{

for (int x = 0; x < this.numColumns; x++)

{

Component comp = parent.getComponent(component++);

Dimension d = comp.getMinimumSize();

if (colWidths[x] < d.width)

{

colWidths[x] = d.width;

}

if (rowHeights[y] < d.height)

{

rowHeights[y] = d.height;

}

if (component == components)

{

break;

}

}

}

int totalWidth = insets.left + insets.right + (this.numColumns - 1) * this.hgap;

for (int x = 0; x < this.numColumns; x++)

{

totalWidth += colWidths[x];

}

int totalHeight = insets.top + insets.bottom + (numRows - 1) * this.vgap;

for (int y = 0; y < numRows; y++)

{

totalHeight += rowHeights[y];

}

return new Dimension(totalWidth, totalHeight);

}

}

/**

* {@inheritDoc}

*/

@Override

public void layoutContainer(Container parent)

{

synchronized (parent.getTreeLock())

{

Insets insets = parent.getInsets();

int components = parent.getComponentCount();

int numRows = (components + this.numColumns - 1) / this.numColumns;

Dimension preferredSize = this.preferredLayoutSize(parent);

int width = parent.getWidth() - (insets.left + insets.right + (this.numColumns - 1) * this.hgap);

int height = parent.getHeight() - (insets.top + insets.bottom + (numRows - 1) * this.vgap);

int preferredWidth = preferredSize.width - (insets.left + insets.right + (this.numColumns - 1) * this.hgap);

int preferredHeight = preferredSize.height - (insets.top + insets.bottom + (numRows - 1) * this.vgap);

int[] currentColWidths = new int[this.numColumns];

for (int x = 0; x < this.numColumns; x++)

{

currentColWidths[x] = this.colWidths[x] * width / preferredWidth;

}

int[] currentRowHeights = new int[numRows];

for (int y = 0; y < numRows; y++)

{

currentRowHeights[y] = this.rowHeights[y] * height / preferredHeight;

}

int component = 0;

int yPos = insets.top;

for (int y = 0; y < numRows; y++)

{

int xPos = insets.left;

for (int x = 0; x < this.numColumns; x++)

{

parent.getComponent(component++).setBounds(xPos, yPos, currentColWidths[x], currentRowHeights[y]);

if (component == components)

{

break;

}

xPos += currentColWidths[x] + this.hgap;

}

yPos += currentRowHeights[y] + this.vgap;

}

}

}

/**

* {@inheritDoc}

*/

@Override

public String toString()

{

return super.getClass().getSimpleName() + "[columns=" + this.columns + ", hgap=" + this.hgap + ", vgap=" + this.vgap + "]";

}

}

[/nobr]

Zom-Ba at 2007-7-12 18:12:29 > top of Java-index,Desktop,Core GUI APIs...