paintComponent() wird nicht aufgerufen!

Status
Nicht offen für weitere Antworten.

Achtel

Mitglied
Leute, ich krieg noch die Krise...

Ich hab zwei Klassen, die eine von JFrame abgeleitet (A), die andere von JPanel (B). In der JPanel-Subklasse habe ich mit
Code:
protected void paintComponent(Graphics g)
die paintComponent()-Methode überschrieben. Jetzt soll bei einem mouseReleased-Event die paintComponent-Methode von B aufgerufen werden. Daher hab ich in meinem MouseMotionListener
Code:
InstanzB.paint(InstanzB.getGraphics())
zu stehen und (zur Kontrolle) ein System.out.println in die paintComponent eingebaut - funktioniert aber nicht, die Methode wird nicht mal aufgerufen...

Was mach ich falsch?

(InstanzB.paint(this.getGraphics()) hab ich auch probiert, mit demselben Ergebnis)
 
Versuch doch mal ein "instanceB.repaint()". "getGraphics" ist sowieso nicht so der Hammer, repaint ist sicherer.

Bist du sicher, dass du bei der richtigen Instanz die paint-Methode aufrufen lässt?
 
Bringt auch nichts. Was die Instanz angeht, bin ich mir schon sicher. Es ist nämlich immer nur eine (zeitgleich) aktiv. Und die ruf ich auf... irgendwelche anderen Vorschläge?
 
Mehr Code 🙂 Hast du das Panel auch dem Frame hinzugefügt? Ist die Grösse ok?
 
Code:
public class TickFrame extends JFrame
{
  public TickFrame(Document d)
  {
    super("TickFrame");
    this.doc = d;
    cp = getContentPane();
    
    // create main panel (user's design)
    main_panel = new JPanel();
    main_panel.setBorder(new javax.swing.border.LineBorder(Color.BLACK));
    main_panel.setPreferredSize(new Dimension(500,400));
    
    // mouseListener for main_panel
    main_panel.addMouseListener(new MouseAdapter()
    {
      public void mouseClicked(MouseEvent evt)
      {
        mainPanelMouseClicked(evt);
      }
      public void mousePressed(MouseEvent evt)
      {
        mainPanelMousePressed(evt);
      }
      public void mouseReleased(MouseEvent evt)
      {
    	mainPanelMouseReleased(evt);
      }
    });
    main_panel.setLayout(null);						// to allow free dragging of boxes
    cp.add(main_panel, BorderLayout.CENTER);
    
    // create button toolbar at side of main_panel
    JToolBar button_toolbar = new JToolBar(SwingConstants.VERTICAL);
   
    // add button "Add Class"
    JButton add_class_button = new JButton("Add Class");
    add_class_button.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); 
    add_class_button.addActionListener(new ActionListener()					
    {
      public void actionPerformed(ActionEvent evt)
      {
        addClassButtonActionPerformed(evt);
      }
    });
    button_toolbar.add(add_class_button);
    
    // add button "Add Arrow"
    JButton add_arrow_button = new JButton("Add Arrow");
    add_arrow_button.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    add_arrow_button.addActionListener(new ActionListener()
    {
      public void actionPerformed(ActionEvent evt)
      {
    	addArrowButtonActionPerformed(evt);
      }
    });
    button_toolbar.add(add_arrow_button);
    cp.add(button_toolbar, BorderLayout.WEST);
    
    // create panel across bottom edge of main window --> counters
    status_panel = new JPanel();
    status_panel.setBorder(new javax.swing.border.LineBorder(Color.BLACK));
    status_panel.setPreferredSize(new Dimension(10,50));
    cp.add(status_panel, BorderLayout.SOUTH);
    
