0

I need to create an object of a subclass in the subclass itself but outside of all the methods of the subclass.

In the code below, I want to create an object of ODrawPanel at the specified location (commented part in the code) but when I do this, I get a StackOverflowError. However, I can create the object ODrawPanel inside the display() method with no problem but in that case I cannot use it in the other methods. I need to do some drawing on the panel and the panel must be available anywhere in the code.

How can I make the panel object available anywhere in the code?

Thanks for helping.

package odrawpanel;

import java.awt.*; 
import javax.swing.*; 
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentAdapter;

public class ODrawPanel extends JPanel
{ 
    
        private Point p1 = new Point(100, 300);
        private Point p2 = new Point(380, 300);

        // Either
        // JPanel panel = new ODrawPanel();     I want to create the object of the subclass here.
        // or
        // ODrawPanel panel = new ODrawPanel();

        @Override
        protected void paintComponent(Graphics g) 
        {
            super.paintComponent(g);
            g.setColor(Color.BLUE);       
            g.drawLine(p1.x, p1.y, p2.x, p2.y);
                        
        }
         
        public void display() 
        {   
            JPanel panel = new ODrawPanel(); 
            JFrame f = new JFrame();
 
            panel.setBounds(40, 40, 400, 400);    
            panel.setBackground(Color.white); 
            
            f.add(panel);  
            f.setSize(800,600);    
            f.setLayout(null);    
            f.setLocationRelativeTo(null);
            f.setVisible(true); 
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            f.addComponentListener(new ComponentAdapter() 
            {           
                @Override
                public void componentResized(ComponentEvent e) 
                {
                  panel.setSize(f.getWidth()-100,f.getHeight()-100);                                 
                }
        
            });
         
        }
        
        public static void main(String args[])  
        {          
                EventQueue.invokeLater(new Runnable() 
                  {
                      @Override
                      public void run() 
                      {
                         new ODrawPanel().display();                        
                      }
                  });  
        }
        
}  



Ozgur
  • 15
  • 2
  • 1
    if you initialize it when declaring it, when you create a new `ODrawPanel`, it will create a new `ODrawPanel` as an attribute, that will itself create a new `ODrawPanel`, that will also create a new `ODrawPanel`, etc. leading to a stackoverflow – jhamon Apr 22 '22 at 07:15
  • "in that case I cannot use it in the other methods" - normally you'd just use `this` within the other instance methods. It's not really clear to me what you're trying to do... – Jon Skeet Apr 22 '22 at 07:31
  • side note: [Why is it frowned upon to use a null layout in Swing?](https://stackoverflow.com/questions/6592468/why-is-it-frowned-upon-to-use-a-null-layout-in-swing) – jhamon Apr 22 '22 at 07:39
  • @JonSkeet. I want to create an object of ODrawPanel within the class ODrawPanel itself in the fields area like a global variable and then use this object in any method of ODrawPanel subclass. I am a beginner Java programmer, so please excuse me if I am asking for strange functionalities. – Ozgur Apr 22 '22 at 13:26
  • "like a global variable" suggests it should be a static field, which would avoid the stack overflow... but I would suggest reorganizing your code to avoid needing that at all. – Jon Skeet Apr 22 '22 at 13:42

3 Answers3

0

I would create different classes for the main(), the JFrame, the JPanel.

In Main: new JFrame();

In JFrame: add(new JPanel()); ...

In JPanel: Do not create JPanels here. ...

David Weber
  • 173
  • 9
0

You may declare a JPanel supplier with lazy initialization as a field of the class:

private Point p1 = new Point(100, 300);
private Point p2 = new Point(380, 300);
private final Supplier<JPanel> panelSupplier = new Supplier<>() {

    private JPanel panel;

    @Override
    public JPanel get() {
        if (panel == null) {
            panel = new ODrawPanel();
        }
        return panel;
    }
};

... and then use it all over the class by .get()ting the value from the supplier (the first time you use it, the ODrawPanel will be created but it won't cause an overflow since you're not recursively initializing it:

public void display() {
    JPanel panel = panelSupplier.get(); //the first time you call get() it will create the panel, the next times it will reuse it
    JFrame f = new JFrame();

    panel.setBounds(40, 40, 400, 400);
    //...rest of the code
Matteo NNZ
  • 11,930
  • 12
  • 52
  • 89
0

Matteo, thank you for the code. When I tried it, I got the following compiler error for the line:

private final Supplier<JPanel> panelSupplier = new Supplier<>()
{
   // some code here.
};
"cannot infer type arguments for Supplier<T>
  reason: '<>' with anonymous inner classes is not supported in -source 8
    (use -source 9 or higher to enable '<>' with anonymous inner classes)
  where T is a type-variable:
    T extends Object declared in interface Supplier"

After changing the code to:

private final Supplier<JPanel> panelSupplier = new Supplier<JPanel>()
{
  // some code here.
}

I did not receive an error. It works, for example, in a method like:

public void Test()
{
  JPanel panel = panelSupplier.get();
  panel.setBackground(Color.RED);
}

But it has no effect in the method:

protected void paintComponent(Graphics g) 
{
   super.paintComponent(g);
   g.setColor(Color.BLUE);       
   g.drawLine(p1.x, p1.y, p2.x, p2.y);
            
   JPanel panel = panelSupplier.get();
   panel.setBackground(Color.CYAN); 
}
Ozgur
  • 15
  • 2