JPanel ignoriert Eigenschaften völlig

Hallöle,

ich komme nun inzwischen ziemlich gut mit diesem ganzen Graphikzeuchs klar, aber manchmal bereitet mir das einfach nur Kopfschmerzen. Ich habe folgendes Problem:

Ich habe eine Klasse mit einem JPanel.
Das macht zwei Dinge:
Es hat eine Eigenschaft “Gast”. Anfangs ist diese Eigenschaft “null”. Wenn sie null ist, dann schreibt er einfach einen String in das JPanel.
Wenn ich dann mit setGast einen Gast hinzufüge, dann soll der String verschwinden und er soll ein Bildchen reinmalen.

So sieht mein Quellcode aus:


import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.image.BufferedImage;

import javax.swing.BorderFactory;
import javax.swing.JPanel;

public class Barzelle extends JPanel {
	
	private BufferedImage i;
	private int barplatznum;
	private Gastkarte gast = null;
	private String key = null;
	
	public Barzelle(int barplatznum) {
		this.barplatznum = barplatznum;
	}
	
	@Override
	protected void paintComponent(Graphics gr) {
		super.paintComponent(gr);
		
		System.out.println(gast);
		if(gast != null) {
			loadImage();
	        gr.drawImage(i, 0, 0, getWidth(), getHeight(), null);
		} else {
			Font font = new Font("Arial", Font.BOLD,16);
			FontMetrics fm = gr.getFontMetrics(font);
			this.setBackground(new Color(0x20324F));
			this.setBorder(BorderFactory.createLineBorder(Color.black));
			gr.drawString("leer",this.getWidth()/2-fm.stringWidth(num)/2,this.getHeight()/2);
		}
	}
	
	private void loadImage() {
		System.out.println(gast);
		if(gast!=null) {
			key = "./gast_"+this.gast.getLand()+"_"+this.gast.getGeschlecht()+".png";
			i = CafeMain.getStuhlcache().get(key);
			System.out.println(key);
		}
	}
	
	public void setGast(Gastkarte gast) {
		this.gast = gast;
		if(gast!=null) {
			loadImage();
		}
	}

