1

basically I'm trying to understand Threads in Java.So I thought I'd create a main JFrame class containing two JPanels from external classes and then do something in one and control it with messages from the second panel.So far I have only created the first external panel and there the probleme starts! It does not show correctly although it appears to be "loaded".(see system.out lines) So here is the Main Class

package com.maybee.gui;

import java.awt.*;
import javax.swing.*;
 import javax.swing.border.LineBorder;

public class Maybee extends JFrame implements Runnable 
{
public JFrame  maynFrame = null;
public JPanel contentPanel = null;
public SimPanel simPanel = null;

public int screenWidth = 0;
public int screenHeight = 0;

public Maybee()
{

}


private void init()
{
    System.out.println("In Inint");
    maynFrame = new JFrame("Maybee");
    maynFrame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
    GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
    screenWidth = gd.getDisplayMode().getWidth();
    screenHeight = gd.getDisplayMode().getHeight();
    maynFrame.setPreferredSize(new Dimension(screenWidth,screenHeight - 100));
    maynFrame.setContentPane(getContentPanel());
    maynFrame.setVisible(true);
    maynFrame.pack();
}

public JPanel getContentPanel()
{
    if (contentPanel == null)
    {
        contentPanel = new JPanel();
        contentPanel.setPreferredSize(new Dimension(screenWidth,screenHeight - 100));
        contentPanel.setBorder(new LineBorder(Color.BLUE));
        contentPanel.setBackground(Color.RED);
        contentPanel.setLayout(new BorderLayout());
        contentPanel.add(getSimPanel(),BorderLayout.CENTER);

    }

    return contentPanel;
}

public SimPanel getSimPanel()
{
    if(simPanel == null)
    {
        simPanel = new SimPanel(this);

    }
    return simPanel;
}


public static void main(String[] args)
{

    EventQueue.invokeLater(new Runnable() 
    {
        public void run()
        {
            System.out.println("Start");
            Maybee maybee =  new Maybee();
            maybee.run();

        }

    });
}

public void run()
{
    init();

}

}

and now the first external JPanel class

package com.maybee.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JPanel;

public class SimPanel extends JPanel
{
   public Maybee localMaybee = null;
   public JPanel simPanel = null;
   private JButton btn;

   public SimPanel(Maybee interMaybee)
  {
    localMaybee = interMaybee;
    init();
  }

  public void init()
  {
    simPanel = new JPanel();
    simPanel.setLayout(new BorderLayout());
    simPanel.setPreferredSize(new Dimension(localMaybee.screenWidth/4,localMaybee.screenHeight - 100));
    simPanel.setBackground(Color.GREEN);
    simPanel.add(getBtn(),BorderLayout.CENTER);
    simPanel.setVisible(true);

    System.out.println("IN SIM" + localMaybee.screenWidth);
}

public JButton getBtn()
{
    if(btn == null)
    {
        btn = new JButton("ENDE");
        btn.setSize(70, 20);
        btn.setForeground(Color.YELLOW);
        btn.addActionListener(new ActionListener()
        {

            @Override
            public void actionPerformed(ActionEvent e) 
            {


            }
        });

    }
    return btn; 
}
}

So what am I missing?

Many thanks!

  • 2
    Can't test at them moment but: 1) Call `pack();` before `setVisible(true);` 2) You're extending `JFrame` on `Maybee` class (and not using that `JFrame`, so it's safe if you delete the `extends JFrame` part. 3) Don't call `setSize()`, [don't call setPreferred|Maximum|MinimumSize()](https://stackoverflow.com/questions/7229226/should-i-avoid-the-use-of-setpreferredmaximumminimumsize-methods-in-java-swi) methods either, instead override `getPreferredSize()` methods (or maximum / minimum). – Frakcool Aug 21 '17 at 18:37
  • Hello Frakcool, that was quick. Unfortunately (1) doesn't work and (2) gives an error. (3) I didn't quite understand.Thanks – stafford3105 Aug 21 '17 at 19:13

1 Answers1

3

The immediate issue is the second instance of JPanel created in SimPanel.init(). SimPanel is already a JPanel, there is no need to maintain public JPanel simPanel member.

The same problem is in the Maybee class which extends JFrame, but maintains public JFrame maynFrame member.

Also, as already mentioned in comments above (thanks @Frakcool!) :

  • Make sure to call pack() before setVisible();

  • Don't call setPreferredSize(), do override getPreferredSize() intead;

  • No need to extend JFrame;

  • No need to call setVisible on JPanel;

  • Don't call btn.setSize(), it is a job for a layout manager;

  • No need for setContentPane(), JFrame by default has a JPanel as content pane with BorderLayout. Calling add() is enough in this case.

Here is a slightly modified version of the original code (simplified for clarity):

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Maybee2 {
    static class SimPanel extends JPanel {
        public SimPanel() {
            setLayout(new BorderLayout());

            JButton btn = new JButton("ENDE");
            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    //TODO
                }
            });
            add(btn, BorderLayout.CENTER);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(300, 200);
        }
    }

    private static void createAndShowGUI() {
        final JFrame frame = new JFrame("Maybee");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        SimPanel simPanel = new SimPanel();
        frame.add(simPanel);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

EDIT:

The application may consist of many panels. The high level container such as JFrame is not aware of all the underlying layout complexities and cannot enforce a certain size. The panel itself knows its internal layout and its content. So the panel reports its preferred size to the layout manager which eventually packs the content. See Laying Out Components Within a Container for more information.

setBackground has its effect although the button occupies the center of the BorderLayout which takes all the space of the panel. Change the layout of the panel and see the effect. Or move the button into another area, ie - add(btn, BorderLayout.NORTH); Read more in A Visual Guide to Layout Managers.

tenorsax
  • 21,123
  • 9
  • 60
  • 107
  • Many thanks to @Frakcool! and @tenorsax. Much food for thought here!! – stafford3105 Aug 23 '17 at 05:20
  • 1
    Many thanks. Much food for thought here!! I have two further questions if I may. Q1. Why override preferred size as I'd like to be able to vary component sizes at will. Q2.When I setBackground color for the panel it dosen't work but when I setBackground color for the button the whole panel changes! – stafford3105 Aug 23 '17 at 05:30
  • @stafford3105 these are good questions! Please see the last edit. – tenorsax Aug 23 '17 at 16:33
  • 1
    Once again thank you for a quick reaction to my questions. Your solutions and explainations are clear and understandable. I have implemented them with success. Thanks again to you and Stackoverflow!!! – stafford3105 Aug 23 '17 at 18:37
  • @stafford3105 you are welcome! I am glad it worked out :) – tenorsax Aug 23 '17 at 18:54