Swing paintComponent, JPanel auslagern, ChangeEvents

keinguru

Mitglied
Hi,
ich bin im Begriff, mein Verständnis der GUI-Programmierung zu vertiefen, und versuche in diesem Zusammenhang, innere oder anonyme Klassen explizit zu machen.
Ich habe im folgenden 3 Klassen (jeweils in separaten Dateien):
DynaGeraden - der Einstiegspunkt
MyPanel - die GUI
GPanel - ein JPanel; der Versuch, die Zeichenfläche auszulagern

DynaGeraden funktioniert in Verbindung mit MyPanel wunderbar.
Meine Frage:
Warum funktioniert
Java:
graphPanel = new GPanel(breite, hoehe, A,B, xmin, xmax,  ymin, ymax,  a, b) ;
(unten Zeile 83 versus Zeilen 85ff ) in Verbindung mit der Klasse GPanel nicht? Wie kann ich die anonyme Klasse aus Zeile 85ff auslagern?
Nochmal anders gefragt: Warum wird in der Version mit
Java:
graphPanel = new GPanel(breite, hoehe, A,B, xmin, xmax,  ymin, ymax,  a, b) ;
das innere Panel nicht von den ChangeEvents erreicht?
Wie gesagt, es geht nicht um die Frage, ob das performant oder sinnvoll ist, ich will nur verstehen, warum es (nicht) funktioniert.

Danke, Steffen.

Java:
//////////////// DynaGeraden.java
import java.awt.EventQueue;
import javax.swing.JFrame;
public class DynaGeraden 
{
    public static void main(String[] args) 
    {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() 
            {
                JFrame frame = new JFrame("Gerade");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new MyPanel());
                frame.pack();
                frame.setVisible(true);
            }
        });
    }//main
}//class


/////////////////// MyPanel.java

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;


@SuppressWarnings("serial")
class MyPanel extends JPanel implements ChangeListener
{
	static int breite= 1400;
    static int hoehe  = 700;
    static int A =  1;
    static int B =  1;
    static double xmin = -10;
    static double xmax =  10;
    static double ymin = -15;
    static double ymax =  15;
    double a, b;

    private Box controls;
    private JPanel graphPanel;
    private JSlider aSlider, bSlider;
    private JLabel aLabel, bLabel;

	public MyPanel() 
    {

    	aSlider=new JSlider(JSlider.HORIZONTAL, -100, 100, 1);
        aSlider.setPaintTicks(true);
        aSlider.setMajorTickSpacing(50);
        aSlider.setMinorTickSpacing(25);
        aSlider.setPaintLabels(true);
    	
    	bSlider=new JSlider(JSlider.HORIZONTAL, -100, 100, 1);
        bSlider.setPaintTicks(true);
        bSlider.setMajorTickSpacing(50);
        bSlider.setMinorTickSpacing(25);
        bSlider.setPaintLabels(true);

        
        aLabel = new JLabel("a");
        bLabel = new JLabel("b");

        controls = new Box(BoxLayout.Y_AXIS);

        controls.add(aLabel);
        controls.add(aSlider);
        
        controls.add(bLabel);
        controls.add(bSlider);
        
        //graphPanel = new GPanel(breite, hoehe, A,B, xmin, xmax,  ymin, ymax,  a, b) ;
  
        graphPanel=new JPanel()
        {
            public Dimension getPreferredSize() 
            {
                return new Dimension(breite, hoehe);
            }

            public void paintComponent(Graphics g) 
            {
               super.paintComponent(g);

            	   // X-Achse
            	   g.drawLine(0, (int) ((ymax) * hoehe / (ymax - ymin)), breite,(int) ((ymax) * hoehe / (ymax - ymin)));
            	   // y-Achse
            	   g.drawLine((int)(-xmin*breite/(xmax-xmin)),0,(int)(-xmin*breite/(xmax-xmin)),hoehe);
             
                    for(int i=0;i<breite;i++)
             		 {
             			 double x=(xmax-xmin)*i/breite+xmin;
             			 double y=a*x+b;
             			 int v1=(int)((ymax-y)*hoehe/(ymax-ymin) );
             			 g.fillOval(i, v1, 5, 5);
             		 }//for
            }//paintComponent
        };
        
        graphPanel.setBackground(Color.white);

        add(graphPanel);
        add(controls);
        
        aSlider.addChangeListener(this);
        bSlider.addChangeListener(this);

        this.stateChanged(null);
    }//Konstruktor MyPanel