    pack();
  }

  // methods called from listeners - buttons
  private void addClassButtonActionPerformed(ActionEvent evt)
  {
    // create new box - dimension = (0,0) --> setSize in mouseReleased
	try
	{
	  activeInstance = new ClassBox(TickFrame.this,main_panel,doc,status_panel);
	  // add instance to main_panel
	  main_panel.add(activeInstance);
	}
	catch(IllegalArgumentException iae)
	{
	  JOptionPane.showMessageDialog(this, "Class couldn't be created");
	}
  }
  
  // methods called from listeners - main_panel
  private void mainPanelMouseClicked(MouseEvent evt)
  {
	this.requestFocus();	// therefore classBox focus lost --> black border
	if(activeInstance != null)
	{
	  activeInstance.setLocation(evt.getX(),evt.getY());
	  activeInstance.setSize(50,50);
	}
  }
  
  private void mainPanelMousePressed(MouseEvent evt)
  {
	if(activeInstance != null)
	{
	  System.out.println("x"+evt.getX()+"y"+evt.getY());
	  activeInstance.setCoordP(evt.getX(),evt.getY());		// set top left coordinates of box
	  System.out.println("coordinates set: "+activeInstance.getX1coord()+activeInstance.getY1coord());
	}
  }
  
  private void mainPanelMouseReleased(MouseEvent evt)
  {
    if(activeInstance != null)		// if instance of ClassBox was created beforehand
    {
      activeInstance.setCoordR(evt.getX(),evt.getY());		// set bottom right coordinates of box      

      // register class
      doc.registerClass(activeInstance,activeInstance.getX1coord(),activeInstance.getY1coord());
      
      activeInstance.repaint();
      
      // increment # classes
      doc.incrementClass(activeInstance,status_panel);
      
      activeInstance = null;		// box created therefore no instance "in preparation"
      
      Cursor hc = new Cursor(Cursor.HAND_CURSOR);
      main_panel.setCursor(hc);
    }
  }

  // program entry point
  public static void main(String args[])
  {
    Document d = new Document();		// create underlying document
	TickFrame tf = new TickFrame(d);	// create instance of tickframe and associate document
	tf.setVisible(true);				
	d.showCounter(tf.status_panel);		// show status_panel
  }
}

