actionPerformed() zur richtigen Zeit

f10

Aktives Mitglied
Hallo zusammen,

ich hänge gerade fest. Entweder hab ich einen gewaltigen Denkfehler oder ich sehe den Wald vor lauter Bäumen nicht.

Ich habe mir eine Klasse geschrieben, die ein JPanel erstellt und darauf ein BufferedImage zeichnet. Nun wollte ich das auf einem JFrame ausgeben. Funktioniert. Gut, jetzt will ich das Ganze aber dynamisch machen und von Textfeldern Werte einlesen, die dann anhand der Konstruktoraufrufe ein neues Bild zeichnen und dieses möchte ich dann als JPanel auf das JFrame setzen.

Java:
/* Hier steht unbedeutender Code */


pnlCenter = new JPanel();
frame.add(pnlCenter, BorderLayout.CENTER);

JButton btn = new JButton("Fire");
btn.addActionListener(ae -> chartify());
btn.setPreferredSize(new Dimension(0,25));
frame.add(btn, BorderLayout.SOUTH);

/* hier endet die Methode (eine Art initComponents()) */

private void chartify(){

  chart = OwnChart(300, 200, 20, 70, 10, "Ananas", "Birne", "Apfel");
  pnlCenter = chart.getPanel();
  frame.repaint();

}

OwnChart ist meine Klasse, die das Bild auf das JPanel malt.

Kann mir jemand erklären, warum nichts passiert, wenn ich den Button druecke?

Theoretisch muesste doch pnlCenter das JPanel von chart referenzieren und mit der repaint()-Methode vom frame muesste doch dann auch das JPanel neu gezeichnet werden und ich muesste das Bild sehen, oder nicht?

LG
f10
 
Nicht ganz. Java hat in dem Sinne kein Call by Reference. Hier belegst du zwar die variable pnlCenter neu, das JFrame bekommt davon aber nichts mit.
Um das ganze ans Laufen zu bringen müsstest du sowas in der Art machen:

Code:
frame.remove(pnlCenter); //ich glaube das könnte man sich sparen. das erneute frame.add() müsste das alte Panel sowieso ersetzen...
pnlCenter = chart.getPanel();
frame.add(pnlCenter, BorderLayout.CENTER);
frame.repaint();
 
Nicht ganz. Java hat in dem Sinne kein Call by Reference. Hier belegst du zwar die variable pnlCenter neu, das JFrame bekommt davon aber nichts mit.
Um das ganze ans Laufen zu bringen müsstest du sowas in der Art machen:

Code:
frame.remove(pnlCenter); //ich glaube das könnte man sich sparen. das erneute frame.add() müsste das alte Panel sowieso ersetzen...
pnlCenter = chart.getPanel();
frame.add(pnlCenter, BorderLayout.CENTER);
frame.repaint();

Ohne das remove() hatte ich es so auch schon versucht, aber selbst mit remove() ändert sich an der Situation nichts. Druecke ich den Knopf, passiert nichts.

Ich hab das schnell runtergebrochen aufs Wesentliche:

Chart.java

Java:
package mychart;

import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class Chart {

    JPanel pnl;
    int chartWidth, chartHeight, val1, val2, val3;
    String text1, text2, text3;
    MyPanel panel;

    public Chart(int chartWidth, int chartHeight, int val1, int val2, int val3, String text1, String text2,
            String text3) {
        this.chartWidth = chartWidth;
        this.chartHeight = chartHeight;
        this.val1 = val1;
        this.val2 = val2;
        this.val3 = val3;
        this.text1 = text1;
        this.text2 = text2;
        this.text3 = text3;
        initComponents();
    }

    private void initComponents() {
        pnl = new JPanel();
        pnl.setLayout(new BorderLayout());

        URL location = null;
        try {
            location = new URL("https://chart.apis.google.com/chart?cht=p&chs=" + this.chartWidth + "x"
                    + this.chartHeight + "&chd=t:" + this.val1 + "," + this.val2 + "," + this.val3 + "&chl="
                    + this.text1 + "|" + this.text2 + "|" + this.text3);
        } catch (MalformedURLException e) {
            System.out.println(e.getMessage());
        }
        BufferedImage img = null;
        try {
            img = ImageIO.read(location);
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }

        this.panel = new MyPanel(img);
        pnl.add(panel, BorderLayout.CENTER);

    }

    public MyPanel getPanel() {
        return panel;
    }

    public JPanel getPnl() {
        return pnl;
    }

    public class MyPanel extends JPanel {
        BufferedImage img;

        public MyPanel(BufferedImage img) {
            this.img = img;
        }

        @Override
        public void paint(Graphics g) {
            Graphics2D g2d = (Graphics2D) g;
            super.paint(g2d);

            g2d.drawImage(img, null, 0, 0);

        }

    }
}

und die App.java:

Java:
import java.awt.BorderLayout;
import java.awt.Dimension;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class App extends JFrame {
    JFrame frame;
    JPanel pnlCenter;
    JButton btn;
    private Chart gooc;

    public static void main(String[] args) {
        new App();

    }

    public App() {
        initComponents();
        this.setVisible(true);
    }

    private void initComponents() {

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setLayout(new BorderLayout());
        this.setSize(new Dimension(317, 335));
        this.setLocationRelativeTo(null);

        pnlCenter = new JPanel();
        this.add(pnlCenter, BorderLayout.CENTER);

        btn = new JButton("Fire");
        btn.addActionListener(ae -> chartify());
        btn.setPreferredSize(new Dimension(0, 25));
        this.add(btn, BorderLayout.SOUTH);
    }

    private void chartify() {
        this.remove(pnlCenter);
        gooc = new Chart(300, 200, 20, 70, 10, "Ananas", "Banane", "Ananas");
        pnlCenter = gooc.getPnl();
        this.add(pnlCenter, BorderLayout.CENTER);
        this.repaint();
    }
}


Wenn ich allerdings die Zeilen

Java:
gooc = new Chart(300, 200, 20, 70, 10, "Ananas", "Banane", "Ananas");
        pnlCenter = gooc.getPnl();

in der initComponents() statt dem new JPanel() aufrufe, funktioniert es. Es wird allerdings nicht neu gezeichnet, wenn ich die actionPerformed() auslöse. Woran kann das liegen?

Edit: Ich weiß, dass man nicht von JFrame erben sollte, wenn man es nicht erweitert, ich hab es nur der Schnelle halber mal kurzfristig so implementiert.
 
Ich hab mal dein Beispiel probiert und die beiden JPanel einfach durch zwei JPanels ersetzt die eine unterschiedliche Farbe haben.
Zuerst wird ein oranges angezeigt. (das setze ich in initComponents())
Beim Klick wird dann ein grünes gesetzt (in charify()).

Das erscheint aber nicht; Hintergrund wird grau...
Was hilft ist in chartify vor dem repaint() ein revalidate() auszuführen. Swing ist da manchmal etwas eigenartig.
 
Lesen kannst du das mal HIER, wie Swing und AWT zeichnet.

Repaint zeichnet die aktuelle Komponente neu.
Revalidate muss aufgerufen werden, falls sich Strukturen ändern (sprich du tauschst das JPanel aus).
 

Neue Themen


Zurück
Oben