Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / GUI / January 2005

Tip: Looking for answers? Try searching our database.

GridBagLayout question

Thread view: 
Jan Danielsson - 08 Jan 2005 01:40 GMT
Hello all,

I have a window that looks something like this:

+-------------------------------------------------+
| Transaction #3298 (id)                          |
+-------------------------------------------------+
| Date:        2004-12-24, 12:00                  |
| Category:    [         |v]                      |
| Shop:        [         |v]                      |
| Amount:      [        ]                         |
| Description: +--------------------------------+ |
|              |                                | |
|              |                                | |
|              |                                | |
|              +--------------------------------+ |
|                [Ok] [Cancel]                    |
+-------------------------------------------------+

The window is split in two. The top part is the entry variables pane.
The bottom is just a small pane containing the buttons.

The top pane uses a GridBagLayout. The idea was to make the JTextArea
(description) use up all available extra space when the window is
resized. Shocklingly enough, that part works great. In fact, everything
about this window works except for one detail: When I call setText() for
the description JTextArea, and set a text which is so long that a
horizontal scrollbar appears, then the JTextField after Amount shrinks
to something like 1 pixel wide, making it impossible to see what it
contains. If I resize the window so that the JTextArea's scroll-control
disappears, then the size of the JTextField becomes normal. If I shrink
the window so the scrollbar appears, then the text field shrinks again.

What am I doing wrong?, and why is it only affecting the "amount" text
field, but not the ComboBox:es?

-[snip]------------------------------------------
public class TransactionEditor extends JDialog implements ActionListener
{
    private JPanel varPane = new JPanel();
    private JPanel buttonPane = new JPanel();

    final private JLabel lblDate = new JLabel("Date");
    private JLabel lblDateText = new JLabel("2004-12-24, 12:00");

    final private JLabel lblCategory = new JLabel("Category");
    private JComboBox cbCategory = new JComboBox();

    final private JLabel lblShop = new JLabel("Shop");
    private JComboBox cbShop = new JComboBox();

    final private JLabel lblAmount = new JLabel("Amount");
    private JTextField tfAmount = new JTextField(8);

    final private JLabel lblDescription = new JLabel("Description");
    private JTextArea taDescription = new JTextArea();
    private JScrollPane sp = new JScrollPane(taDescription);

    final private JButton okButton = new JButton("Ok");
    final private JButton cancelButton = new JButton("Cancel");

    private boolean fDidChange = false;

    final DatabaseManager dbMgr;

    int id;    // entry id
    int category_id;
    int shop_id;
    double amount;
    String description;
    java.util.Date date;

    // ************************************************************************
    // Constructor
    // ************************************************************************
    public TransactionEditor(DatabaseManager dbMgr, int id) {

        this.dbMgr = dbMgr;
        this.id = id;

        // ******************************************************************
        // Set up gridbag layout for entry variables pane
        // ******************************************************************
        GridBagLayout m = new GridBagLayout();
        varPane.setLayout(m);

        // grid bag contrstraints object used to set up constraints
        GridBagConstraints con = new GridBagConstraints();

//        lblDescription.setVerticalTextPosition(JLabel.TOP);

        // Date
        con.insets = new Insets(4, 4, 2, 4);
        con.gridy = 0;
        con.gridx = 0;
        con.anchor = GridBagConstraints.EAST;
        m.setConstraints(lblDate, con);
        varPane.add(lblDate);

        con.insets = new Insets(4, 2, 4, 4);
        con.gridx = 1;
        con.anchor = GridBagConstraints.WEST;
        m.setConstraints(lblDateText, con);
        varPane.add(lblDateText);

        // Category
        con.insets = new Insets(2, 4, 2, 2);
        con.gridy = 1;
        con.gridx = 0;
        con.anchor = GridBagConstraints.EAST;
        m.setConstraints(lblCategory, con);
        varPane.add(lblCategory);

        con.insets = new Insets(2, 2, 2, 4);
        con.gridx = 1;
        con.anchor = GridBagConstraints.WEST;
        m.setConstraints(cbCategory, con);
        varPane.add(cbCategory);

        // "Shop"
        con.insets = new Insets(2, 4, 2, 2);
        con.gridy = 2;
        con.gridx = 0;
        con.anchor = GridBagConstraints.EAST;
        m.setConstraints(lblShop, con);
        varPane.add(lblShop);

        con.insets = new Insets(2, 2, 2, 4);
        con.gridx = 1;
        con.anchor = GridBagConstraints.WEST;
        m.setConstraints(cbShop, con);
        varPane.add(cbShop);

        // amount
        con.insets = new Insets(2, 4, 2, 2);
        con.gridy = 3;
        con.gridx = 0;
        con.anchor = GridBagConstraints.EAST;
        m.setConstraints(lblAmount, con);
        varPane.add(lblAmount);

        con.insets = new Insets(2, 2, 2, 4);
        con.gridx = 1;
        con.weightx = 1;
        con.anchor = GridBagConstraints.WEST;
        m.setConstraints(tfAmount, con);
        varPane.add(tfAmount);

        // description
        con.insets = new Insets(2, 4, 4, 2);
        con.gridy = 4;
        con.gridx = 0;
        con.anchor = GridBagConstraints.EAST;
        m.setConstraints(lblDescription, con);
        varPane.add(lblDescription);

        con.insets = new Insets(2, 2, 4, 4);
        con.weighty = con.weightx = 1;
        con.gridx = 1;
//        con.gridwidth = 2;
//        con.gridheight = 2;
        con.anchor = GridBagConstraints.WEST;
        con.fill = GridBagConstraints.BOTH;
        m.setConstraints(sp, con);
        varPane.add(sp);

        // *********************************************************************
        // Add Ok and Cancel buttons
        // *********************************************************************
        con = new GridBagConstraints();
        con.anchor = GridBagConstraints.WEST;
        con.gridx = 0;
        con.gridy = 0;
        con.fill = GridBagConstraints.NONE;
        m.setConstraints(okButton, con);
        buttonPane.add(okButton);

        con.gridx = 1;
        m.setConstraints(cancelButton, con);
        buttonPane.add(cancelButton);

        con.gridx = 2;
        con.weightx = 1.0;
        con.anchor = GridBagConstraints.EAST;
        con.fill = GridBagConstraints.HORIZONTAL;
        JPanel voidPane = new JPanel();
        m.setConstraints(voidPane, con);
        buttonPane.add(voidPane);

        okButton.addActionListener(this);
        cancelButton.addActionListener(this);

        // *********************************************************************
        // Load data base information into dialog
        // *********************************************************************
        LoadDataThread thrd = new LoadDataThread();
        thrd.start();

        // Intialize mnemonics
        lblCategory.setLabelFor(cbCategory);
        lblCategory.setDisplayedMnemonic('C');

        lblShop.setLabelFor(cbShop);
        lblShop.setDisplayedMnemonic('S');

        lblAmount.setLabelFor(tfAmount);
        lblAmount.setDisplayedMnemonic('A');

        lblDescription.setLabelFor(taDescription);
        lblDescription.setDisplayedMnemonic('D');

        // Set up the dialog's content pane
         Container c = getContentPane();
        c.add(varPane, BorderLayout.CENTER);
        c.add(buttonPane, BorderLayout.SOUTH);

        getRootPane().setDefaultButton(okButton);

        // ******************************************************************
        // Set up window properties
        // ******************************************************************
        setModal(true);

        setTitle("Transaction #" + id);
        setSize(320, 240);

        // Center window
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        Dimension frameSize = getSize();
        int cx = (int)(screenSize.width-frameSize.width)/2;
        int cy = (int)(screenSize.height-frameSize.height)/2;
        setLocation(cx,cy);

        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }
    public void actionPerformed(ActionEvent e) {
        if(e.getSource() == okButton)
        {
            // Transfer variables

        }
        dispose();
    }

    final public boolean didChange() {
        return fDidChange;
    }

    private class ComboBoxEntry
    {
        private int id;
        private String title;

        public ComboBoxEntry(int id, String title) {
            this.id = id;
            this.title = title;
        }
        public int getId() {
            return id;
        }
        public String getTitle() {
            return title;
        }
        public String toString() {
            return title;
        }
    }

    /*
    * Load entry information into dialog controls
    */
    private class LoadDataThread extends Thread {
        final Vector<ComboBoxEntry> list = new Vector<ComboBoxEntry>();

        public void run() {
            try {
                Connection con = dbMgr.connect();
                Statement stmt = con.createStatement();

                // ***************************************************************
                // First get the transaction entry information
                // ***************************************************************
                String Q = "SELECT CATEGORY_ID,SHOP_ID,DATE,AMOUNT,DESCRIPTION " +
                    "FROM TRANSACTIONS WHERE ID=" + id;
                ResultSet rs = stmt.executeQuery(Q);

                if(rs.next())
                {
                    category_id = rs.getInt(1);
                    shop_id = rs.getInt(2);
                    date = Date.valueOf(rs.getString(3));
                    amount = rs.getDouble(4);
                    Clob clob = rs.getClob(5);
                    if(!rs.wasNull())
                    {
                        description = clob.getSubString(1, (int)clob.length());
                    }
                }

                // ***************************************************************
                // Now set what we can..
                // ***************************************************************
                SwingUtilities.invokeAndWait(new Runnable() {
                    public void run() {
                        lblDateText.setText(date.toString());
                        tfAmount.setText(Double.toString(amount));
                        taDescription.setText(description);
                    }
                });

                // ***************************************************************
                // Load categories
                // ***************************************************************
                rs = stmt.executeQuery("SELECT ID,TITLE FROM CATEGORIES " +
                    "ORDER BY TITLE");
                while(rs.next())
                {
                    list.add(new ComboBoxEntry(rs.getInt(1), rs.getString(2)));
                }

                // ***************************************************************
                // Transfer list to ComboBox
                // ***************************************************************
                SwingUtilities.invokeAndWait(new Runnable() {
                    public void run() {
                        for(int i = 0; i < list.size(); i++)
                        {
                            ComboBoxEntry c = list.elementAt(i);
                            cbCategory.addItem(c);
                            if(category_id == c.getId())
                            {
                                cbCategory.setSelectedItem(c);
                            }
                        }
                    }
                });

                // ***************************************************************
                // Load shops
                // ***************************************************************
                list.clear();
                rs = stmt.executeQuery("SELECT ID,TITLE FROM SHOPS " +
                    "ORDER BY TITLE");
                while(rs.next())
                {
                    list.add(new ComboBoxEntry(rs.getInt(1), rs.getString(2)));
                }

                // ***************************************************************
                // Transfer list to ComboBox
                // ***************************************************************
                SwingUtilities.invokeAndWait(new Runnable() {
                    public void run() {
                        for(int i = 0; i < list.size(); i++)
                        {
                            ComboBoxEntry c = list.elementAt(i);
                            cbShop.addItem(c);
                            if(shop_id == c.getId())
                            {
                                cbShop.setSelectedItem(c);
                            }
                        }
                    }
                });

                rs.close();
                stmt.close();
//                con.close();
            }
            catch(Exception e) {
                JdbcException jdbcExc = new JdbcException(e);
                jdbcExc.handle();
            }

        } // run()

    }    // class LoadDataThread

} // class TransactionEditor
-[snip]------------------------------------------

Signature

Kind regards,
Jan Danielsson
Nobody loves a cynic

Andrew Thompson - 08 Jan 2005 05:51 GMT
..
>| Amount:      [        ]                         |
>| Description: +--------------------------------+ |
[quoted text clipped - 4 lines]
>|                [Ok] [Cancel]                    |
> +-------------------------------------------------+

One quick question.  Could the end user go with the text area
spanning the entire width, below the 'Description' label?  I
think that would be better.  

But it should not require a 394 line post, only to include code that
will not compile, and is not easy for others to work with.

A couple of tips on code examples.

(snip)
> public class TransactionEditor extends JDialog implements ActionListener

Include a 'main' and the imports and people can see it instantly..

> {
>     private JPanel varPane = new JPanel();

Please do a global replace on tabs to either '  ' or '   '
before posting.  A lot of news-clients indent them too far,
others ignore them.
...
>                    Clob clob = rs.getClob(5);

A GUI problem does not require file I/O, networking, or D/B access,
so strip all that code from behind your GUI before posting.  If
you require actual data in the layout to display the problem,
hard code it or generate it randomly.

For more tips on preparing examples, see..
<http://www.physci.org/codes/sscce.jsp>

BTW - I would recommend replacing the GBL with a nested layout.

HTH

Signature

Andrew Thompson
http://www.PhySci.org/codes/  Web & IT Help
http://www.PhySci.org/  Open-source software suite
http://www.1point1C.org/  Science & Technology
http://www.LensEscapes.com/  Images that escape the mundane

Jan Danielsson - 08 Jan 2005 14:02 GMT
> ..
>
[quoted text clipped - 10 lines]
> spanning the entire width, below the 'Description' label?  I
> think that would be better.  

That's a good idea; I'll try that. Thanks for the tip.

> But it should not require a 394 line post, only to include code that
> will not compile, and is not easy for others to work with.

I'm aware of that, and the problems with the tabs. Last time I tried to
cut the example down to minimum, but then I got comments that I was
posting too little. This time I was too damn tired (2:40 in the morning)
to fix all the tabs and strip the non-relevant data. I was banking on
the hopes that no one would care this one time. Sorry, won't happen again.

> BTW - I would recommend replacing the GBL with a nested layout.

I don't understand what that means. Could you clarify?

Signature

Kind regards,
Jan Danielsson
Nobody loves a cynic

Andrew Thompson - 08 Jan 2005 21:46 GMT
>> ..
>>
[quoted text clipped - 19 lines]
> cut the example down to minimum, but then I got comments that I was
> posting too little.

Whereas an SSCCE is 'just right'.  It is exactly for comments
like that that I wrote the document.
<http://www.physci.org/codes/sscce.jsp>

An SSCCE is ..
- Short
- Self Contained
- Compilable and
- an Example of the problem.

>> BTW - I would recommend replacing the GBL with a nested layout.
>
> I don't understand what that means. Could you clarify?

If you wanted a column of buttons on the left of a JTextArea, you
might do it by putting the JTextArea in the CENTER of a BorderLayout
and the buttons into a GridLayout in a JPanel that is added to the
BorderLayout.WEST.

The GridLayout is 'nested' inside the WEST area of the BorderLayout.

My original thinking would take 2 BorderLayouts and 2 GridLayouts for the
UI described, with that JTextArea spanning the horizontal space.

Signature

Andrew Thompson
http://www.PhySci.org/codes/  Web & IT Help
http://www.PhySci.org/  Open-source software suite
http://www.1point1C.org/  Science & Technology
http://www.LensEscapes.com/  Images that escape the mundane

Andrew McDonagh - 08 Jan 2005 22:03 GMT
snipped.

>>>BTW - I would recommend replacing the GBL with a nested layout.
>>
[quoted text clipped - 9 lines]
> My original thinking would take 2 BorderLayouts and 2 GridLayouts for the
> UI described, with that JTextArea spanning the horizontal space.

Ignoring your usual annoying habit of telling everyone how they post is
wrong...

I completely agree with you with regards to the GBL.  There are always
easier to understand ways of laying things out.  Your suggestion for
nesting panels in a border layout is classic, and I would hope that as
many people as possible started this way.

I understand the GBL, but it is without a doubt the strangest, easiest
to bugger, Layout Manager in Java.  Sun have even realised this by
creating newer ones that do almost as much but in a simpler way (though
at this exact time I can't remember the sods name).

I also find that by using simpler LMs and nesting components, that it
lends itself to creating a more OO design for the GUI components, rather
than having one large class with a ton of widgets on.

IMHO GUI design wizards should always start up with a message reminding
the developer that the generated code will be procedural and very long.
Andrew McDonagh - 08 Jan 2005 22:09 GMT
> snipped.
>
[quoted text clipped - 31 lines]
> IMHO GUI design wizards should always start up with a message reminding
> the developer that the generated code will be procedural and very long.

here they are...

SpringLayout

http://java.sun.com/docs/books/tutorial/uiswing/layout/spring.html

BoxLayout

http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/BoxLayout.html
Babu Kalakrishnan - 08 Jan 2005 06:15 GMT
> The top pane uses a GridBagLayout. The idea was to make the JTextArea
> (description) use up all available extra space when the window is
[quoted text clipped - 6 lines]
> disappears, then the size of the JTextField becomes normal. If I shrink
> the window so the scrollbar appears, then the text field shrinks again.

This is a quirk of GridBagLayout. If the total space available in the
container is not enough to display _all_ the components in their
preferred sizes, the GridBagLayout will assign every component (whose
constraints spec doesn't specify filling) its _minimum_ size. When you
add a long text line to the JTextArea, its preferred width increases
beyond what can be allocated in the panel (it is only when the allocated
size is less than the preferred size that the scrollbar appears), and
this causes all other components to be displayed at their minimum sizes.

The work around I've used at times is to override the minimum size of
the JTextfields to return the preferred size instead.

> What am I doing wrong?, and why is it only affecting the "amount" text
> field, but not the ComboBox:es?

Because the minimum size of the combobox is probably larger (or the same
as its preferred size)

Try :

>     private JTextField tfAmount = new JTextField(8)
      {
    public Dimension getMinimumSize()
        {
           return getPreferredSize();
        }
      };   

BK
Jan Danielsson - 08 Jan 2005 14:08 GMT
[---]
> This is a quirk of GridBagLayout. If the total space available in the
> container is not enough to display _all_ the components in their
[quoted text clipped - 4 lines]
> size is less than the preferred size that the scrollbar appears), and
> this causes all other components to be displayed at their minimum sizes.

This is very confusing to me.. So the JTextArea *actually* grows in
size, while JScrollPane only moves around the giant text area widget?

I'm confused over this becase I've written several panes with
scrollwidgets for OS/2 and Windows, and in all of them the technique
used is to scale down the size of the text control, adjust the
scrollbars and the paint routine. So if the widget is 320x240 on screen,
but the text spans to 1000x1000 pixels, then if I were to query the
window for its size, I would get 320x240.

If I were to do the same in Java, would I get 1000x1000? If so; that
would explain some of the things I don't understand with JScrollPane.

>> What am I doing wrong?, and why is it only affecting the "amount" text
>> field, but not the ComboBox:es?
> Because the minimum size of the combobox is probably larger (or the same
> as its preferred size)
>
> Try :
[---]

That did the trick. Thanks!

However, I'm still somewhat annoyed but this behaviour of the
GridBagLayout manager. I assume that it behaves this way for a reason I
will discover later on..

Signature

Kind regards,
Jan Danielsson
Nobody loves a cynic

Andrey Kuznetsov - 08 Jan 2005 15:00 GMT
> However, I'm still somewhat annoyed but this behaviour of the
> GridBagLayout manager. I assume that it behaves this way for a reason I
> will discover later on..

you can find here some alternative to GBL:
http://mindprod.com/jgloss/layout.html

Signature

Andrey Kuznetsov
http://uio.dev.java.net Unified I/O for Java
http://reader.imagero.com Java image reader
http://jgui.imagero.com Java GUI components and utilities

Babu Kalakrishnan - 10 Jan 2005 05:41 GMT
[snip]

> This is very confusing to me.. So the JTextArea *actually* grows in
> size, while JScrollPane only moves around the giant text area widget?
[quoted text clipped - 8 lines]
> If I were to do the same in Java, would I get 1000x1000? If so; that
> would explain some of the things I don't understand with JScrollPane.

The JScrollPane in Java functions almost similar to their counterparts
elsewhere - but the parameter you're looking at is the preferredSize -
which is called by LayoutManagers to see how much space it should
allocate to it.

When the getPreferredSize method of a JScrollPane is called, it replies
with the preferred size of the component in its viewport - which if fair
enough - because that is the size it would require to display the
component without any scrollbars. But you (or the LayoutManager) is free
to set it to any size, and the JScrollPane will display scrollbars to
display the component properly. The A getSize() call on it (which is the
actual query for its size) will also return the actual size it is being
displayed at.

>>> What am I doing wrong?, and why is it only affecting the "amount"
>>> text field, but not the ComboBox:es?
[quoted text clipped - 11 lines]
> GridBagLayout manager. I assume that it behaves this way for a reason I
> will discover later on..

I doubt if you'll really discover it :-) In my opinion The sizing
strategy of the GridBagLayout is too simplistic for a complex
LayoutManager. I would have expected it to be able to allocate its child
components an appropriate size between their the preferredSizes and
minimumSizes if there wasn't enough space to allocate them their
preferredSizes instead of abruptly switching between either the
preferredSize for all or minimumSize for all its children. Also it would
have been ideal if the LayoutManager had decoupled the X and Y axis in
its computations - which it is incapable of in its current incarnation.
(For instance if there isn't enough space in the vertical direction -
which would be the case if your textarea had one line too many requiring
a vertical scrollbar - you'd have found your JTextField shrinking
horizontally - which is _very_ counter-intuitive and ridiculous in my
opinion)

A long time ago I started out writing a GBL variant that would do these
things right - but then never got around to finishing it because I
located other alternatives which suited my requirements then - Maybe I
will get around to complete it sometime if I find the time to..

BK


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.