I'm trying to develop an editor which you can insert text and draw shapes on. To do this, I'm using a JPanel as the main panel, and listening to mouse actions I add new JPanels into it. I draw the shapes on the small panels using getGraphics(). But the main panel somehow prevents the small panels from displaying their contents. When repaint is called we can see a glimpse of the ovals and lines inside the panels, but then they disappear. If I use JEditorPane as the main canvas, then they are displayed correctly. Why does JPanel do this?

public class SectionPage extends JPanel {

    private int drawMode = 0;
    ArrayList<JComponent> pageComponents;
    ArrayList<ReportElement> reportElements;
    JTextArea tempTextArea;
    JPanel tempPanel;
    JComponent tempComponent;
    BasicStroke stroke;
    float[] dashes;

    public SectionPage() {
        dashes = new float[]{10.0f, 10.0f};
        pageComponents = new ArrayList<JComponent>();
        reportElements = new ArrayList<ReportElement>();
        setBackground(Color.white);
    @Override
    public void paintComponent(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        super.paintComponent(g2);
        int x1, y1;
        int x2, y2;
        this.removeAll();

        for (int i = 0; i < reportElements.size(); i++) {
            tempComponent = new JPanel();
            x1 = reportElements.get(i).getX1();
            y1 = reportElements.get(i).getY1();
            x2 = reportElements.get(i).getX2();
            y2 = reportElements.get(i).getY2();

            if (x1 > x2 && y1 > y2) {
                tempComponent.setLocation(x2, y2);
                tempComponent.setSize(x1 - x2, y1 - y2);
            } else if (x1 < x2 && y1 > y2) {
                tempComponent.setLocation(x1, y2);
                tempComponent.setSize(x2 - x1, y1 - y2);
            } else if (x1 < x2 && y1 < y2) {
                tempComponent.setLocation(x1, y1);
                tempComponent.setSize(x2 - x1, y2 - y1);
            } else if (x1 > x2 && y1 < y2) {
                tempComponent.setLocation(x2, y1);
                tempComponent.setSize(x1 - x2, y2 - y1);
            }

            //tempComponent.setBackground(Color.red);
            this.add(tempComponent);
            reportElements.get(i).display((Graphics2D)  tempComponent.getGraphics());
        }
    }

Edited 6 Years Ago by linkinmal: n/a

by the way that display() method at the end takes that Graphics object and draws a line or oval or sth. using it.

public void display( Graphics2D g ) {
               g.drawLine( 0, 0, Math.abs(x2-x1), Math.abs(y2-y1) );
        }

Edited 6 Years Ago by linkinmal: n/a

Probably because whatever method repaint() indirectly calls (paint or update, I don't remember which) must be clearing your background. Get rid of the call to repaint() and instead try calling revalidate(). If that doesn't work and you post the rest of your code, I'll play around with it later tonight and try to help you out.

Edited 6 Years Ago by BestJewSinceJC: n/a

thanks. it didn't work, actually I had to put all the panel-adding-and-drawing-inside-them-part into paintComponent() because the main panel was resetting its layout on repaint or some other invocation. So now they stay where they are, but we can't see the drawings inside.

I mean at every repaint I remove all the components and put them again at their coordinates, and call display() to draw something in them. I do it every time :) Because like I said calling repaint on every little component wasn't working, the main panel was resetting the layout.
Ok i will post the code.

Edited 6 Years Ago by linkinmal: n/a

I'll try to cut and reorganize because everything is spread to other classes; I'm not sure if it will be, what's that called, compilable, readable something something.

public class SectionPage extends JPanel {
    public SectionPage() {
JComponent tempComponent;
        setBackground(Color.white);
}
    @Override
    public void paintComponent(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        super.paintComponent(g2);
        int x1, y1;
        int x2, y2;
        this.removeAll();

        tempComponent = new JPanel();
        x1 = 100;
        y1 = 100;
        x2 = 200;
        y2 = 150;

        if (x1 > x2 && y1 > y2) {
              tempComponent.setLocation(x2, y2);
              tempComponent.setSize(x1 - x2, y1 - y2);
        } else if (x1 < x2 && y1 > y2) {
              tempComponent.setLocation(x1, y2);
              tempComponent.setSize(x2 - x1, y1 - y2);
        } else if (x1 < x2 && y1 < y2) {
              tempComponent.setLocation(x1, y1);
              tempComponent.setSize(x2 - x1, y2 - y1);
         } else if (x1 > x2 && y1 < y2) {
              tempComponent.setLocation(x2, y1);
              tempComponent.setSize(x1 - x2, y2 - y1);
           }

            tempComponent.setBackground(Color.red);
            this.add(tempComponent);
            display((Graphics2D) tempComponent.getGraphics());
}
        
    public void display( Graphics2D g ) {
        g.drawLine( 0, 0, Math.abs(x2-x1), Math.abs(y2-y1) );
    }
}

can you add this to a frame and do things that fire repaint()? Maybe this very short and unsophisticated cut will work, if it does, it's bad. thanks in advance

Edited 6 Years Ago by linkinmal: n/a

I don't know why your call to super.paintComponent(g) is the second call in your method; I was always taught that a call to super has to be the first call in your method as it says here. I could be wrong and this might be a special case, but I don't think so. And you don't need to be constantly adding the JPanel back; add it once, then simply clear the screen when you need to (which is what super.paintComponent(g) does if I remember correctly). Anyway, the code you gave me wouldn't compile or even come close, but this small sample works:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class SectionPage extends JPanel implements MouseListener{
	JFrame tempComponent;
	boolean colorWhite;
	
	public static void main(String[] args){
		
		new SectionPage();
	}
	
	
	@Override
	protected void paintComponent(Graphics g) {
        super.paintComponent(g);
		Graphics2D g2 = (Graphics2D) g;
		if (colorWhite){
		g2.setColor(Color.WHITE);
		} else g2.setColor(Color.BLACK);
        g2.fillRect(100, 100, 50, 50);
        
	}
        
    public void display( Graphics2D g ) {
    	
    }
    
	public SectionPage() {
		tempComponent = new JFrame("Test Graphics");
		tempComponent.add(this); 
		tempComponent.setSize(500,500);
		tempComponent.setVisible(true);
		this.addMouseListener(this);
		colorWhite=true;
        setBackground(Color.white);
	}

	@Override
	public void mouseClicked(MouseEvent arg0) {
		// TODO Auto-generated method stub
		if (colorWhite) colorWhite=false;
		else colorWhite=true;
		repaint();
	}

	@Override
	public void mouseEntered(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseExited(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mousePressed(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseReleased(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}
}

I don't know why your call to super.paintComponent(g) is the second call in your method; I was always taught that a call to super has to be the first call in your method as it says here. I could be wrong and this might be a special case, but I don't think so.

Just to clear this bit up, you can call super.whatever() anytime, anywhere, you're thinking of constructors where the super() or super(x,y,x....) must be the first line in the constructor

typically super.method() is called if you're overriding a method but still want/need the super to be called for whatever processing it does

thanks I will try that super call thing. By the way my problem was adding panel B into panel A and then drawing something on panel B. And that code didn't compile, eh?

It may be more complicated than I thought due to drawing JPanels which are components, perhaps the Swing Layout Manager is preventing you from explicitly setting the location and keeping it there. Maybe if you set the layout of the container to null it will work. But again, if you would post the *working, compiling* code instead of a snippet that doesn't come close to running then I could play around with it and truly help you. . anything else from me at this point is just speculation. If you can't post all of your code for whatever reason that is fine, hopefully someone else can help you. Oh, and what balmark says seems to be true, it only matters for constructors; in any other method, you can call super at any point.

Edited 6 Years Ago by BestJewSinceJC: n/a

In that case I will have to post a very long code from 4-5 classes, it's gonna be really long the thread will look like Sears Tower :) Well, hmm, let me try to use another project and try it, then post the code if required.

I'd recommend re-thinking your painting logic altogether. You really don't want to be creating new components, adding them to your current container, and then trying to hand their graphics context off to be drawn on all inside the method that is just supposed to be drawing your panel. It's just too much.

Create a small component that can represent your sub-panels and put the painting code in its paintComponent() method. Create some other method that handles the creation/arrangement of those sub-components. Leave paintComponent() to what it is for: painting.

Ok here it is.

You need to first select 'New' from the menu and three pages will be opened. Then select the line button from the left and draw it on one of the pages. You draw it like press, drag and release style. It's gonna put the panel but not draw the line inside.

Thanks Ezzaral, I'll do that. The problem with adding the components was that the main panel was forgetting the locations of the small ones. Someone here suggested trying setting the layout to null, I guess I'll try something like that. It's frustrating, though.

This article has been dead for over six months. Start a new discussion instead.