	public Gastkarte getGast() {
		return gast;
	}
	
}```

Er malt den String, der da der Einfachheit halber einfach "leer" heißt auch brav. Das klappt.

Wenn ich dann von außerhalb die Methode `setGast` ausführe, dann wird auch brav ein Gast hinzufügt. Danach ruft er loadImage auf.
An der Stelle lasse ich mir den Gast nochmal ausgeben und die Konsole zeigt ihn mit all seinen Eigenschaften (getLand() und getGeschlecht()) an. Er ist also korrekt hinzugefügt worden. Dann lade ich das Bild, indem ich den String key mit den Eigenschaften des Gastes fülle und das Bild aus einer Treemap `i = CafeMain.getStuhlcache().get(key);` lade.

An dieser Stelle sieht man, lasse ich mir nochmal letztmalig den key ausgeben, den ich erzeugt habe. Alles vollkommen korrekt.

Aber dann beginnt das Problem:
Es geht in die paintComponent-Methode rein. Und ab da zeigt er für `System.out.println(gast);` nur noch null an. Die Konsole wirft im Millisekundentakt immer null, null, null, null, null aus. Als ob der Gast auf einmal verschwunden wäre. Demzufolge kommt er auch nie in die Funktion mit dem DrawImage rein. Niemals. 

Ich weiß nicht, was das soll.

Ich habe nun schon sehr viel mit drawImage gearbeitet, da ging es immer.

Kann mir jemand erklären, wieso das Programm sich so verhält?

Viele Grüße und Vielen Lieben Dank, wenn mir irgendwer sagen kann, was der Fehler ist.

Gruß
Lukas

Du solltest in der paintComponent()-Methode keine Bilder laden. Der loadImage()-Aufruf muss dort raus.
Stattdessen solltest du nach Aufruf von setGast() (also in der setGast()-Methode direkt nach loadImage()) ein repaint()-Aufruf starten.

ohne vollständiges Testprogramm kann man besonders bei GUI wenig sagen,
vielleicht hast du verschiedene Barzelle-Objekte erstellt, eins in dem du Gast hinzufügst, ein anderes wird ohne Gast angezeigt,

setze auch in setGast() eine Ausgabe, evtl. auch in Konstruktor,
gib bei allen Ausgaben den hashCode() aus um evtl. mehrere Objekte zu unterscheiden

poste ein vollständiges minimales Testprogramm mit JFrame, main-Methode,
auf Bild-Laden kannst du dabei auch für das Problem vorerst verzichten, nur Übergabe von String und Vorhandensein in paintComponent-Methode

Wenn key und gast korrekt ausgegeben werden, beim repaint() aber null arbeitest du definitiv mit zwei verschiedenen Objekten, wie Slater schon sagte : hashCode() mit in die Ausgabe einbauen, dann solltest du es sehen.
Ansonsten brauchen wir ein vollständiges Beispiel, bzw den Rest vom Code um dir den Fehler aufzeigen zu können. Das Stück was du gepostet hast reicht leider nicht aus.

Was auch sehr verwirrend ist ist dein static call : CafeMain.getStuhlCache().get(key) … das schreit gerade zu nach NULL.
Auch : nehm den loadImage() call aus paintComponent() raus. Sowas gehört immer in einen eigenen Thread, und dann auch nur einmal bei Änderung, nicht bei jedem repaint().
Weiter macht es mir Kopfschmerzen das er warum auch immer anstatt einmal NULL auszugeben damit garnicht mehr aufhören will, klingt für mich danach als hättest du irgendwo einen repaint() loop oder sowas drin > mehr Code.

Hallöle,

ich habe das Problem gefunden.
Peinlich peinlich, was das schon wieder für Unfug ist. Ich kann es ehrlich gesagt nicht nachvollziehen wieso, aber es geht um folgendes:
Ich verwechsel static und nicht static an vielen Stellen noch. An den Meisten Stellen ist es weg, ich versuche es wegzulassen, wo nur möglich. Aber:
In der Methode wo ich diese Barzelle (Name der Klasse) aufrufe hab ich:
Barzelle bz = new Barzelle();
Und irgendwie wiederholt und wiederholt er das immer wieder. Das heißt er ruft es immer und immer wieder auf, daher der Loop der vielen Null. Und ab dem zweiten Aufruf ist die Eigenschaft die ich gerade festgelegt habe auch null.
Wenn ich die Methode die das macht auf static setze, dann läuft es. Dann ruft er es auch nur einmal auf.

Sorry, dass ich keinen Code posten kann, habe den schon anders verarbeitet. Ich krame die Tage den Fehlerhaften Code nochmal aus meinem GitHub Profil aus, damit man das nachvollziehen kann.

Bussy
Lukas

ach, sofern das Problem gelöst ist kann da wohl jeder auch drauf verzichten :wink:

ich interpretiere dass das Thema gelöst ist und setze es entsprechend,
sonst protestieren/ weiter posten

Sir, bitte um Erlaubnis offen sprechen zu dürfen, Sir.
*scnr

@TO
Ach ja, das liebe static und alle die Grundsatzdiskusionen die darüber schon geführt wurden. Ich möchte auch keine neue lostreten, sondern lediglich meine Erfahrung weitergeben. Ich bitte auch alle anderen die sich daran beteiligen möchten in einer ähnlichen Sicht zu schreiben. Wenn wir uns darüber die Köpfe einschlagen wollen sollten wir dies wenn dann in einem eigenen Thread machen. Danke.

Grundsätzlich schreibe ich meine Codes nach der Regel : Es gibt nur genau ein static in meinen Codes : public static void main(String... args)

Aber : es wäre natürlich keine Regel wenn sie nicht ihre Ausnahmen hätte (gosh wie falsch das einfach mal nur wieder klingt). Diese sind :

  • KONSTANTEN - schon per Java Conventions als public static final und in UPPER_CASE zu deklarieren, sinnvollerweise natürlich ein primitiver Type oder immutable (in sich unveränderlich) wie z.B. String-Literale.
    Was ist das besondere an der Deklaration ? Das Keyword final legt fest das eine Variable nach ihrer Initialisierung nur auf dieses eine Objekt zeigen darf, die Speicheradresse auf die sie zeigt also nicht verändert werden darf.
    Bei primitiven Types funktioniert das deshalb da halt in der Referenz nicht der Wert selbst steht sondern die Speicheradresse wo dieser Wert zu finden ist. (Hier darf sich gerne jemand auslassen der das besser erklären kann.)
    Und warum sollte es, wenn es kein primitiver Type ist, immutable sein ? Weil es sonst wenig bringen würde eine Referenz fest an ein bestimmtes Objekt zu binden wenn sich dessen interner Zustand verändern kann. Das widerspricht irgendwie dem Wortsinn „konstant“.
    Will man sich hier das static sparen und kann es irgendwie sinnvoll gruppieren kann man auch ENUMs verwenden.

  • Factory-Methoden - ohne gehts halt manchmal einfach nicht. Wie auch ich erst kürzlich hier gelernt habe macht es Sinn wenn man z.B. im Konstruktor bestimmte Variablen braucht und diese vorher sauber auf z.B. NULL oder gültige Wertebereiche prüfen möchte. Dann macht man den Konstruktor private und setzt eine Factory-Methode davor (meist als getInstance() bezeichnet). So kann man beruhigt prüfen und ggf. entsprechende Exceptions werfen ohne das der Konstruktor angefasst wird.
    Auch kann man mit einer Factory ein Singleton bauen (Thread-synchronisation beachten !), und es mag sicher den einen oder anderen Anwedungsfall für dieses oft als Anti-Pattern genanntes Design (auch wenn ich es noch nie bewusst speziell gebraucht hätte), aber zumindest meine Factories liefern immer ein neues Objekt.

  • Utility- und Helper-Methode - hat man manchmal, da man bestimmte Codestücke mehrfach braucht, sie aber trotzdem irgendwie keiner Klasse so wirklich richtig zuordnen kann. Ich z.B. habe mitlerweile eine lange Liste an Helper-Klassen mit entsprechenden -Methoden die bei mir einfach so im Classpath rumdümpeln. Sicher, müsste ich mal wieder aufräumen, und einiges kann man sicher auch eleganter lösen. Aber statt jedes mal copy’n’paste zu machen ist es einfach auf bereits vorhandenes zurückzugreifen.
    Auch viele Libs wie dieser ganze Apache-Krams bieten viel von sowas.

Ja, mir ist auch bewusst das man diese Liste weiterführen könnte, aber das sind so meine persönlichen Top 3 bei denen ich in meinen eigenen Codes ein static „toleriere“.

Vielleicht hilft dir das ja beim nächsten mal. Oder vielleicht auch : Hinterfrage immer ob etwas wirklich static sein muss, und wenn du diese Frage mit „ja“ beantwortest, dann hinterfrage : WARUM ?

PS : Ist schon ok wenn du keinen Code postest so lange du den Fehler für dich selbst lösen konntest, aber es ist für andere Hilfesuchende eher sub-optimal. Sie stoßen vielleicht auf diesen Thread und haben vielleicht genau das gleiche Problem wie du, aber halt mangels Code einen Ansatzpunkt wo zu suchen ist.

immer das Problem bei solchen Sätzen im Auge behalten,
das ist keine komplizierte spezifische Fehlermeldung, die aus aufwendiger Kombination von 5 FAQ-Antworten aus drei Quellen konfiguratorisch gelöst werden konnte, und diese Erkenntnis nun verschwiegen,

sondern ein Allerweltsproblem das jeweils ganz anders auftritt und kaum zur Hilfe dienen kann,
nicht dass es nicht auch schon 20 andere entsprechende Threads gibt

‚hast du mehrere Objekte erzeugt?‘ ist mein 4. Vorname, Standardsatz :wink: