First of all, I know using the setLayout(null) is not the best way, but the goal of that program was to try writing a GUI that is resizable by myself.
First of all, the three classes (the reason of splitting the GroundFrame.java and the HomeScreen.java is that in future there will be multiple windows):
Start.java
public class Start {
public static void main(String[] arg){
new GroundFrame();
}
}
GroundFrame.java
public class GroundFrame extends JFrame{
static final long serialVersionUID = 0;
Container contentPane;
HomeScreen homeScreen;
public GroundFrame(){
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private void createAndShowGUI(){
createBasicFrame();
createPaneAndAddHome();
setVisible(true);
}
private void createBasicFrame(){
addComponentListener(new ComponentListener() {
public void componentShown(ComponentEvent e) {}
public void componentResized(ComponentEvent e) {
homeScreen.resizeHome(getContentPane().getSize());
}
public void componentMoved(ComponentEvent e) {}
public void componentHidden(ComponentEvent e) {}
});
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
contentPane = getContentPane();
contentPane.setPreferredSize(new Dimension(600, 400));
contentPane.setLayout(null);
pack();
}
private void createPaneAndAddHome(){
homeScreen = new HomeScreen(contentPane.getSize());
contentPane.add(homeScreen);
}
}
HomeScreen.java
public class HomeScreen extends JPanel{
static final long serialVersionUID = 0;
private JLabel labelHeader, labelFooter;
private JTextField textField;
private int x, y;
public HomeScreen(final Dimension dimension){
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowPanel(dimension);
}
});
}
private void createAndShowPanel(Dimension dimension){
labelHeader = new JLabel("HEADER");
textField = new JTextField();
labelFooter = new JLabel("FOOTER");
setupPanel(dimension);
}
private void setupPanel(Dimension dimension){
x = dimension.width;
y = dimension.height;
setBounds(0,0,x,y);
setLayout(null);
setupTitle(new Dimension(x,y));
}
private void setupTitle(Dimension dimension){
x = dimension.width;
y = dimension.height;
labelHeader.setBounds((int)(x*0.1), (int)(y*0.1), (int)(x*0.8), (int)(y*0.3));
labelHeader.setOpaque(true);
labelHeader.setBackground(Color.cyan);
labelHeader.setFont(new Font("Arial", Font.PLAIN, (int)(y*0.25)));
textField.setBounds((int)(x*0.25), (int)(y*0.45), (int)(x*0.5), (int)(y*0.1));
textField.setFont(new Font("Arial", Font.PLAIN, (int)(y*0.08)));
labelFooter.setBounds((int)(x*0.1), (int)(y*0.6), (int)(x*0.8), (int)(y*0.3));
labelFooter.setOpaque(true);
labelFooter.setBackground(Color.cyan);
labelFooter.setFont(new Font("Arial", Font.PLAIN, (int)(y*0.25)));
add(labelHeader);
add(labelFooter);
add(textField);
}
public void resizeHome(Dimension dimension){
setupPanel(dimension);
}
}
Now everything works as I had in mind, but I’m getting a NullpointerException at following line in HomeScreen.java
labelHeader.setBounds((int)(x*0.1), (int)(y*0.1), (int)(x*0.8), (int)(y*0.3));
This is the error message
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at gui.HomeScreen.setupTitle(HomeScreen.java:45)
at gui.HomeScreen.setupPanel(HomeScreen.java:39)
at gui.HomeScreen.resizeHome(HomeScreen.java:64)
at gui.GroundFrame$2.componentResized(GroundFrame.java:43)
at java.awt.AWTEventMulticaster.componentResized(AWTEventMulticaster.java:159)
at java.awt.Component.processComponentEvent(Component.java:6331)
at java.awt.Component.processEvent(Component.java:6285)
at java.awt.Container.processEvent(Container.java:2229)
at java.awt.Window.processEvent(Window.java:2022)
at java.awt.Component.dispatchEventImpl(Component.java:4861)
at java.awt.Container.dispatchEventImpl(Container.java:2287)
at java.awt.Window.dispatchEventImpl(Window.java:2719)
at java.awt.Component.dispatchEvent(Component.java:4687)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:703)
at java.awt.EventQueue.access$000(EventQueue.java:102)
at java.awt.EventQueue$3.run(EventQueue.java:662)
at java.awt.EventQueue$3.run(EventQueue.java:660)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
at java.awt.EventQueue$4.run(EventQueue.java:676)
at java.awt.EventQueue$4.run(EventQueue.java:674)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:673)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:244)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:163)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:151)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:147)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:139)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:97)
Nonetheless, the program continues to run as nothing happened. After all, the error appears when the program starts, so at a point where no manually resize is performed (The error message indicates that the error is called among others from the HomeScreens resizeHome()). Why is this so? Why does the program continues to run? Is it possible that the building of the GUI itself is a first call of the ComponentListeners componentResized()?
This is because you are using
SwingUtilities#invokeLaterin your constructorsWhat you’ve created is a race condition within you UI.
Basically,
homeScreen.resizeHomeis being called (fromcomponentResized) BEFOREHomeScreen#createAndShowPanelis called, thus meaning that thelablelHeaderhas not yet being initalised…Your current sequence of events look something like…
new GrounFrame()invokeLaterGroundFrame#createAndShowGUIGroundFrame#createBasicFrame(addComponentListener,pack)GroundFrame#createPaneAndAddHomenew HomeScreeninvokeLaterHomeScreen#createAndShowPanel… return immediately…GrounFrame#setVisible(true)GrounFrame#ComponentListener#componentResizedHomeScreen#resizeHomeHomeScreen#setupPanelNull Pointer ExceptionHomeScreen#createAndShowPanelYou should sync your UI with the EDT within your
mainAnd remove the other references to
SwingUtilities#invokeLater