1

I can't make the pack() method work. I tried several things. My code looks like this at the moment:

Class 1:

public static void main( String[] args )
    {
    java.awt.EventQueue.invokeLater(new Runnable() {
        public void run()
        {
         JavaGui mygui = new JavaGui();
   //       mygui.setSize(1154, 753);
            mygui.setVisible(true);
            mygui.pack();

Class 2:

public class JavaGui extends javax.swing.JFrame 
    {
    public JavaGui()
        {
        getContentPane().setLayout(null);
        ..
        getContentPane().add(panelLeft);
        ...
        getContentPane().add(panelRight);

I tried putting the pack method in everywhere, but it's not going to work with this way of adding gui elements. Any suggestions why? I also tried adding everything to a JFrame instead of the getContentPane(), but I can't make that work either.

David Conrad
  • 15,432
  • 2
  • 42
  • 54
user3025756
  • 13
  • 1
  • 1
  • 4
  • I'm not sure if that will work if you're using `null` as the `LayoutManager`. I think you have to set the sizes and positions manually yourself at that point. – David Conrad Sep 09 '14 at 22:21
  • If you are using pack(), use setMinimumSize() instead of setSize() so that your JFrame doesn't shrink down to nothing. – Santiago Benoit Sep 09 '14 at 22:24

3 Answers3

15
  1. Don't use null layouts together with pack(). The pack method tells the layout managers and components to size themselves optimally, and if you instead use null layouts, then the gui risks shrinking to a minimal size, since there is no layout to hold it together.
  2. Don't use null layouts at all for the most part. Using these risk your creating rigid GUI's that are almost impossible to extend, improve, debug.
  3. Don't use setSize(...) and pack(). The layouts mostly respect the preferred sizes of components, not their sizes.

Instead:

  1. Use a pleasing and sensible combination of nested JPanels, each using its own layout manager.
  2. Let the components and the layout managers size themselves.
  3. Then pack should help.
  4. The general order that I do is to add all components to the GUI, then call pack(), then setLocationByPlatform(true) (I think), then setVisible(true).

For better help, please check out the Swing Layout Manager Tutorials.

Here are a couple examples to other questions on this site that use various layout managers:

Community
  • 1
  • 1
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • -1 because you make it yourself to easy. This guy is obviously lost in general on building swing guis. so throwing just a few dont do this´s is not helpful at all. – gantners Sep 09 '14 at 22:24
  • 4
    @gantners: I can't give any more specific answer because he doesn't show any real code, or any image of desired layout or GUI. The real solution of course is for him is to go through the layout manager tutorials and to experiment with them and with building GUI's. But -1 if you like, or better still, create and post a better answer, one we all can learn from. Do that and I will gladly up-vote it! – Hovercraft Full Of Eels Sep 09 '14 at 22:25
  • My experience is that it is absolutely essential to experiment with layouts (i.e. layout managers) at length. You need to start with the simple ones, BorderLayout and BoxLayout, until you really start to understand how they operate, then use JPanels within JPanels within JPanels, with X_AXIS BoxLayouts combined with Y_AXIS BoxLayouts, etc. ... ad nauseam. I think most beginners never do this because it's "only GUI". But the time spend subsequently being baffled, pulling out residual hair, and generally cursing Swing as the spawn of the devil will in fact be MUCH longer. Twas ever thus. – mike rodent Jul 05 '15 at 14:30
2

I would recommened beginners on building up swing guis to use a good ide with a builtin gui designer like eclipse and windowbuilder or netbeans with matisse. It will help you building up a prototype of your desired gui and gives you an insight how the layouting is done in the source code. Experiment with the differenet layouts and what is happening when some values are changed.

one does not simply build up a well behaving gui without understanding how the layout works, so doing the recommended tutorials and looking at examples as already posted by Hovercraft Full Of Eels is absolutely necessary.

For your case i just guess what you were up to. Because youre mentioning left and right panels i suggest a JSplitPane which let you divide your screen in two areas which are customizable in size and orientation.

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;

public class JavaGui extends JFrame {

    //SerialVersionId http://stackoverflow.com/questions/285793/what-is-a-serialversionuid-and-why-should-i-use-it
    private static final long   serialVersionUID    = 1L;

    public static void main(String[] args) {
        //Calls to Gui Code must happen on the event dispatch thread that the gui does not get stuck
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new JavaGui().setVisible(true);
            }
        });
    }       

    public JavaGui() {
        // Set the desired size of the frame to determine the maximum size of its components
        setPreferredSize(new Dimension(1024, 768));

        // Set the default close operation, if press x on frame, destroy the frame and exit the application - others are just destroy the frame or just hide the
        // frame
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // BorderLayout because we just need a centric gui with one component, here JSplitPane in full size
        getContentPane().setLayout(new BorderLayout(0, 0));

        // JsplitPane is a bit special as it depends on the divider location between both panels, for the sake of a small example we take the default -1,
        JSplitPane splitPane = new JSplitPane();
        // 0.5 divides extra space equally to left and right component when resizing the frame - so specifiying a size for the left and right component is not
        // necessary
        // use the divider location default -1 to let the width of the left component decide where the right component begins, in that case because of the
        // resize weight half and half
        splitPane.setDividerLocation(-1);
        splitPane.setResizeWeight(0.5);
        getContentPane().add(splitPane, BorderLayout.CENTER);

        // For the panels the same layout as default as the intention is not stated in your question
        JPanel leftPanel = new JPanel();
        splitPane.setLeftComponent(leftPanel);
        leftPanel.setLayout(new BorderLayout(0, 0));

        JPanel rightPanel = new JPanel();
        splitPane.setRightComponent(rightPanel);
        rightPanel.setLayout(new BorderLayout(0, 0));

        // Add a button Panel to the south for doing something - flow layout for letting the components flow to the right side
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        getContentPane().add(buttonPanel, BorderLayout.SOUTH);

        // Close Button for closing the frame
        JButton btnExit = new JButton("Destroy this frame, but let application run");
        btnExit.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                dispose();
            }
        });
        buttonPanel.add(btnExit);

        // Set every component to its preferred size
        pack();

        // Make it visible
        setVisible(true);
    }
}
gantners
  • 471
  • 4
  • 16
  • 1
    1+ although I don't agree with use of NetBeans in the OP's situation. Maybe I'm jaded by my experience here, but I often see beginners doing great with GUI builder tools as long as they want to create straight-forward GUI's, but as soon as they want to bend the envelope even a little bit, they run into serious difficulties because they are unfamiliar with the GUI library that underpins the tool. – Hovercraft Full Of Eels Sep 10 '14 at 16:10