Code:
public class ClassBox extends JPanel implements MouseListener, MouseMotionListener, FocusListener
{  
   // Constructor
   public ClassBox(TickFrame frame, JPanel panel, Document d, JPanel status) throws IllegalArgumentException 
   {
	 this.mpanel = panel;
	 this.spanel = status;
	 this.frame = frame;
	 this.document = d;
	 
	 this.setSize(new Dimension(0,0));	// initial dimension of box
	 									// final size set after getting coordinates from mouse
     this.setBorder(BorderFactory.createLineBorder(Color.black,1));
     this.setBackground(Color.white);
     
     // listeners
     this.addMouseListener(this);
     this.addMouseMotionListener(this);
     this.addFocusListener(this);
     
     // vertical box layout for aligning class/method labels 
     this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
     
     // dialog for class name
     c_name = (String) JOptionPane.showInputDialog(frame,
                                                   "Enter the class name",
                                                   "Name?",
                                                    JOptionPane.PLAIN_MESSAGE,
                                                    null,
                                                    null,
                                                    "Enter class name here...");
     if(c_name == null) 
     {
      IllegalArgumentException iae = new IllegalArgumentException();
      throw iae;
     }
     
     // dialog for # class methods
     Object options[] = {"1", "2", "3", "more...", "cancel"};
     int no1 = JOptionPane.showOptionDialog(frame,
                                            "How many class methods?",
                                            "# methods?",
                                            JOptionPane.DEFAULT_OPTION,
                                            JOptionPane.QUESTION_MESSAGE,
                                            null,
                                            options,
                                            options[0]);
     // selection = cancel
     if(no1 == 4)
     {
       IllegalArgumentException iae = new IllegalArgumentException();
       throw iae;
     }
     
     // selection = more, read input and convert to integer
     if(no1 == 3)
     {
       String no2 = (String) JOptionPane.showInputDialog(frame,
                                                         "How many class methods=",
                                                         "# methods?",
                                                         JOptionPane.PLAIN_MESSAGE,
                                                         null,
                                                         null,
                                                         "Enter the number of methods here...");
       
       if(no2 == null)
       {
         IllegalArgumentException iae = new IllegalArgumentException();
    	 throw iae;
       }
       else
       {
         // cast Integer from String
         Integer no3 = new Integer(no2);
         no1 = no3.intValue() - 1;
       }
     } 
     
     // dialog for method names
     c_methods = new Vector((no1+1),1); 
     for(int i=0; i<(no1+1);i++)
       {
         String method_names = (String) JOptionPane.showInputDialog(frame,
                                                           "Enter method name #" + (i+1),
                                                           "Methods",
                                                           JOptionPane.PLAIN_MESSAGE,
                                                           null,
                                                           null,
                                                           "Enter the method name here...");
    	 if(method_names == null)
    	 {
    	   for(int j=1;j<=i;j++)
    	   {
    	     document.decrementMethod(spanel);
    	   }
    	   
    	   IllegalArgumentException iae = new IllegalArgumentException();
           throw iae;
    	 }
    	 else
    	 {
    	   c_methods.add(i,method_names);
    	   // increment counter of methods
           document.incrementMethod((String) c_methods.elementAt(i),spanel);
    	 }
       }

     // info dialog 
     JOptionPane.showMessageDialog(frame, "Click anywhere in the panel to indicate the top left corner 
and release mouse to indicate bottom right corner.");
     
     // change cursor
     Cursor chc = new Cursor(Cursor.CROSSHAIR_CURSOR);
     mpanel.setCursor(chc);
   }
   
   protected void paintComponent(Graphics g)
   {
 	System.out.println("paintComponent");
 	// set location for classboxes as registered in array
 	for(int i=1;i<document.noclass;i++)
 	{
       Register[] r = document.regarray;
       // set location
 	  r[i].getBox().setLocation(r[i].getX(),r[i].getY());
 	  // set size - standard || customized
 	  if(r[i].getBox().getBoxWidth() < 50 || r[i].getBox().getBoxHeight() < 50)
      {
     	r[i].getBox().setSize(50,50);		// minimum size 50x50
      }
      else
      {
     	r[i].getBox().setSize(r[i].getBox().getBoxWidth(),r[i].getBox().getBoxHeight());  
      }
 	  // add label
 	  r[i].getBox().addLabel(r[i].getBox().c_name, r[i].getBox().classMetrics, 
r[i].getBox().className);
       for(int j=0;j<r[i].getBox().c_methods.size();j++)
       {
     	r[i].getBox().addLabel((String)r[i].getBox().c_methods.get(i), 
r[i].getBox().methodMetrics, r[i].getBox().methodName);
       }
 	}
   }
   
   // methods for coordinates of box (top left) - get & set
   public int getX1coord()
   {
     return c_x1;
   }
   public int getY1coord()
   {
     return c_y1;
   }
   public void setCoordP(int x,int y) 
   {
	 c_x1 = x;
	 System.out.println("c_x1 "+c_x1);
	 c_y1 = y;
	 System.out.println("c_y1 "+c_y1);
   }
   
   // methods for coordinates of box (bottom right) - get & set
   public int getX2coord()
   {
	 return c_x2;
   }
   public int getY2coord()
   {
	 return c_y2;
   }
   public void setCoordR(int x,int y)
   {
	 c_x2 = x;
	 c_y2 = y
   }
   
   // methods for width, height of box - get & set
   public int getBoxWidth()
   {
	 c_width = c_x2 - c_x1;
	 return c_width;
   }
   public int getBoxHeight()
   {
	 c_height = c_y2 - c_y1;
	 return c_height;
   }
   public void setBoxWidth(int width)
   {
     c_width = width;
   }
   public void setBoxHeight(int height)
   {
     c_height = height;
   }
   
   // label for class + methods
   public void addLabel(String text, FontMetrics fontMetrics, Font font)
   { 
	 this.add(Box.createRigidArea(new Dimension(0,5)));
	 this.add(Box.createRigidArea(new Dimension(5,0)));
	 
	 JLabel label = new JLabel(text, SwingConstants.CENTER);	// align text in centre
	 label.setFont(font);										// set Font 
	 
	 if(text.equals(c_name)) label.setBorder(BorderFactory.createMatteBorder(0, 0, 2, 0, Color.black));
	 
	 if(fontMetrics.stringWidth(text)>this.getBoxWidth())		// label text > box width
	 {
	   char[] letters = text.toCharArray();
	   int ellipslength = fontMetrics.stringWidth(ellipsis);
	   int emptylength = fontMetrics.stringWidth(empty);
	   
	   StringBuilder shortname = new StringBuilder();
	   int i = 0;
	   // build label letter by letter 
	   while((fontMetrics.stringWidth(shortname.toString()) + ellipslength + emptylength) < this.getBoxWidth())
	   {
		 shortname.append(letters[i]);
		 i++;
	   }
	   shortname.append(ellipsis);
	   label.setText(shortname.toString());
	 }	 
	 
	 this.add(label);											// add label to box
	 this.add(Box.createHorizontalGlue());
	 this.validate();
	 this.repaint();
   }

   // increase number of methods - either by double-click or context-menu
   public void addMethods()
   {
     // add new item to Vector
	 c_methods.add((String) JOptionPane.showInputDialog(frame,
               											   "Enter method name #" + (c_methods.size()+1),
               											   "Methods",
               											   JOptionPane.PLAIN_MESSAGE,
               											   null,
               											   null,
               											   "Enter the new method name here..."));
	 // add new label to box
     this.addLabel((String)c_methods.lastElement(),this.methodMetrics,this.methodName);
     // increase number of methods in status panel (and underlying document)
     document.incrementMethod((String) c_methods.lastElement(),spanel);
   }
   
   public void resize()		// called from context-menu only
   {
	 //dialog for new width
	 String widthStr = (String) JOptionPane.showInputDialog(frame,
             											 "What is the new width of your box?",
             											 "Resize",
             											 JOptionPane.PLAIN_MESSAGE,
             											 null,
             											 null,
	 													 "");
	 // cast Integer from String
	 Integer width = new Integer(widthStr);
	 
	 //dialog for new height
	 String heightStr = (String) JOptionPane.showInputDialog(frame,
				 											 "What is the new height of your box?",
				 											 "Resize",
				 											 JOptionPane.PLAIN_MESSAGE,
				 											 null,
				 											 null,
				 											 "");
	 // cast Integer from String
	 Integer height = new Integer(heightStr);
	 
	 this.setBoxWidth(width);
	 this.setBoxHeight(height);
	 
	 this.setSize(width,height);
	 this.validate();
   }
   
   // mouseListener + mouseMotionListener
   public void mousePressed(MouseEvent evt)
   {
	 if(State.enable == false)
	 {
	   this.setBorder(BorderFactory.createLineBorder(Color.red,2));
	 }
	 else
	 {
	   this.setBorder(BorderFactory.createLineBorder(Color.blue,2));
	 }
	 
	 dragFromX = evt.getX() - this.getX1coord();			// calculate dragSource - X
	 dragFromY = evt.getY() - this.getY1coord();			// calculate dragSource - Y
	 canDrag = true;
   }
   
   public void mouseDragged(MouseEvent evt)
   {
	 int x = evt.getX() - dragFromX;
	 int y = evt.getY() - dragFromY; 							// top of box off screen
	 if(canDrag)
     {
	   this.setCoordP(x,y);
	   // set new coordinates of box after converting 
	   this.setLocation(SwingUtilities.convertPoint(this,this.getX1coord(),this.getY1coord(),mpanel));
     }
   }
   
   public void mouseClicked(MouseEvent evt) 
   {
	 this.requestFocus();												// focus on box
	 if(evt.getClickCount() == 2) this.addMethods();					// detect double-click
	 
	 if(State.enable == false)
	 {
	   this.setBorder(BorderFactory.createLineBorder(Color.red,2));
	 }
	 else
	 {
	   this.setBorder(BorderFactory.createLineBorder(Color.blue,2));
	 }
	 
	 // if arrow created - box might be either source or destination of arrow
	 try
	 {
	   // State = 0: arrow initiated, no source set
	   if(State.getInstance().getState() == 0)
       {
		 frame.getActiveArrow().setCurrent(this);			// set current box as source
  	     State.getInstance().changeState(State.TRANS_2);	// change state to "source identified"
  	     return;
       }
	   // State = 1: source set, no destination
       if(State.getInstance().getState() == 1)
       {
    	 frame.getActiveArrow().setConnect(this,spanel);	// set current box as destination
  	     State.getInstance().changeState(State.TRANS_3);	// change state to "both source & dest. identified"
  	     return;
       }
	 }
	 catch(NullPointerException npe)	// no arrow instance was created
	 {
	   return;	
	 }
   }
   
   public void mouseReleased(MouseEvent evt) 
   {
	 this.setBorder(BorderFactory.createLineBorder(Color.black,1));	// remove highlight   
	 if(evt.isPopupTrigger()) 										// mouse click = right
	 {
	   popmen = new ContextMenu(this);		
	   popmen.show(evt.getComponent(),evt.getX(),evt.getY());		// show context menu
	 }
	 // Point classbox = this.getLocation();
	 // this.setCoordP((int)classbox.getX(),(int)classbox.getY());
   }
   
   public void mouseEntered(MouseEvent evt) {}
   
   public void mouseExited(MouseEvent evt) {}
   
   public void mouseMoved(MouseEvent evt) {}
   
   // focusListener
   public void focusGained(FocusEvent evt)
   {
     if(State.enable == false)
	 {
	   this.setBorder(BorderFactory.createLineBorder(Color.red,2));
	 }
	 else
	 {
	   this.setBorder(BorderFactory.createLineBorder(Color.blue,2));
     }
   }
   
   public void focusLost(FocusEvent evt)
   {
	 this.setBorder(BorderFactory.createLineBorder(Color.black,1));
   }
}

Du wolltest mehr Code... Sorry dafür, aber ist schwer nachzuvollziehen, was wichtig ist und was nicht. In paintComponent selbst wird ein zentraler Array aufgerufen, der die nötigen Werte hat um die Boxen zu zeichnen (Instanz von ClassBox und Location). Bis jetzt hat alles super funktioniert, wenn ich direkt in TickFrame in MouseReleased z.B. activeInstance.setLocation(x,y) und activeInstance.setSize(x,y) aufgerufen hab. Das ganze muss ich aber zentral händeln, daher paintComponent. Aber wie gesagt - sie wird nicht mal aufgerufen...
 
Ok, ich habe den Code so halbwegs zum laufen gebracht - und dein Problem nicht nachvollziehen können.

Also was deine paintComponent-Methode alles machen soll... da werden Componenten irgendwo hinzugefügt, Grössen verändert... das ist alles nicht die Aufgabe einer paint-Methode. Eine paint-Methode soll zeichnen, und sonst gar nichts. Die Programmlogik hat darin nichts zu suchen :wink:

Wie gesagt, ich steige bei deinem Code nicht durch. Ich finde ihn nur *seltsam* :wink: (persönlich würde ich versuchen, mehr Struktur reinzubringen. Dass klar ist, wer für was verantwortlich ist. Was diese arme Frame-Klasse nicht alles abarbeiten muss... das könnte man locker in 5 Klassen aufteilen :wink: Wenn das aber aufgeteilt ist, wird es eher richtig funktionieren)
 
Ja, hab ich mir auch gedacht. Deshalb hab ich ihn nochmal auseinander genommen und neu organisiert...(z.B. gibt es jetzt eine Klasse ClassBox für In-&Output, und eine Klasse ClassBoxModel für sämtliche Daten etc. - ganz nach MVC-Standard... 🙂 ) aber jetzt werden die Label nicht gezeichnet und das Skurile ist, wenn ich die Box anklicke, springt sie an eine andere Stelle im Screen, die Label werden gezeichnet und die Größe passt sich den Label an...zu bemerken ist, dass auf Component.getLocation() und Component.getSize() immer noch die gleichen Werte ausgegeben werden wie vor dem "Sprung"... ??!?

Code:
package editor2;

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

public class ClassBox extends JPanel {
	// ClassBox = delegate for rectangular Components on screen
	// implement Mouse & MouseMotionListener
	// can just be instantiated from ClassBoxModel to have data to be displayed
	// needs to overwrite paintComponent()
	
