Wie kann ich beim Button klicken Balkendiagramm zeichnen?

Hallo Leute,

ich möchte mein Code auf 2 Arte schreiben

  1. Ich möchte dass wenn ich auf Button klicke möchte ich dass Diagramm in dem Ort aufscheint wo p_unten sein soll.
    Was soll ich dazu in meine Codes ändern?

  2. Wenn ich auf Button klicke möchte ich dass Diagramm in neues Fenster öffnet ? Natürlich muss ich p_unten in Test.java löschen.

Wie soll ich Instanz von Klasse Balkendiagramm nützen?

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

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


public class Test extends JFrame {

	JLabel l1;
	JButton b1;
	double preis;
	
	Balkendiagramm malflaeche = new Balkendiagramm();

	public Test() {
		JPanel p_oben = new JPanel();

		JPanel p_mitte = new JPanel();
		
		JPanel p_unten = new JPanel();

		GridLayout layfenster = new GridLayout(4, 1);

		l1 = new JLabel("Klicken um Diagramm anzuzeigen");
		p_oben.add(l1);

		b1 = new JButton("OK");
		p_mitte.add(b1);

		setLayout(layfenster);
		add(p_oben);

		add(p_mitte);
		
		
		
		add(p_unten);
		

		b1.addActionListener(new CLauscher());
	}

	class CLauscher implements ActionListener {
		public void actionPerformed(ActionEvent e) {
			String s;
			System.out.println("Test-3333--------");
			s = e.getActionCommand();

			if (s.equals("OK")) {

				System.out.println("Test---------");
				
			}

		}

	}

	public static void main(String[] args) {

		Test a = new Test();
		a.setSize(300, 500);
		a.setVisible(true);
		a.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	}

}

import java.awt.*;
import java.awt.event.*;

public class Balkendiagramm extends JFrame {
	MeineCanvas malflaeche;

	
	String[] monat = new String[] { "Jan", "Feb", "M‰rz", "April", "Mai",
			"Juni", "Juli", "Aug", "Sept", "Okt", "Nov", "Dez" };
	int[] h = new int[] { 150, 170, 140, 100, 15, 0, 30, 50, 100, 135, 160, 200 };

	Balkendiagramm() {

		malflaeche = new MeineCanvas();
		JPanel p = new JPanel();
		p.setLayout(new FlowLayout());

		add(malflaeche);

	}

	class MeineCanvas extends Canvas {
		MeineCanvas() {
			setBackground(Color.BLACK);
		}

		public void paint(Graphics g) {
			
				int x = 10;
				int b = 10;
				g.setColor(Color.red);
				g.drawLine(5, 20, 5, 250);
				g.drawLine(5, 250, 600, 250);
			
				for (int i = 0; i < 12; i++) {
					int rot = (int) (Math.random() * 256);
					int gruen = (int) (Math.random() * 256);
					int blau = (int) (Math.random() * 256);
					g.setColor(new Color(rot, gruen, blau));

					g.fillRect(x, 250 - h**, b, h**);

					g.drawString(monat**, x, 260);
					x = x + 50;
				}

			

		}

	}