        @Override
        public void stateChanged(ChangeEvent event) 
        {
            a = aSlider.getValue();
            b = bSlider.getValue();
            aLabel.setText("a: " + a);
            bLabel.setText("b: " + b);
            graphPanel.repaint();
            // oder:
            //repaint();
        }
}//class MyPanel


/////////////////////// GPanel.java
import java.awt.Dimension;
import java.awt.Graphics;

import javax.swing.JPanel;

@SuppressWarnings("serial")
public class GPanel extends JPanel
{
	int breite;
    int hoehe ;
    int A;
    int B;
    double xmin;
    double xmax;
    double ymin;
    double ymax;
    double a, b;
    
    
    GPanel(int breite, int hoehe, int A, int B, double xmin, double xmax, double ymin, double ymax, double a, double b)
    {
    	this.breite=breite;
    	this.hoehe=hoehe;
    	this.A=A;
    	this.B=B;
    	this.xmin=xmin;
    	this.xmax=xmax;
    	this.ymin=ymin;
    	this.ymax=ymax;
    	this.a=a;
    	this.b=b;
    }
    
    @Override
    public Dimension getPreferredSize() 
    {
        return new Dimension(breite, hoehe);
    }

    @Override
    public void paintComponent(Graphics g) 
    {
       super.paintComponent(g);

    	   // X-Achse
    	   g.drawLine(0, (int) ((ymax) * hoehe / (ymax - ymin)), breite,(int) ((ymax) * hoehe / (ymax - ymin)));
    	   // y-Achse
    	   g.drawLine((int)(-xmin*breite/(xmax-xmin)),0,(int)(-xmin*breite/(xmax-xmin)),hoehe);
     
            for(int i=0;i<breite;i++)
     		 {
     			 double x=(xmax-xmin)*i/breite+xmin;
     			 double y=a*x+b;
     			 int v1=(int)((ymax-y)*hoehe/(ymax-ymin) );
     			 g.fillOval(i, v1, 5, 5);
     		 }//for
    }//paintComponent
	
}// class GPanel
 
Zuletzt bearbeitet:
In der stateChanged-Methode setzt du einfach nur den Text von zwei JLabels. Die inneren panels sind weder als ChangeListener auf den JSlidern registiert, noch greifen sie auf die JSlider oder die JLabels zu.
Von daher verstehe ich den Sinn der Frage "Warum wird das innere panel von den ChangeEvents nicht erreicht?" nicht. Auf welchem Wege sollten denn deiner Meinung nach die Events dort ankommen?
 
stateChanged verändert die werte der variablen a und b von MyPanel. Von diesen Änderungen bekommt die Klasse GPanel aber nichts mit, da nur einmal ein GPanel Objekt mit ihnen erzeugt wird. Das ist so, weil es sich zum einen um einen primitiven Datentyp handelt (int) und zum anderen weil Java auch bei Referenzen kein direktes Call by Reference kennt. Man könnte sich behelfen indem man eine Wrapper Klasse schreibt, die einen int (oder auch gleich beide) hat und so per getter/setter zugänglich ist. Ein Objekt davon könnte die variablen a und b ersetzen. Dieses Objekt könnte dann auch an GPanel übergeben werden.
 
@VfL_Freak 09:02:
Wie gesagt, das "externalisierte" GPanel ruft die paintComponent-Methode - immerhin - einmal auf, ganz abwegig kann mein Ansatz also nicht sein. Meine Frage ist halt, warum es keine ChangeEvents verarbeitet.
 
Zuletzt bearbeitet:
stateChanged verändert die werte der variablen a und b von MyPanel. [..] Man könnte sich behelfen indem man eine Wrapper Klasse schreibt, die einen int (oder auch gleich beide) hat und so per getter/setter zugänglich ist.
Ok, probiere ich.

Edit: Wunderbar, hat geklappt!! Da wäre ich nie drauf gekommen, vielen Dank!
 
Zuletzt bearbeitet:

Neue Themen


Zurück
Oben