BufferedImage -> Farbe wechselt willkürlich

Gromit

Mitglied
Hallo,

wenn ich auf ein BufferedImage zeichnen will, wechselt die Farbe willkürlich und ich habe keine Ahnung, warum. Meine Methode:

Java:
    public void paint(Graphics g) {
        if (screenImage == null) {
            screenImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
            screenGraphics = screenImage.getGraphics();
            screenGraphics.setFont(font);
        }

        if (hasTextChanged) {
            for (int i = 0, x = 0; i < chars.length; i++, x++) {
                if (x >= columns)
                    x = 0;

                int y = i / columns;

                screenGraphics.setColor(Color.YELLOW);
                screenGraphics.fillRect(x * CHAR_WIDTH, y * CHAR_HEIGHT, CHAR_WIDTH, CHAR_HEIGHT);

                screenGraphics.setColor(Color.RED); // Testweise
                screenGraphics.setColor(Color.GREEN);
                screenGraphics.drawString("A", x * CHAR_WIDTH, (y * CHAR_HEIGHT) + 10);
            }

            hasTextChanged = false;
        }

        g.drawImage(screenImage, 0, 0, null);
    }

Ergebnis ist, dass die Farbe des Hintergrundes (bzw. der einzelnen Blöcke, aus denen der Hintergrund besteht) und die Farben der einzelnen Buchstaben (drawString) zwischen Gelb, Rot und Grün wechseln. Da die Methode von einem Thread einmal pro Sekunde aufgerufen wird, wechseln unterschiedliche Buchstaben und Hintergrundblöcke jeweils einmal pro Sekunde ihre Farbe.

Nur woran liegt das?
 

Marco13

