Problem mit Doublebuffering
-
Ich hab hier ein einfaches Beispiel für Double Buffering gebastelt bei dem einfach ein Viereck rechts aus dem Bildschirm verschwindet.
Das funktioniert soweit auch ganz gut allerdings ruckelt es wenn das viereck an den rechten rand kommt.
dann wirft mir java irgendwann noch eine nullpointerexception von der ich nicht weiss wo sie her kommt.
Hier der Code:
import java.awt.*; public class game extends Frame{ Graphics buffer; Image offscreen; Dimension dim; int curX,curY; public game(){ this.setSize(640,480); this.setVisible(true); init(); } public void init(){ dim = getSize(); this.setBackground(Color.black); offscreen = createImage(dim.width,dim.height); buffer = offscreen.getGraphics(); curX = curY = 50; repaint(); loop(); } public void loop(){ while(true){ curX +=1; repaint(); for (int i=0;i<1000000;i++){ } } } public void paint(Graphics g){ buffer.clearRect(0,0,dim.width,dim.height); buffer.setColor(Color.red); buffer.drawString("Double-buffered",50,50); buffer.fillRect(curX,curY,20,20); g.drawImage(offscreen,0,0,this); } public void update(Graphics g){ paint(g); } public static void main(String[] args){ new game(); } }
kann mir jemand erklären woher die ruckel und die excpetion kommen?
-
0. Klassen werden groß geschrieben.
1. Mach ein neuen Thread der die Bewegung übernimmt
Blockiert man mit seiner Methode nicht den kompletten GUI-Thread ?
die Schleife
for (int i=0;i<1000000;i++){ }
machste weg und machst dafür Thread.sleep(millisekunden).
Der Thread kann dann Frame.update oder Frame.repaint() aufrufen.
Die OOP-Methode dafür ist das Observer-Pattern.3. leite von JFrame ab, tu ins JFrame ein JPanel rein und mahle auf das Panel, nicht auf JFrame.
ist java.awt.Frame nicht veraltet ?
-
0. ja ^^, ich hab das recht fix runtergetippt und nicht drauf geachtet
1. ich hab das mit dem auslagern in einen Thread versucht, hatte aber noch kein zufriedenstellendes ergebniss und bin daher erstmal auf die einfachere Variante mit einem Thread zurück gegangen. Aber wenn mich wieder besser mit Java auskenn werd ich da nochmal nen versuch starten.
2. Die Schleife ist hässlich, wurd auch gant schnell wieder entfernt , also keine angst war ne ausnahme da ich an dem tag irgendwie mit exception handling auf kriegsfuß stand
3. Auch das habe ich versucht, funktioniert auch wunderbar.
Aber:
Wenn ich mit JPanel arbeite funktionieren meine Listener nicht mehr. Mit JFrame+Panel funktionieren sie.Des weiteren habe ich noch ein Problem mit dem Fokus des Panels ich muss erst mit der maus aufs panel klicken damit die KeyListener reagieren.
Hier erstmal der Quelltext vor den konkreten Fragen:
Game.java (Keine Probleme hier)
import java.awt.Color; import java.awt.Container; import java.awt.Dimension; import javax.swing.JFrame; public class Game extends JFrame{ Dimension dim = new Dimension(640,480); Client client = new Client(dim); Game(){ int x,y; this.setResizable(false); if (this.isResizable()){ // +9 und +35 um im panel 640*480 darstellen zu können x=9; y=35; } else{ x=7; y=33; } this.setSize(dim.width+x,dim.height+y); this.setBackground(Color.black); add(client); this.setVisible(true); } public static void main(String[] argc){ new Game(); } }
DoubleBuffer.java (Panel mit double buffering von dem geerbt wird)
import java.awt.Graphics; import java.awt.Image; import java.awt.Panel; import javax.swing.JPanel; public class DoubleBuffer extends Panel{ private static final long serialVersionUID = 1L; private int bufferWidth; private int bufferHeight; private Image bufferImage; private Graphics bufferGraphics; public DoubleBuffer() { super(); } public void paintBuffer(Graphics g){ } public void paint(Graphics g){ // checks the buffersize with the current panelsize // or initialises the image with the first paint if(bufferWidth!=getSize().width || bufferHeight!=getSize().height || bufferImage==null || bufferGraphics==null) resetBuffer(); if(bufferGraphics!=null){ //this clears the offscreen image, not the onscreen one bufferGraphics.clearRect(0,0,bufferWidth,bufferHeight); //calls the paintbuffer method with //the offscreen graphics as a param paintBuffer(bufferGraphics); //we finaly paint the offscreen image onto the onscreen image g.drawImage(bufferImage,0,0,this); } } public void update(Graphics g){ paint(g); } private void resetBuffer(){ // always keep track of the image size bufferWidth=getSize().width; bufferHeight=getSize().height; // clean up the previous image if(bufferGraphics!=null){ bufferGraphics.dispose(); bufferGraphics=null; } if(bufferImage!=null){ bufferImage.flush(); bufferImage=null; } System.gc(); // create the new image with the size of the panel bufferImage=createImage(bufferWidth,bufferHeight); bufferGraphics=bufferImage.getGraphics(); } }
Client.java (eigentlicher Clientbereich in dem ich arbeiten will)
import java.awt.*; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; public class Client extends DoubleBuffer implements KeyListener{ int x,y=0; Client(Dimension dim){ this.setSize(dim); this.addKeyListener(this); this.requestFocus(); } public void paintBuffer(Graphics g){ g.setColor(Color.RED); g.fillRect(0,0,1,1); g.fillRect(this.getWidth(),0,1,1); g.fillRect(0,this.getHeight(),1,1); g.fillRect(this.getWidth(),this.getHeight(),1,1); g.fillRect(x,y,100,100); } public void keyTyped(KeyEvent arg0) { // TODO Auto-generated method stub } public void keyPressed(KeyEvent arg0) { int key = (int)arg0.getKeyCode(); int step = 7; if (key == 27){ System.exit(0); } if (key == 37){//left if (x>0) x-=step; } else if (key == 39){//right if (x<this.getWidth()-100) x+=step; } if (key == 38){//up if (y>0) y-=step; } else if (key == 40){//down if (y<this.getHeight()-100) y+=step; } repaint(); } public void keyReleased(KeyEvent arg0) { // TODO Auto-generated method stub } }
Ich hoff mal der Code ist übersichtlich ich tendiere dazu zu wenig zu kommentieren.
Wie kann ich nun die Listener mit dem JPanel zum laufen bringen?(falls ich mich hier grad zu dumm anstell reicht auch ein link ^^)
Ab und zu kommt es mir immernoch so vor als würde es flackern. Wenn ich step z.b. auf 7 setze und ein paar mal von links nach rechts und umgekehrt fahre sehe ich ab und an noch ein kurzes flackern.
Habe ich beim Double buffering was falsch gemacht?