	private JPanel draw;
	private ClassBoxModel cbm;
	private JPanel status;
	private Document doc;
	
	public ClassBox() {
		
	};
	
	protected ClassBox(ClassBoxModel classBoxModel, JPanel tickFrameMainPanel, JPanel tickFrameStatusPanel, 
Document doc) {
		cbm = classBoxModel;
		draw = tickFrameMainPanel;
		status = tickFrameStatusPanel;
		this.doc = doc;
		
		this.setLocation(50,50);
		this.setBorder(BorderFactory.createLineBorder(Color.black,1));
		this.setBackground(Color.white);
		this.setSize(cbm.getInitial());
		this.addLabel(cbm.getClassName(),cbm.getClassMetrics(),cbm.getClassFont());
		for(int i=0;i<cbm.getClassMethods().size();i++) {
			this.addLabel((String)cbm.getClassMethods().get(i),cbm.getMethodMetrics(),cbm.getMethodFont());
		}
		this.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent evt) {
				mouseClickedEvent(evt);
			}
			public void mouseReleased(MouseEvent evt) {
				mouseReleasedEvent(evt);
			}
		});
		draw.add(this);	
		doc.incrementClass(status);
	}
	
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
	}
	
	public void addLabel(String text, FontMetrics fontMetrics, Font font) {
		JLabel label = new JLabel(text);
		label.setFont(font);
		if(text.equals(cbm.getClassName()))
			label.setBorder(BorderFactory.createMatteBorder(0,0,2,0,Color.BLACK));
		if(fontMetrics.stringWidth(text)>cbm.getSize().getWidth()) {
			char[] letters = text.toCharArray();
			int ellipslength = fontMetrics.stringWidth(cbm.getEllipsis());
			int emptylength = fontMetrics.stringWidth(cbm.getEmpty());
			StringBuilder shortname = new StringBuilder();
			int i = 0;
			while((fontMetrics.stringWidth(shortname.toString()) + ellipslength + emptylength) < 
cbm.getSize().getWidth()) {
				shortname.append(letters[i]);
				i++;
			}
			shortname.append(cbm.getEllipsis());
			label.setText(shortname.toString());
		}
		this.add(label);
	}
	
	public void mouseClickedEvent(MouseEvent evt) {
		this.requestFocus();
		if(evt.getClickCount() == 2)
			cbm.addMethod();
                this.setBorder(BorderFactory.createLineBorder(Color.RED,2));
	}
	
	public void mouseReleasedEvent(MouseEvent evt) {
		if(evt.isPopupTrigger()) {
			ContextMenu popmen = new ContextMenu(cbm);
			popmen.show(evt.getComponent(),evt.getX(),evt.getY());
		}
	}
}

