Hoffe ich war nicht zu hart oder dreb, hatte wenig Zeit und bins nicht gewöhnt anderer Leute Code umzubauen. (hab zoom ganz ausgelassen, der Fehler war ganz woanders)
import java.awt.\*;
import java.awt.image.\*;// BufferedImage
import java.awt.geom.\*;
import javax.swing.\*;
//.io ?
import java.io.\*;
//wozu brauchts du HIER .net ?
import java.net.\*;
public class Playfield extends JPanel {
//komische Nameswahl, du benutzt hintergrund als Vordergrund (im Verhältins zu bi).
private Image hintergrund /\*, puffer \*/ ;
private BufferedImage bi;
//braucht man nicht, hat JPanel schon von sich aus. (es sei den du willst nur einen Teil des JPanel selbst benutzten...)
private int scr\_width, scr\_height;
public Playfield(int scr\_width, int scr\_height) {
hintergrund = Toolkit.getDefaultToolkit().getImage("gfx/map.gif");
//arbeite mit this.setHight (scr\_height); Dann weis das JPanel auch das es gerade grösser geworden ist.
this.scr\_height = scr\_height;
//idem.
this.scr\_width = scr\_width;
bi = new BufferedImage(scr\_width, scr\_height, BufferedImage.TYPE\_INT\_RGB);
Graphics2D g2 = bi.createGraphics();
// clear
g2.setBackground(Color.lightGray);
g2.clearRect(0, 0, scr\_width, scr\_height);
MediaTracker tracker = new MediaTracker(this);
tracker.addImage(hintergrund, 0);
tracker.addImage(bi, 0);
try {
tracker.waitForAll();
} catch (InterruptedException ign) {
//Es ist immer schlecht so eine Stelle leer zu lassen wenn man debugged also:
System.out.println ("OPS :"+ign.toString());
}
}
/\*\*
\* clears the panel (User action)
\*/
public void clearPlayfield() {
Graphics2D g2 = (Graphics2D)bi.getGraphics();
//wieder die bemerkung mit getHeight()
g2.clipRect(0, 0, scr\_width, scr\_height);
g2.setColor(Color.lightGray);
Rectangle2D.Double rect = new Rectangle2D.Double(0,0,scr\_width,scr\_height);
g2.fill(rect);
//nein ! NIE direkt auf den Graphics-Context zugreifen, immer mit repaint() arbeiten.
//java macht das genau umgedreht zu C. alles was malten betrifft in paint(g) verbauen.
// alles raus bis
g2 = (Graphics2D)this.getGraphics();
g2.clipRect(0, 0, scr\_width, scr\_height);
g2.drawImage(bi, 0, 0, null);
g2.drawImage(hintergrund, 0, 0, this);
// hier. und durch
repaint();
//ersetzen.
//oder mit paintImmediately() arbeiten, aber nur wenns SEHR schnell sein MUSS.
}
public void updateCoords(int x\_alt, int y\_alt, int x, int y, Color farbe) {
//das geht einfacherer:
/\*
if(x == 0||y ==0||x\_alt == 0||y\_alt ==0||xx\_alt+30||yy\_alt+30) {
;
}else {
\*/ //so:
if(!(x == 0||y ==0||x\_alt == 0||y\_alt ==0||xx\_alt+30||yy\_alt+30)) {
Graphics2D g2 = (Graphics2D)bi.getGraphics();
g2.clipRect(x\_alt-2, y\_alt-2, 4, 4);
g2.setColor(farbe);
g2.drawLine(x\_alt, y\_alt, x, y);
//nein ! NIE direkt auf den Graphics-Context zugreifen, immer mit repaint() arbeiten.
// alles raus bis
g2 = (Graphics2D)this.getGraphics();
g2.clipRect(x\_alt-2, y\_alt-2, 4, 4);
g2.drawImage(hintergrund, 0, 0, this);
g2.drawImage(bi, 0, 0, this);
// hier. und durch
repaint();
//ersetzen.
}
}
public void setPunkt(int x, int y, int r, Color pkt\_farbe) {
//Du weist das der 1. Punkt dann stehen bleibt, sprich der Bildschrim irgendwann voll ist ?
Graphics2D g2 = (Graphics2D)bi.getGraphics();
g2.setColor(Color.black);
g2.drawOval(x, y, r+1, r+1);
g2.setColor(pkt\_farbe);
g2.fillOval(x, y, r, r);
}
// muss man nicht unbedingt überschreiben, das double-buffering ausschalten reicht eigentlich.
public void update(Graphics2D g2) {
paint(g2);
}
public void paint(Graphics g) {
//FALSCH ! das letzte Argument muss this, nicht null sein:
//das muss aber nicht der Fehler sein....
g.drawImage(bi, 0, 0, null);
//idem.
g.drawImage(hintergrund, 0, 0, null);
}
//besser du rufts super.getWidth() auf
public int getScreenWidth() { return scr\_width; }
//siehe oben.
public int getScreenHeight() { return scr\_height; }
}
Meiner Meinung nach ist das Problem mit „Linien weg nach resize/max.“ relativ einfach zu erklären:
Deine paint()-Methode malt das „HintergrundBild“ zuletzt, und übermalt dabei „bi“. Die Linien die über getGraphics() gemalt wurden sind weg nach einem resize weg (java-logik => never-clean), die Linien von bi hast du nie gesehen (du malts sie ja 2x, einmal bi einmal getGraphics()). Generel war bi ziemlich sinnfrei, es lag unter den hintergrund. Überprüf die Transparenz von „map.gif“, stell sicher das java das auch als transparent ansieht und versuchs nochmal.
Oder machs so:
public void init (){
hintergrund = Toolkit.getImage ("...");
MediaTracker ... usw
}
public paint(Graphics G){
g.drawImage (hintergrund,0,0,this);
for (int i=0;i
wobei linien ein int[][] ist das du in setPunkt(...) veränderts.
wenn du die doublebuffer-funktion von JPanel nur einschaltets müsste das sogar bei vielen Linien flüssig laufen (bei 100 Linien etwa 20-25 Bilder/s auf PII 450 unter JDK.1.3.0). ausgeschaltet könnte man das aufbauen der Linien u.U. bei vielen Linien sehen.
Erst wenn 2 Images gleichzeitig auftauchen sollen, und sich bewegen ist custom-doppel-buffering sinnvoll.
kleine Kurzeinführung in java und GUI: (ich lass alles weg was nicht direkt mit der GUI zu tun hat und setzt das Thread-konzept vorraus)
java startet bei GUI-Applicationen immer 2 Threads, einen mit main(String[] A) und einen für die interaktion mit dem User. Dieser 2. Thread wird "event" oder "paint"-thread genannt und ruft paint(), update(), und alle Actionlistener die auf Klicks, MouseXYZ, Buttons, TextFelder und ähnliches (was der User sieht) auf. Dieser Thread passt auf NICHTS auf und sollte nicht blockiert werden. Ist er blockiert so passiert keine Interaktion mehr mit dem User, die GUI steht komplett (nichtmal coursor-blinken geht). Diesem Thread sollte man nicht in die Quere kommen.
Der Thread unterwirft sich nur dem RepaintManager. Er wird "aktiviert" durch repaint(), paintImmediately() und invokeLater(runnable r) (und ähnliches).
wenn man aber getGraphics benutzt bekommt man einen GraphicsContext (Graphics ist ein Teil davon) der von den event-thread ebenfalls benutzt wird. Da wäre nicht schlimm wenn Graphics "synchronized" wäre, ist es aber nicht. Also entweder man stellt den Thread über den RepaintManager ruhig (schlecht), oder man synchronisiert alle Zugriffe auf Graphics-Objecte (schlimmer, da syn. immer langsam ist).
ergo gehört jeder Code der auf Graphics (einer sichtbaren Componente) zugreift in paint(Graphics g) (paintChildren(),...). Und diese Methode ruft man \_nicht\_ direkt auf, ausserdem sollte diese Methode "schnell" sein. Will man ein "paint()"-aufruf durch den event-thread "provozieren" so ruft man repaint() auf.
cu