Hello guys,
I hope you can help me with this.
I have read a bit about GUI and now I am trying to do a few exercises to consolidate what I have read.
In the first exercise I have to reproduce a simple GUI. Well I thought it was simple…
Anyway, I have attached a screenshot (exercise.png)
7271152a80ba328594c0c399b2152576
that shows what I have to do.
The result of my code is instead shown in the second screenshot (result.png)
8a5f11f3c5a1875c6db7e9d7fa977bb2
As you can see I didn’t quite manage to group the elements together and place them in the correct order.
Now, let me say that this GUI business isn’t incredibly clear to me and this was my first attempt. I have used a FlowLayout layout manager probably because it is the simplest one and I thought I could achieve that format with it. With hindsight though, maybe that’s not the best option. From the little I know, FlowLayout arranges the elements one after the other till the space runs out, whereas I want them to be arranged in 3 separate groups I reckon and inside the group, one above the other one as in the exercise screenshot
Does anybody have any suggestion? I am not looking for code, I’d like to give it another go first and try to understand the whole thing before admitting defeat.
Which layout manager should I use?
Here is the code:

/*Exercise 14.8 p 662. Create a GUI as described
    create Gui.java
    -checkboxes
    -buttons
    -text fields
*/
import java.awt.FlowLayout;//arrange the components
import javax.swing.JFrame;//basic window feature
import javax.swing.JTextField;//text fields
import javax.swing.JButton;//display the buttons
import javax.swing.JCheckBox;//for checkboxes
import javax.swing.JLabel;//for labels

public class Gui extends JFrame{
    private JCheckBox snapCheckbox;//snap to grid checkbox
    private JCheckBox showGridCheckBox;//show grid checkbox
    private JLabel xLabel;//X
    private JLabel yLabel;//Y
    private JTextField xTextField;//x text
    private JTextField yTextField;//y text
    private JButton okButton;// OK
    private JButton cancelButton;//Cancel
    private JButton helpButton;//Help
    private FlowLayout layout;//layout object

    //constructor
    public Gui(){
        super("Align");
        layout = new FlowLayout();//create FlowLayout
        setLayout( layout ); //set frame layout

        snapCheckbox = new JCheckBox( "Snap to grid" );
        add( snapCheckbox );

        showGridCheckBox = new JCheckBox( "Show grid" );
        add( showGridCheckBox );

        //layout.setAlignment( FlowLayout.LEFT );

        xLabel = new JLabel( "X:" );
        add( xLabel );

        xTextField = new JTextField( "8", 5 );
        add( xTextField );

        yLabel = new JLabel( "Y:" );
        add( yLabel );

        yTextField = new JTextField( "8", 5);
        add( yTextField );

        //layout.setAlignment( FlowLayout.CENTER );

        okButton = new JButton( "OK" );
        add( okButton );

        cancelButton = new JButton( "Cancel" );
        add( cancelButton );

        helpButton = new JButton( "Help" );
        add( helpButton );  

        //layout.setAlignment( FlowLayout.RIGHT );

    }//end of Gui constructor



}//end of Gui class

And

/*Exercise 14.8 p 662, GuiTest.java
    testing Gui.java class. 
*/
import javax.swing.JFrame;
public class GuiTest{
    public static void main( String[] args ){

        Gui guiTest = new Gui();
        guiTest.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        guiTest.setSize( 400, 200 );
        guiTest.setVisible( true );     
    }//end main

}//end of GuiTest

Edited 2 Years Ago by Violet_82

The simplest way is to use multiple JPanels to organise the groups of controls.

eg Place 3 JPanels in your JFrame, flowing left to right. In the first one add the two checkboxes, in the second add the x,y labels and fields, in the third add the buttons. In each of those three cases the controls are just placed in a vertical stack (2x2 grid for the middle one) centered vertically in their respective JPanels.

Edited 2 Years Ago by JamesCherrill

Thanks JamesCherrill. I didn't know I could do that, so you mean like having a JFrame as I currently do and then inside 3 JPanels.
How is a panel different from a JFrame?
I will have a go and then post back

Right, I have made some changes, but I must have missed something really obvious just for a change.
So:
1)I now have 3 JPanels for 3 different types of controllers
2)the checkboxes are in the first panel, the text fields in the second and the buttons in the third
3)I have attached the three types of controllers to the relevant JPanel and then the JPanels to the JFrame.
One thing though is that I am not too sure whether I am supposed to keep the flowLayout manager or not. I left it there but I believe I am not using it?
The position of the elements hasn't changed. Sorry maybe I misunderstood byt I thought that the elements would have been placed in a vertical stack automatically. Here is a screenshot of how it looks like after updating the code
09b0b58794df9a9e162a5fc8044ec361

And here is the updated code:

/*Exercise 14.8 p 662. Create a GUI as described
    create Gui.java
    -checkboxes
    -buttons
    -text fields
*/
import java.awt.FlowLayout;//arrange the components
import javax.swing.JFrame;//basic window feature
import javax.swing.JTextField;//text fields
import javax.swing.JButton;//display the buttons
import javax.swing.JCheckBox;//for checkboxes
import javax.swing.JLabel;//for labels
import javax.swing.JPanel;//for the JPanel

public class Gui extends JFrame{
    private JCheckBox snapCheckbox;//snap to grid checkbox
    private JCheckBox showGridCheckBox;//show grid checkbox
    private JLabel xLabel;//X
    private JLabel yLabel;//Y
    private JTextField xTextField;//x text
    private JTextField yTextField;//y text
    private JButton okButton;// OK
    private JButton cancelButton;//Cancel
    private JButton helpButton;//Help
    private FlowLayout layout;//layout object
    private JPanel checkBoxesPanel;//panel object of JPanel type
    private JPanel textFieldsPanel;
    private JPanel buttonsPanel;

    //constructor
    public Gui(){
        super("Align");
        layout = new FlowLayout();//create FlowLayout
        setLayout( layout ); //set frame layout
        checkBoxesPanel = new JPanel();//set up check boxes panel
        textFieldsPanel = new JPanel();//set up text fields panel
        buttonsPanel = new JPanel();//set up buttons panel

        //elements in checkBoxesPanel
        snapCheckbox = new JCheckBox( "Snap to grid" );
        checkBoxesPanel.add( snapCheckbox );        
        showGridCheckBox = new JCheckBox( "Show grid" );
        checkBoxesPanel.add( showGridCheckBox );


        //layout.setAlignment( FlowLayout.LEFT );
        //elements in textFieldsPanel
        xLabel = new JLabel( "X:" );
        textFieldsPanel.add( xLabel );      
        xTextField = new JTextField( "8", 5 );
        textFieldsPanel.add( xTextField );      
        yLabel = new JLabel( "Y:" );
        textFieldsPanel.add( yLabel );      
        yTextField = new JTextField( "8", 5);
        textFieldsPanel.add( yTextField );

        //layout.setAlignment( FlowLayout.CENTER );

        //elements in buttonsPanel
        okButton = new JButton( "OK" );
        buttonsPanel.add( okButton );       
        cancelButton = new JButton( "Cancel" );
        buttonsPanel.add( cancelButton );       
        helpButton = new JButton( "Help" );
        buttonsPanel.add( helpButton ); 

        //attaching the three panels to the JFrame
        add( checkBoxesPanel );
        add( textFieldsPanel );
        add( buttonsPanel );

        //layout.setAlignment( FlowLayout.RIGHT );

    }//end of Gui constructor



}//end of Gui class

and the same test class:

import javax.swing.JFrame;
public class GuiTest{
    public static void main( String[] args ){

        Gui guiTest = new Gui();
        guiTest.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        guiTest.setSize( 400, 200 );
        guiTest.setVisible( true );     
    }//end main

}//end of GuiTest

You still need to specify appropriate layout managers for the JPanel and its child JPanels. For th JFrame a flow layout is OK - it will place the panels left to right (given enough room). For the panels you ned to specify a layout manager that stacks things vertically - eg GridLayout(0,1) - one column and as many rows as needed, or (0,2) - 2 cols eg for labels & entry fields.

ps don't forget to pack() you JFrame after adding everything.

Edited 2 Years Ago by JamesCherrill

Hello, I think I am getting somewhere, although it's not perfect as yet.
This is what I have now:
ead4d1d646c29a281138712ec9786ce8

As you can see there are some problems in there: there is too little distance between the textfields (where the 8's are) and the buttons and too much between the labels (x and y) and the text fields. I have played around with the parameters in the gridLayout constructor but I don't seem to be able to get the right conbination (if that's the problem) to get the same layout as in the brief.
I have added (I believe) the gridLayout manager for the panels, I am not sure if I have implemented it correctly though. Here's what I have done.
1)declared 3 new gridLayout objects:

//3 grid layouts for 3 different types of controllers
    private GridLayout checkboxGrid;
    private GridLayout textfieldsGrid;
    private GridLayout buttonsGrid;

2)Then in the constructor I set up the 3 grids:

//set up layout manager for checkbox panels
checkboxGrid = new GridLayout( 0, 1 );//1 col and as many rows as needed
checkBoxesPanel.setLayout( checkboxGrid );//set the layout of the jpanel?

//set up layout manager for textfields panels
textfieldsGrid = new GridLayout( 0, 2, 0, 5 );//2 col and as many rows as needed
textFieldsPanel.setLayout( textfieldsGrid );//set the layout for the jpanel?

//set up layout manager for textfields panels
buttonsGrid = new GridLayout( 0, 1, 5, 10 );//1 col and as many rows as needed
buttonsPanel.setLayout( buttonsGrid );//set the layout for the jpanel?

Here is the full code for reference:

/*Exercise 14.8 p 662. Create a GUI as described
    create Gui.java
    -checkboxes
    -buttons
    -text fields
*/
import java.awt.FlowLayout;//arrange the components
import java.awt.GridLayout;//layout for actual controllers
import javax.swing.JFrame;//basic window feature
import javax.swing.JTextField;//text fields
import javax.swing.JButton;//display the buttons
import javax.swing.JCheckBox;//for checkboxes
import javax.swing.JLabel;//for labels
import javax.swing.JPanel;//for the JPanel, 3 of them containing the controls

public class Gui extends JFrame{
    private JCheckBox snapCheckbox;//snap to grid checkbox
    private JCheckBox showGridCheckBox;//show grid checkbox
    private JLabel xLabel;//X
    private JLabel yLabel;//Y
    private JTextField xTextField;//x text
    private JTextField yTextField;//y text
    private JButton okButton;// OK
    private JButton cancelButton;//Cancel
    private JButton helpButton;//Help
    private FlowLayout layout;//layout object
    //panel object of JPanel type
    private JPanel checkBoxesPanel;
    private JPanel textFieldsPanel;
    private JPanel buttonsPanel;
    //3 grid layouts for 3 different types of controllers
    private GridLayout checkboxGrid;
    private GridLayout textfieldsGrid;
    private GridLayout buttonsGrid;

    //constructor
    public Gui(){
        super("Align");
        layout = new FlowLayout();//create FlowLayout
        setLayout( layout ); //set frame layout
        checkBoxesPanel = new JPanel();//set up check boxes panel
        textFieldsPanel = new JPanel();//set up text fields panel
        buttonsPanel = new JPanel();//set up buttons panel

        //elements in checkBoxesPanel
        snapCheckbox = new JCheckBox( "Snap to grid" );
        checkBoxesPanel.add( snapCheckbox );        
        showGridCheckBox = new JCheckBox( "Show grid" );
        checkBoxesPanel.add( showGridCheckBox );

        //set up layout manager for checkbox panels
        checkboxGrid = new GridLayout( 0, 1 );//1 col and as many rows as needed
        checkBoxesPanel.setLayout( checkboxGrid );//set the layout of the jpanel?

        //layout.setAlignment( FlowLayout.LEFT );
        //elements in textFieldsPanel
        xLabel = new JLabel( "X:" );
        textFieldsPanel.add( xLabel );      
        xTextField = new JTextField( "8", 3 );
        textFieldsPanel.add( xTextField );      
        yLabel = new JLabel( "Y:" );
        textFieldsPanel.add( yLabel );      
        yTextField = new JTextField( "8", 3);
        textFieldsPanel.add( yTextField );

        //set up layout manager for textfields panels
        textfieldsGrid = new GridLayout( 0, 2, 0, 5 );//2 col and as many rows as needed
        textFieldsPanel.setLayout( textfieldsGrid );//set the layout for the jpanel?


        //layout.setAlignment( FlowLayout.CENTER );

        //elements in buttonsPanel
        okButton = new JButton( "OK" );
        buttonsPanel.add( okButton );       
        cancelButton = new JButton( "Cancel" );
        buttonsPanel.add( cancelButton );       
        helpButton = new JButton( "Help" );
        buttonsPanel.add( helpButton ); 

        //set up layout manager for textfields panels
        buttonsGrid = new GridLayout( 0, 1, 5, 10 );//1 col and as many rows as needed
        buttonsPanel.setLayout( buttonsGrid );//set the layout for the jpanel?


        //attaching the three panels to the JFrame
        add( checkBoxesPanel );
        add( textFieldsPanel );
        add( buttonsPanel );

        //layout.setAlignment( FlowLayout.RIGHT );

    }//end of Gui constructor



}//end of Gui class

On to the pack() now. I have to admit I have never heard of this before, so I looked that up here and there and it seems that it deals with resizing the window? I have added it but the layout of my window gets even worse and also it constraints the size of the window making the sizes specified in my GUITest.java ineffective. Here is the pack() commented out

/*Exercise 14.8 p 662, GuiTest.java
    testing Gui.java class. 
*/
import javax.swing.JFrame;
public class GuiTest{
    public static void main( String[] args ){

        Gui guiTest = new Gui();
        guiTest.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        guiTest.setSize( 400, 200 );
        guiTest.setVisible( true );
        //guiTest.pack();   
    }//end main

}//end of GuiTest

pack() fits everything together according to the layout manager(s) and any other constrains you have specified. Until you call it your laying out isn't finished. In particular the setSize for the JFrame will be overridden by the pack, but a setMinimumSize should be honoured.

There's only so much you can do with a simple layout manager like GridLayout - I see you already found the h/v spacing options for the constructor. You can shift the labels right by changing their setHorizontalAlignment to close them up to the entry fields. How important is it in this case to get it "just right" as opposed to "near enough"?

In the end, if you really want total control over spacing etc, while still retaining the resizability and platform independence that a layout manager gives you, you have to go to one of the heavy-duty managers - GridBagLayout or SpringLayout. SpringLayout was designed for use by visual form editors, so GridBagLayout is probably the best option if you are writing the code yourself.

Personally, I find the visual editors useless for anything other than the most simple layouts, and I use GridBagLayout for pretty much everything. The syntax is a bit cumbersome, the learning curve is steep, but IMHO it's worth it in the end if you really want complete control.

OK, so essentially I have to use pack(). I don't want to sound thick but what's the point of setting constraints like guiTest.setSize( 400, 200 ); if then pack() will override them? So, have I corrected implemented the pack() method in the GuiTest.java? I was a bit unsure of that.

but a setMinimumSize should be honoured.

I take that by minimum size you mean that the panel will be as big as the content inside it.

I don't think it is absolutely imperative for me to get it perfect, at the end of the day I am not enrolled in any course or doing coursework, I am just learning JAVA in my own time so as long as I understand how tHings work I am more than happy :-)!

I appreciate that the GridLayout, BorderLayout and FlowLayout are very basic layout managers, but I think that I am happy to work with them for the time being: this was my first very basic GUI attempt so I would like to learn a bit more about these before moving to more complicated layout like GridBagLayout.
I know I could use an IDE and save me all the work but I think it is useful to understand how to code them from scratch, at least a basic understanding

I totally agree with everything you said in your last paragraph.

setSize is call for when you're not using a layout manager. By default, most layout managers will make your window "big enough" for its contents.

However if you set a minimum sze for your window then if the layout manager comes up with a smaller size it should "round it up" to your specified minimum. You can also set minimum sizes for your JPanels, which may help with some spacing issues.

@JamesCherrill

  • happy new year, all the best for you and your family

  • can't resist, flamewar again

  • You can also set minimum sizes for your JPanels, which may help with some spacing issues.

  • all JComponents can returns own PreferredSize acceptable by LayoutManager

  • excluding JTable (setPreferredScrollableViewportSize) and JComboBox (setPrototypeDisplayValue), those two JCompoments doesn't returns reasonable PreferredSize

  • AFAIK only BoxLayout accepting min size, there are an some issue with GBC, but by default is this Dimension accepted too

Happy new year to you and yours as well.
My own experience has been that setting preferred size seems to be ignored most of the time, but setting minimum sizes are more often honoured by the layout managers I happened to use. I didn't keep any records, so I can't confirm the details. It's just a general impression. I'm happy to listen to anyone with any hard data on this. :)

Personally I use GridBagLayout whenever layout really matters.

thanks for your help guys.
@JamesCherrill before I close this thread I would like to pick up on something you said:

setSize is call for when you're not using a layout manager.

Can you actually draw a GUI without using a layout manager? I thought that a layout manager had to be used at all times.
Thanks

There is the option of setting the layout manager to null and positioning/sizing everything in pixels using setLocation, setSize, orsetBounds. In doing so you sacrifice any hope of portability between different machines with different preferred font sizec etc, so it's usually a very bad idea. Maybe if you were coding for some known device (eg smartphone) with only one size of screen?

Can you actually draw a GUI without using a layout manager? I thought that a layout manager had to be used at all times.

  • not you can't,

  • NullLayout only to supply unwillingness to read the description in (already linked) official Oracle tutorials about How to Use Layout Managers

This question has already been answered. Start a new discussion instead.