Top Contributor
Da arbeiten mehrere Threads, und painten "gleichzeitig" in ein Graphics von EINEM BufferedImage? Joa, das haut ihn raus, das ist klar. Wenn das unbedingt von mehreren Threads gemacht werden MUSS, könnte schon ein
Code:
snychronized (screenImage)
{
     for (int i = 0, x = 0; i < chars.length; i++, x++) {
      ...
}
helfen...
 

Gromit

Mitglied
Na eigentlich übergibt der Thread der Methode paint nur das eigene Graphics g, auf dann das screenImage gezeichnet wird.

Auf das screenImage hat sonst nur die Methode paint(Graphics g) Zugriff (und nur die zeichnet darauf). Insofern kann ich mir auch nicht vorstellen, dass es daran liegt. :-?

Edit: Beispiel angehangen

Edit 2: Rechtschreibung
 

Anhänge

  • Beispiel.png
    Beispiel.png
    15 KB · Aufrufe: 52
Zuletzt bearbeitet:

Marco13

Top Contributor
Hast du es ausprobiert? Das Problem ist vermutlich, dass mehrere Threads die Methode gleichzeitig ausführen, und alle dasSELBE screenImage verwenden. Der erste Thread macht
screenGraphics.setColor(Color.YELLOW);
und bevor er
screenGraphics.fillRect(x * CHAR_WIDTH, y * CHAR_HEIGHT, CHAR_WIDTH, CHAR_HEIGHT);
machen kann, pfuscht ihm ein anderer Thread mit seinem
screenGraphics.setColor(Color.RED); // Testweise
dazwischen.
 

Gromit

Mitglied
Es gibt ja nur einen Thread, der die paint-Methode aufruft.

Edit: Aber ja, du hast recht. Mit synchronized geht es. Kann man das nicht eleganter lösen? Und warum greift dieser eine Thread mehrmals parallel auf die Methode zu (obwohl der Aufruf nur einmal pro Sekunde passiert)?
 
Zuletzt bearbeitet:

Marco13

Top Contributor
Häm? ???:L Wie komm' ich eigentlich drauf, dass es mehrere Threads sind... ? (Hattest du den ersten Beitrag editiert oder so? ???:L ). Mit EINEM Thread sollte das eigentlich gehen. Es kann zwar theoretisch ein "inkonsistenter" (also halb-fertig gezeichneter) Zustand auf dem Bildschirm dargestellt werden, aber falsche Farben sollte es nicht geben. Kann man da ein KSKB basteln?
 

Gromit

Mitglied
Seltsam ist, dass es funktioniert, wenn ich screenImage erst beim Aufruf von paint erstelle:

Java:
    public void paint(Graphics g) {
        BufferedImage screenImage;
        Graphics screenGraphics;
        screenImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
        screenGraphics = screenImage.getGraphics();
        screenGraphics.setFont(font);

        if (hasTextChanged) {

           ...
 

Marco13

Top Contributor
Dort werden ja jetzt lokale Variablen angelegt (und immer neue Bilder - nicht gut). Eigentlich KANN das nur ein Threading-Problem sein ???:L
Kleines
Selbstständig
Kompilierbares
Beispiel...?
 

Gromit

Mitglied
Der Thread hat eine run-Methode:

Java:
    public void run() {
        running = true;

        while (running) {
            update();
            render(); // <--
            paintScreen();

            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                System.err.println(e);
            }
        }

        System.exit(0);
    }

Die Methode render() ruft die Methode paint des ColorConsole-Objektes auf und übergibt das Graphics, damit ColorConsole darauf zeichnen kann:

Java:
    // render-Methode des Threads
    private void render() {
        doubleBufferedGraphics.setColor(Color.BLACK);
        doubleBufferedGraphics.fillRect(0, 0, width, height);

        console.paint(doubleBufferedGraphics);    // übergebe Graphics, damit ColorConsole darauf zeichnen kann
    }

In der paint-Methode wird dann erst auf das screenImage gezeichnet und das screenImage anschließend via
Java:
g.drawImage(screenImage, 0, 0, null) // g: doubleBufferedGraphics
aufs doubleBufferedGraphics. Das ist auch schon alles.

Der Name "paint" für die Methode ist vielleicht etwas irreleitend. ColorConsole ist keine Swing- oder AWT-Komponente. Der Name "render" wäre vielleicht besser.
 

EgonOlsen

Bekanntes Mitglied
Du hast vermutlich deinen eigenen Thread und den normalen AWT Event Dispatch Thread, der das Zeichnen von Swing/AWT üblicherweise macht. Wenn du das Zeichnen unbedingt über deinen eigenen Thread machen willst, mach es über deine eigene Methode und hebel das Swing-Zeichnen aus, indem du update und paint mit leeren Implementierungen überschreibst.
 

Gromit

Mitglied
Anbei mal ein funktionierendes Minimalbeispiel.

  • io.ColorConsole: zeichnet den Text
  • lang.ColoredCharacter: eigener Datentyp; speichert char, Vorder- und Hintergrundfarbe
  • main.Main: erstellt Swing-Fenster
  • swing.ColorConsolePanel: der Thread; abgeleitet von JPanel, Runnable
 

Anhänge

  • JColorConsole.zip
    3,8 KB · Aufrufe: 5

Marco13

Top Contributor
Code:
    public void paint(Graphics g) {
        System.out.println("Start on "+Thread.currentThread());
        if (hasTextChanged) {
...
        }
        System.out.println("End on "+Thread.currentThread());
        g.drawImage(screenImage, 0, 0, null);
    }

---> :idea:

Du rufst in der main "run()" auf, UND startest einen zweiten Thread, der auch "run()" ausführt. Nur der zweite Thread sollte run() ausführen. Und er sollte definitiv NICHT in addNotify gestartet werden. Im Konstruktor, oder sonstwo, aber NICHT diese Methode überschreiben!

Also: Das run() aus der main rausnehmen, dann funzts...
 

Gromit

Mitglied
---> :idea:

Du rufst in der main "run()" auf, UND startest einen zweiten Thread, der auch "run()" ausführt. Nur der zweite Thread sollte run() ausführen. Und er sollte definitiv NICHT in addNotify gestartet werden. Im Konstruktor, oder sonstwo, aber NICHT diese Methode überschreiben!

Also: Das run() aus der main rausnehmen, dann funzts...
Uff, das hätte ich im Leben nicht gefunden. Vielen Dank erst einmal!! Hatte das run() im Main anfangs mal testweise drin und dann ganz vergessen.

Was spricht gegen addNotify? Und im Konstruktur gibt es eine NullPointerException.
 

Marco13

Top Contributor
Man sollte nicht willkürlich irgendeine Methode überschreiben und sich da einklinken (von solchen Sachen dass mehrere Threads gestartet werden, wenn man das ding merhfach irgendwo entfernt und hinzufügt mal ganz abgesehen). Wegen NPE...notfalls pragmatisch
Code:
    private void render() {
        if (doubleBufferedImage == null) {
            doubleBufferedImage = createImage(width, height);
            if (doubleBufferedImage != null)
            {
                doubleBufferedGraphics = doubleBufferedImage.getGraphics();
            }
        }
        if (doubleBufferedGraphics != null)
        {
            doubleBufferedGraphics.setColor(Color.BLACK);
            doubleBufferedGraphics.fillRect(0, 0, width, height);

            console.paint(doubleBufferedGraphics);
        }
    }

Ich seh grad, da steht ja DOCH ein getGraphics drin... das sollte man nicht verwenden. Was soll paintScreen eigentlich machen? Mach' das mal raus, ein "repaint()" aufruf stattdessen sollte es schon tun...
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
B BufferedImage Position Spiele- und Multimedia-Programmierung 8
B BufferStrategy zu BufferedImage? Irgendwie? Spiele- und Multimedia-Programmierung 2
D getsubimage aus BufferedImage und Rueckwandlung in ein ImagePlus bild Spiele- und Multimedia-Programmierung 0
V BufferedImage[] aus anderer Classe auslesen Spiele- und Multimedia-Programmierung 2
F [JMyron] Bild von int[] zu BufferedImage Spiele- und Multimedia-Programmierung 2
Q BufferedImage vs. Heap Space ‒ Warum wird der Speicher nicht freigegeben? Spiele- und Multimedia-Programmierung 6
M Performance Problem bei BufferedImage Spiele- und Multimedia-Programmierung 7
R BufferedImage > Integer.MAX_VALUE Spiele- und Multimedia-Programmierung 9
M Pixel eines BufferedImage bearbeiten (Performance) Spiele- und Multimedia-Programmierung 23
P int-Array zu BufferedImage (performance?) Spiele- und Multimedia-Programmierung 14
agentone BufferedImage transparent löschen Spiele- und Multimedia-Programmierung 12
radiac Stringtext mit BufferedImage Textur. Spiele- und Multimedia-Programmierung 6
kowa BufferedImage und Antialias Spiele- und Multimedia-Programmierung 2
T BufferedImage#setRGB #getRGB zu langsam Spiele- und Multimedia-Programmierung 4
J Zeichnen in BufferedImage und dieses in Datei speichern Spiele- und Multimedia-Programmierung 2
A Image in BufferedImage konvertieren Spiele- und Multimedia-Programmierung 2
Z Transparenz in BufferedImage Spiele- und Multimedia-Programmierung 8
Z JME - Rendering in BufferedImage Spiele- und Multimedia-Programmierung 14
A Bildbereich als BufferedImage Spiele- und Multimedia-Programmierung 3
M BufferedImage blass machen Spiele- und Multimedia-Programmierung 5
Lulumann6 BufferedImage in VolatileImage casten Spiele- und Multimedia-Programmierung 10
F BufferedImage verursacht OutOfMemoryError Spiele- und Multimedia-Programmierung 11
P Rotation von BufferedImage (Affine Transformation) Spiele- und Multimedia-Programmierung 7
S Image to BufferedImage Spiele- und Multimedia-Programmierung 3
dummycoders Android Studio - Button ändert Farbe erst nach Delay? Spiele- und Multimedia-Programmierung 5
R Problem bei Farbe ändern/4Gewinnt Spiele- und Multimedia-Programmierung 5
W Java3D: Farbe von Objekten stimmt nicht mit übergebenem RGB-Wert überein Spiele- und Multimedia-Programmierung 9
truesoul Picking und Farbe ändern Spiele- und Multimedia-Programmierung 3
F Farbe ändern bei Überlappung Spiele- und Multimedia-Programmierung 2
M g.setColor erzeugt falsche Farbe? Spiele- und Multimedia-Programmierung 5
D Text3D Farbe aendern Spiele- und Multimedia-Programmierung 2
R Transparente Farbe von (Buffered) Image Spiele- und Multimedia-Programmierung 10
E Durch Klick auf den JButton will ich die Farbe ändern? Spiele- und Multimedia-Programmierung 8
DEvent [2D] Farbe bestimmten Pixels eines Bildes ändern Spiele- und Multimedia-Programmierung 3
O transparente farbe in Image mit Graphics Spiele- und Multimedia-Programmierung 8
F QuadArray, Farbe auf beiden Seiten? Spiele- und Multimedia-Programmierung 4

Ähnliche Java Themen


Oben