	public static void main(String args[]) {
		Balkendiagramm z = new Balkendiagramm();
		z.pack();
		z.setSize(800, 350);
		z.setVisible(true);
		z.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	}
}```

Auf eure Hilfe wurde ich mich sehr freuen
LG Anni

zu Swing besser nur Swing hinzufügen, nicht AWT-Canvas:

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

Klassenname nun natürlich nicht mehr passend, ‘Meine’ ist ja eh aussagelos

ein JFrame selber läßt sich nicht woanders einfügen, besser trennen, nur MeineCanvas-Objekt erzeugen,

wenn überhaupt dann ist es fatal schlechte Wahl, das Balkendiagramm-Objekt ein einer Variablen malflaeche abzulegen,
denn so heißt ja schon das Attribut für MeineCanvas innerhalb Balkendiagramm,
man könnte malflaeche.malflaeche schreiben, immer vermeiden

im ActionListener muss nicht ganz fern aller einfachen Versuche ein MeineCanvas-Objekt in p_unten hinein,
dafür muss p_unten ein Attribut sein, keine hier unkannte lokale Variable des Konstruktors

nach dem Einfügen TestF.this.validate(); um Layout neu zu sortieren, repaint notfalls ebenso,

schließlich noch die Frage wie sich MeineCanvas in p_unten einfügt, mit
p_unten.setLayout(new BorderLayout());
hast du vorerst eine Sorglos-Lösung, damit wird jede (nur eine) eingefügte Komponente maximiert dargestellt

viel ist das Maximum freilich nicht, reicht bei mir nicht um gesamten Inhalt von MeineCanvas anzuzeigen,
dort ist ja alles mit absoluten Werten gelöst, kein Zoom möglich,

mehr Platz im Test-JFrame gewünscht? dann nicht GridLayout, puh…


ein zweites JFrame zu öffnen sollte nicht schwer sein,
man kann sogar Balkendiagramm.main(null); im ActionListener aufrufen,

für die eigene Instanz wären freilich nur ein Teil der Befehle zu wiederholen,
kannst ja noch eine Methode schreiben die sowohl im ActionListener als auch in der main-Methode (falls noch benötigt) aufgerufen wird,
alles bis auf setVisible(true) könnte auch in Konstruktor von Balkendiagramm

Von wo geht eigentlich die Verwendung des Namens “Lauscher” für Listener aus?
zu deiner Frage, Balkendiagramm darf kein JFrame sein, sondern ein JPanel. Dann kannst du es deine p_unten hinzufügen.

das ist doch noch eine Eindeutschung im korrekten Rahmen und praktischerweise ähnliches Wort, etwa gleich lang und mit L, super,
ist mir beim Durchgehen gar nicht aufgefallen :wink:

‚java swing lauscher‘ findet auch manches in Suchmaschinen

nicht so sehr rein spitzfindische (Kritik-?)postings, könnte zu viel werden

Danke für dein Aufwand und viel Erklärung. Leider habe ich nicht so viel verstanden, aber am meistens interessiert mich diese Zeilen . was du damit gemeint hast

[quote=SlaterB]wenn überhaupt dann ist es fatal schlechte Wahl, das Balkendiagramm-Objekt ein einer Variablen malflaeche abzulegen,
denn so heißt ja schon das Attribut für MeineCanvas innerhalb Balkendiagramm,
man könnte malflaeche.malflaeche schreiben, immer vermeiden[/quote]

ich habe nach dem Unterschied Zwischen JPanel und JFrame gegoogelt und bin ich darauf angestossen dass JPanel mehr Funktionen hat. Soll ich immer in der Zukunft Kalssenname extends JPanel machen? Liege ich richtig daran dass man JPanel nicht initialisieren kann und deswegen im Hauptprogramm soll man so machen?

Klassenname Instanz = new Klassenname();
frame.getContentPane().add(Instanz);   ```

du verwendest doch schon JFrame als das was man nirgendwo einfügt sondern für sich anzeigt,
du verwendest doch schon JPanel als das was man für sich angezeigt sondern irgendwo einfügt,
wie kann dieser Unterschied nicht klar sein?

Canvas ist sowas ähnliches wie JPanel, hast du ja alles schon,
nur noch zu beachten dass Canvas alt ist, JPanel neuere Version für deine Zwecke, grob gesprochen, kann auch zeichnen
(AWT vs. Swing falls dir das was sagt oder du wieder nachschauen willst…)


den zitierten Text-Abschnitt einfach vergessen, ne schnippische Kleinigkeit
und wenn man erst darüber diskutieren müsste dann endgültig kaputtgeredet

nur noch eine Frage und dann lasse ich dich in Ruhe malflaeche.repaint(); wird immer in Konstruktor ausgeführt und das ist immer notwendig oder? nehmen wir an dass wir Methode actionPerformed(ActionEvent e) haben. wird malflaeche.repaint() in der Methode oder Konstruktor aufgerufen?

repaint(); muss immer dann aufgerufen werden wenn du willst, dass sich dein Diagramm neuzeichnet. Im Konstruktor hat das in der Regel nichts zu suchen.

für bessere Übersicht habe ich Klassen getrennt

class MeineCanvas extends JPanel {

	String[] monat = new String[] { "Jan", "Feb", "M‰rz", "April", "Mai",
			"Juni", "Juli", "Aug", "Sept", "Okt", "Nov", "Dez" };
	int[] h = new int[] { 150, 170, 140, 100, 15, 0, 30, 50, 100, 135, 160, 200 };

	MeineCanvas() {
		// setBackground(Color.black);
	}

	@Override
	protected void paintComponent(Graphics g) {
		// TODO Auto-generated method stub
		super.paintComponent(g);
		int x = 10;
		int b = 10;
		g.setColor(Color.red);
		g.drawLine(5, 20, 5, 250);
		g.drawLine(5, 250, 600, 250);

		for (int i = 0; i < 12; i++) {
			int rot = (int) (Math.random() * 256);
			int gruen = (int) (Math.random() * 256);
			int blau = (int) (Math.random() * 256);
			g.setColor(new Color(rot, gruen, blau));

			g.fillRect(x, 250 - h**, b, h**);

			g.drawString(monat**, x, 260);
			x = x + 50;
		}
		//repaint();

	}
}

import java.awt.*;
import java.awt.event.*;

public class Balkendiagramm {

	Balkendiagramm() {

	}

	public static void main(String args[]) {
		JFrame frame = new JFrame();

		MeineCanvas z = new MeineCanvas();
		z.setBackground(Color.black);

		// frame.setBackground(Color.black);
		frame.pack();
		frame.getContentPane().add(z);

		frame.setSize(800, 350);

		frame.setVisible(true);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	}
}```

wenn ich repaint(); in der Methode paintComponent(Graphics g)  aufrufe blinken ganze Zeit die Balkens dabei wird doch einmal aufgerufen und nicht in der endlosschleife ist. Woran liegt das?
normalerweise soll man in der Hauptprogramm frame.repaint() aufrufen? Ich frage nur deswegen weil ich Visuell zwischen  z.repaint() und  frame.repaint() nichts sehe. aber da frame darstellt denke ich dass es logisch ist , dass man drauf repaint() macht oder was man einfügt soll man drauf repaint() machen ?

was passiert oder könnte passieren, wenn in paintComponent() repaint() aufgerufen ist,
was ist die naheliegende Folge? -> dass wirklich repainted wird, ergo paintComponent() nochmal drankommt,
was steht dort drin? wieder ein repaint()-Aufruf, dann wieder paintComponent() usw.,
-> Endlosschleife, Problem

nicht besonders verwunderlich, oder?
vielleicht hast du anderes darunter vermutet, repaint() an den Monitor oder so, nun gut,

dann sei gesagt dass dazu nichts zu steuern ist,
repaint()s Aufgabe ist den Swing-Ablauf mit paintComponent() zu erzwingen,
in paintComponent() ist dafür der schlechteste und auch überflüssigste Platz,
denn wenn die Methode dran kommt wird ja gerade schon gezeichnet

in anderen Methoden, insbesondere da wo die GUI geändert wird, etwas besser,
einfacher Gedanke: wenn man was hinzufügt, dann noch (falls nicht schon automatisch, was auch schön wäre) dafür sorgen dass das auch gleich mal gezeichnet wird,
kann auch sein dass es automatisch passiert, in meinen Posting nur mit evtl. gekennzeichnet

validate() ist für Neuberechnung des Layouts, und schon etwas zwingender, obwohl eigentlich auch automatisch wünschenswert,
sicher ist die Lage auch da nicht

ob alles nur auf einzelne neue Komponenten oder eine Stufe sicherer auf die sie umgebende Komponente oder umfassend auf ganze JFrames aufgerufen sind dazu Details, zu denen ich mich eigentlich lieber nicht zu genau äußern möchte,
im Zweifel alles ausprobieren…


noch ein Kommentar, obwohl ich sie mir vielleicht besser einsparen sollte:
ein pack()-Befehl für JFrame ist maximal nach Einfügen aller Komponenten brauchbar, und macht dann die Größe klein, gepackt,
steht einem setSize()-Befehl ziemlich entgegen,
es sei denn du siehst doch nützliche Effekte in der (Doppel-)Anwendung, man weiß ja nie was so alles drin ist in Swing

[quote=SlaterB]was passiert oder könnte passieren, wenn in paintComponent() repaint() aufgerufen ist,
was ist die naheliegende Folge? -> dass wirklich repainted wird, ergo paintComponent() nochmal drankommt,
was steht dort drin? wieder ein repaint()-Aufruf, dann wieder paintComponent() usw.,
-> Endlosschleife, Problem[/quote]

danke. du bist echt Klasse

Zu pack() und setSize() ist anzumerken, dass dies wenig Sinn macht. Und erst recht nicht in dieser Reihenfolge.

Was sinnvoller ist, ist ein Aufruf von setPreferedSize() oder setMinimumSize() und am Ende wenn wirklich alles hinzugefügt wurde ein Aufruf von pack().