Dateneingabe erfolgt über ClassBoxModel. Irgendwelche Vorschläge, warum es scheitert?
 
Rufst du irgendwo mal selbst die paint-Methode eines Panels oder sonst einer Component auf? Weil das Verhalten, dass eine Component rumspringt, kann passieren, wenn man eine paint-Methode (paint, nicht paintComponent) überschreibt und dann anderen aufruft.

Instanzen von ClassBox dürften noch einen LayoutManager gesetzt haben. Das wird ein BorderLayout sein, da musst du bei jeder Component angeben, wo genau sie hin soll "add( component, BorderLayout.XXX )". Oder du setzt einen anderen LayoutManager.
 
Ich hab im Prinzip eine zweite Klasse mit nem JPanel (NullLayout) in welches die Boxen reingezeichnet werden. Der Aufruf erfolgt über einen Button, und ja, da ist ein anderes paint()...

Code:
private void ButtonActionPerformed(ActionEvent evt) {
        Object source = evt.getSource();
        if(source == addClassButton)
        {
        	try {
        		ClassBoxModel cbmodel = new ClassBoxModel(TickFrame.this,mainPanel,statusPanel,doc);
        	}
        	catch(java.lang.IllegalArgumentException iae) {
        		JOptionPane.showMessageDialog(this,"Class couldn't be created");
        	}
        	this.paint(getGraphics());
        }    
        if(source == addArrowButton)
        	System.out.println("Add Arrow");
    }

Wenn ich das auskommentiere, dann springt die Box nicht, sondern erscheint gleich am "Zielort", der aber nicht mit dem übereinstimmt, was über setLocation definiert wird. Noch stimmt die Größe mit dem überein, was ich als Rückgabe von getSize bekomme...?
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben