Frage

Für die letzten zwei Tage habe ich versucht, auf verstehen , wie Java behandelt Grafiken, aber kläglich bei nur, dass gescheitert. Mein Hauptproblem ist das Verständnis genau, wie und wann Farbe () (oder die neuere paintcomponent ()) wird / soll aufgerufen werden.

Im folgenden Code sehe ich gemacht, wenn die Dinge geschaffen, die paintcomponent () nie aufgerufen wird, es sei denn ich einen Anruf, um es selbst manuell hinzufügen oder Anrufe zu JFrame.paintAll () / JFrame.paintComponents ().

I umbenannt die Farbe () -Methode paintcomponent () in der Hoffnung, dass mein Problem beheben würde nie (auch bei repaint ()) aufgerufen wird, aber kein Glück.

package jpanelpaint;

import java.awt.*;
import javax.imageio.*;
import javax.swing.*;
import java.io.*;
import java.util.ArrayList;

public class ImageLoadTest extends JComponent {
 ArrayList<Image> list;

 public ImageLoadTest() {
  list = new ArrayList<Image>();

  try { //create the images (a deck of 4 cards)
   for(String name : createImageFileNames(4)){
    System.err.println(name);
    list.add(ImageIO.read(new File(name)));
   }
  } catch (IOException e) {  }
 }

    protected void paintComponent(Graphics g) {
     int yOffset=0;
  System.err.println("ImageLoadTest.paintComponent()");
     for(Image img : list) {
      g.drawImage(img, 0, yOffset,  null);
      yOffset+=20;
     }
    }

 public static void main(String args[]) throws InterruptedException {
  JFrame frame = new JFrame("Empty JFrame");
  frame.setSize(new Dimension(1000, 500));
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

  frame.setVisible(true);

  Thread.sleep(1000);
  frame.setTitle("Loading images");
  ImageLoadTest ilt = new ImageLoadTest();
  frame.add(ilt);
  //update the screen
  //DOESN'T WORK. only works if I call frame.paintAll(frame.getGraphics()) 
  ilt.repaint();
  frame.repaint();

  Thread.sleep(1000);
  frame.setTitle("Setting background");
  ilt.setBackground(Color.BLACK);
  //update the screen - DOESN'T WORK even if I call paintAll ..
  ilt.repaint();
  frame.repaint();

            //have to call one of these to get anything to display  
//  ilt.paintComponent(frame.getGraphics()); //works
  frame.paintComponents(frame.getGraphics()); //works
 }

 //PRIVATE HELPER FUNCTIONS

 private String[] createImageFileNames(int count){
  String[] fileNames = new String[count];
  for(int i=0; i < count; i++)
   fileNames[i] = "Cards" + File.separator + (i+1) + ".bmp";  
  return fileNames;
 }
}
War es hilfreich?

Lösung 4

Dies waren die Hauptprobleme mit dem ursprünglichen Code, der sie verursacht hat, nicht zu arbeiten:

  1. nicht Aufruf validate () nach einer add () Betrieb
  2. nicht die bevorzugte Größe der Komponente einstellen.
  3. nicht Aufruf super.paintComponent (), wenn es zwingende (dies machte die setBackground () aufrufen, funktionieren nicht)
  4. Ich brauchte von JPanel, um zu erben für sie gemalt werden. Weder Komponente noch JComponent war ausreichend für die setBackground () aufrufen, selbst zu arbeiten, wenn Befestigungspunkt 3.

die oben getan zu haben, dauerte es nicht wirklich wichtig, wenn die Methode paintcomponent oder Farbe nennen, beide schienen so lange zu arbeiten, wie ich die Super-Konstruktor zu Beginn rufen in Erinnerung hatte.

Dieses Info montiert, von welcher @jitter, @tackline und @camickr schrieb, so großes Lob!

P. S. Keine Ahnung, ob Ihre eigene Frage zu beantworten ist schlechter Stil angesehen, aber da die Informationen, die ich aus mehreren Antworten zusammengesetzt benötigt, dachte ich, der beste Weg, um die anderen Antworten wurde upmodding und eine Summe up wie diese zu schreiben.

Andere Tipps

Einer der Gründe, die paintcomponent () nicht in dem ursprünglichen Code aufgerufen erhalten ist, weil die Komponente eine „Null-Größe“ und die RepaintManger sind intelligent genug, um nicht zu versuchen und zu malen, etwas ohne Größe.

Der Grund für die Umordnung des Codes funktioniert, weil, wenn Sie die Komponente mit dem Rahmen hinzufügen und dann den Rahmen sichtbar der Layout-Manager machen wird, um die Komponente aufgerufen Layout. Standardmäßig verwendet einen Rahmen mit einem Border und ist standardmäßig eine Komponente zur Mitte des Border hinzugefügt, die den Raum alle verfügbaren auf die Komponente geschieht geben, damit es gemalt wird.

Allerdings Sie den Layout-Manager Bereich des Inhalts ändern ein Flowlayout zu sein, würden Sie immer noch ein Problem haben, weil ein Flowlayout die bevorzugte Größe der Komponente respektiert die Null ist.

Also, was Sie wirklich tun müssen, ist eine bevorzugte Größe Sie Ihre Komponente zuweisen, so Layout-Manager ihre Arbeit tun können.

Ein großes Problem hier ist, dass Sie die Aktualisierung nicht Ihre Swing-Komponenten auf dem Event Dispatch Thread (EDT) . Versuchen Sie wickeln den gesamten Code in Ihre Hauptmethode in der folgenden:

    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            // swing code here...             
        }
    });

Sie auch: Ihre ImageLoadTest den Rahmen hinzufügen, bevor der Rahmen sichtbar zu setzen. Dies basiert auf einem schnellen flüchtigen Lesen des Codes -. Ich kann es weiter lesen und sehen, was kann ich sonst noch finden

EDIT:

Folgen Sie meine ursprüngliche Beratung oben, und Ihr Hauptverfahren vereinfachen, wie die folgenden und Ihre paintcomponent suchen () aufgerufen werden:

public static void main(String args[]) throws InterruptedException {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            JFrame frame = new JFrame("Empty JFrame");
            frame.setSize(new Dimension(1000, 500));
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            PaintComponentTest ilt = new PaintComponentTest();
            frame.add(ilt);
            frame.setVisible(true);
            ilt.setBackground(Color.BLACK);
        }
    });
}

Auch würde ich lesen, Timer zur Verwendung von Animation auszuführen, sowie allgemeines Swing-Ereignis ausgelöst wird und wie / wann verschiedene Farbe Methoden außer Kraft zu setzen.

http://java.sun.com/products/jfc/ tsc / articles / Malerei /

http://java.sun.com/docs /books/tutorial/uiswing/misc/timer.html

http://java.sun.com/docs /books/tutorial/uiswing/concurrency/dispatch.html

Um Tom Hawtin - tackline glücklich. Ich schrieb noch einmal

Es gibt mehrere Dinge, die ich (überprüfen Sie die Zeilen mit dem //new Kommentar) geändert

schrieb es vollständig

  • Split in eine saubere neue Komponentendatei (ImageLoadTest.java) und eine Datei zu testen (Tester.java)

Verbesserungen auf Original-Plakate Code

  • rufen Konstruktor der Eltern in ImageLoadTest Konstruktor (super())
  • bereitgestellt zweiter Konstruktor gesetzt Liste der Bilder, die die Komponente
  • angezeigt werden sollen
  • WICHTIG: Aufruf der Komponente im Konstruktor setPreferredSize(). Wenn Größe nicht gesetzt ist Swing natürlich nicht Ihre Komponente malen. bevorzugte Größe basiert auf max. Breite aller Bilder und Summe aller Bildhöhen
  • ruft in überschriebenen super.paintComponent(g) paintComponent()
  • geändert paintComponent automatisch Basis yOffset auf Höhe der Bilder gezogen werden

  • GUI-Initialisierung auf dem EDT getan

  • als Original-Code basiert auf sleep() mit Laden und Laden von Bildern illustrieren eine lange Zeit SwingWorker die verwendet werden, nehmen könnte
  • worker wartet setzt dann neuen Titel und lädt dann Bilder
  • nach Abschluss fügt der worker in done() schließlich die Komponente auf die JFrame und zeigt sie an. Hinzugefügt Komponente Inhaltsbereich von JFrame wie in JFrame api. Und wie in javadoc beschrieben hergestellt notwendig Anruf auf validate() JFrame nach add() Aufruf, da der JFrame ein bereits sichtbaren Behälter Rechenblatt Kinder geändert.
  

javdoc Zitat aus validate()

     

Die Validate-Methode wird verwendet, ein verursachen   Behälter seine Subkomponenten legen   nochmal. Es sollte aufgerufen werden, wenn diese   Containers Subkomponenten modifiziert   (Addiert oder von der Abnehm   Behälter oder Layout-verwandtes   Informationen geändert) nach dem   Container angezeigt wurde.

  • zweiter Arbeiter warten einige mehr nur hat dann setzt die Hintergrundfarbe schwarz
  • verwendet JPanel als Basisklasse für ImageLoadTest setBackground() zu beheben, die ich nicht mit JComponent arbeiten konnte erhalten.

So Ihre Hauptprobleme, wo, dass Sie nicht die bevorzugte Größe der Komponente festgelegt haben, und dass Sie nicht nennen validate() auf dem JFrame nach etwas zu den bereits sichtbaren Container hinzugefügt wird.

Das sollte funktionieren

jpanelpaint / ImageLoadTest.java

package jpanelpaint;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JPanel;
import java.util.List;

public class ImageLoadTest extends JPanel {
  private List<Image> list;

  public ImageLoadTest() {
    super();
  }

  public ImageLoadTest(List<Image> list) {
    this();
    this.list = list;
    int height = 0;
    int width = 0;
    for (Image img : list) {
      height += img.getHeight(this);
      width = img.getWidth(this) > width ? img.getWidth(this) : width;
      setPreferredSize(new Dimension(width, height));
    }
  }

  @Override
  protected void paintComponent(Graphics g) {
    int yOffset=0;
    super.paintComponent(g);
    System.err.println("ImageLoadTest.paintComponent()");
    for(Image img : list) {
      g.drawImage(img, 0, yOffset, null);
      yOffset+=img.getHeight(this);
    }
  }
}

Tester.java

import java.awt.Dimension;
import java.awt.Color;
import java.awt.Image;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.SwingWorker;
import javax.swing.SwingUtilities;
import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import jpanelpaint.ImageLoadTest;

public class Tester {

  private JFrame frame;
  private ImageLoadTest ilt;
  private final int NUMBEROFFILES = 4;
  private List<Image> list;

  //will load the images
  SwingWorker worker = new SwingWorker<List<Image>, Void>() {
    @Override
    public List<Image> doInBackground() throws InterruptedException {
      //sleep at start so user is able to see empty jframe
      Thread.sleep(1000);
      //let Event-Dispatch-Thread (EDT) handle this
      SwingUtilities.invokeLater(new Runnable() {
        public void run() {
          frame.setTitle("Loading images");
        }
      });
      //sleep again so user is able to see loading has started
      Thread.sleep(1000);
      //loads the images and returns list<image>
      return loadImages();
    }

    @Override
    public void done() {
      //this is run on the EDT anyway
      try {
        //get result from doInBackground
        list = get();
        frame.setTitle("Done loading images");
        ilt = new ImageLoadTest(list);
        frame.getContentPane().add(ilt);
        frame.getContentPane().validate();
        //start second worker of background stuff
        worker2.execute();
      } catch (InterruptedException ignore) {}
      catch (ExecutionException e) {
        String why = null;
        Throwable cause = e.getCause();
        if (cause != null) {
          why = cause.getMessage();
        } else {
          why = e.getMessage();
        }
        System.err.println("Error retrieving file: " + why);
      }
    }
  };

  //just delay a little then set background
  SwingWorker worker2 = new SwingWorker<Object, Void>() {
    @Override
    public List<Image> doInBackground() throws InterruptedException {
      Thread.sleep(1000);
      SwingUtilities.invokeLater(new Runnable() {
        public void run() {
          frame.setTitle("Setting background");
        }
      });
      Thread.sleep(1000);
      return null;
    }

    @Override
    public void done() {
      ilt.setBackground(Color.BLACK);
      frame.setTitle("Done!");
    }
  };

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

  public Tester() {
    //setupGUI
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        frame = new JFrame("Empty JFrame");
        frame.setSize(new Dimension(1000, 500));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
      }
    });

    //start the swingworker which loads the images
    worker.execute();
  }

  //create image names
  private String[] createImageFileNames(int count){
    String[] fileNames = new String[count];
    for(int i=0; i < count; i++)
      fileNames[i] = "Cards" + File.separator + (i+1) + ".bmp"; 
    return fileNames;
  }

  //load images
  private List<Image> loadImages() {
    List<Image> tmpA = new ArrayList<Image>();
    try {
      for(String name : createImageFileNames(NUMBEROFFILES)){
        System.err.println(name);
        tmpA.add(ImageIO.read(new File(name)));
      }
    } catch (IOException e) { }

    return tmpA;
  }
}

Ich empfehle die ersten paar Kapitel von „Filthy Rich Clients“ zu lesen. Ich hatte Schaukel seit Jahren verwendet, aber erst nach der Lektüre dieses Buches habe ich voll und ganz verstehen, schließlich genau, wie Java Malerei Mechanismus funktioniert.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top