-1

If you want your JFrame to work with a null layout, rearrange your code so that it looks like this:

public class JavaGui extends javax.swing.JFrame 
{
public JavaGui()
{
    setMinimumSize(1154, 753); // Make sure you do setMinimumSize() instead of setSize() when using pack() so that the JFrame does not shrink to 0 size
    setLayout(null);
    add(panelLeft);
    add(panelRight);
    pack();
}
// Next is main method

Main:

public static void main(String[] args)
{
java.awt.EventQueue.invokeLater(new Runnable() {
    public void run()
    {
        new JavaGui().setVisible(true);
        // Do not do any formatting for your JFrame here
    }
});

Before, you were modifying the JFrame after it was set visible, so that usually does not work, except for pack(). All components and settings for your JFrame should not be in the main method if you are using an anonymous inner class.

You can also use other layouts. Null layouts are for getting pixels in precise locations, which is used for advanced GUI design such as creating a custom GUI, but it seems that you are making a generic GUI with JPanels. For this, I would recommend using a GridBagLayout, which keeps everything centered if the frame is resized and is easy to use. To use a GridBagLayout, you have to replace setLayout(null); with setLayout(new GridBagLayout()); and set GridBagConstraints. Here is some example code of making a panel with a component and a GridBagLayout:

JPanel pane = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
if (shouldFill) {
            //natural height, maximum width
            c.fill = GridBagConstraints.HORIZONTAL;
}
//For each component to be added to this container:
//...Create the component...
//...Set instance variables in the GridBagConstraints instance...
pane.add(theComponent, c);
// Source: Oracle Docs
Santiago Benoit
  • 994
  • 1
  • 8
  • 22
  • 1
    You're recommending that he use a null layout -- a bad thing to recommend to a Swing newbie, and then you're recommend that he call `pack()` on the null layout, something that will cause his GUI to shrink to nothing. Why? – Hovercraft Full Of Eels Sep 09 '14 at 22:39
  • Also note that pack is one of the few modifications that **will** work after the GUI has been set visible. – Hovercraft Full Of Eels Sep 09 '14 at 22:41
  • If you use setMinimumSize() instead of setSize(), the GUI will not shrink down to nothing when pack() is used on a null layout. pack() shrinks the GUI down to the **minimum size**. – Santiago Benoit Sep 09 '14 at 22:41
  • OK, I stand corrected on that point, but still why the recommendation to use a null layout? Using null layout and setBounds will make for very inflexible GUI's that while they might look good on one platform look terrible on most other platforms or screen resolutions and that are very difficult to update and maintain. – Hovercraft Full Of Eels Sep 09 '14 at 22:44
  • i dont think he recommended using the null layout, he just gave a direct answer to the question. so `setMinimumSize` is ok to use with `pack()` which will lead to a frame with this minimum size. Although the left and right panel will shrink to nothing because their minimum size is not set. so he ends up with an empty looking frame. using the null layout is absolutely a viable way to layout something if you strictly need absolute positioning with the drawback of doing it all manually. – gantners Sep 09 '14 at 22:47
  • @gantners: still awaiting your answer to this question. Edit: which should be pretty good, since in all seriousness, I do like some of your other answers to Swing related questions. – Hovercraft Full Of Eels Sep 09 '14 at 22:58
  • @gantners `i dont think he recommended using the null layout` he didn't explicitly but in this line `setLayout(null);` he actually did. – Frakcool Sep 09 '14 at 23:20
  • 2
    Avoid using `null` layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify. Just because the OP has started to use a given approach doesn't mean that approach this right one. As professionals, we should be focusing guiding people to the correct solution, not just the answer to their question - IMHO – MadProgrammer Sep 09 '14 at 23:52
  • @Frakcool he just made the best out of the given code by not deleting what does not need to be deleted. – gantners Sep 10 '14 at 00:15
  • @MadProgrammer Youre fully right up to the point where you want guide to the correct solution. of course the experts should guide the beginners, but not to the correct but a good solution backed by experience. When two experts write code to the same problem, they just take different approaches, but neither of them is more correct. my answer sounds high toned, but thats just another opinion. – gantners Sep 10 '14 at 00:22
  • @gantners I would argue the point that the improper use of an API is cause for a change in direction. If you were teaching some to shoot, would you only teach them how to pull the trigger? Or would you teach them how to hold and point the gun? The proper stance and body position? The API has been designed to operate in a particular way, if the OP wishes to get the most of the API, then it is up to all of us to help guide them to an appropriate solution(s), it would be negligent of us to do otherwise and I would expect no less of any one who answers my questions. Of cause, context helps... – MadProgrammer Sep 10 '14 at 00:28
  • @MadProgrammer this is totally true, i just defended Santiagos solution, as i understood it just as a possible, although not the best, solution to a problem and not as a recommendation he got finger pointed at. – gantners Sep 10 '14 at 00:45
  • I have added clarification on how to use a `GridBagLayout`, which seems like the best layout for them to use. – Santiago Benoit Sep 10 '14 at 18:50