Probleme de keylistener sur Jframe et clipping

superjoe3 Messages postés 7 Date d'inscription samedi 11 février 2006 Statut Membre Dernière intervention 29 mars 2006 - 23 mars 2006 à 11:34
tucobouch Messages postés 194 Date d'inscription vendredi 17 février 2006 Statut Membre Dernière intervention 1 mai 2009 - 29 mars 2006 à 23:53
Bonjour,


je suis en train de faire un pacman dans le cadre d'un projet de
programmation, et j'ai un souci à propos des Keylistener sur la Frame
qui doivent écouter les directions que je rentre au clavier pour
diriger le pacman.

En effet, lorsque j'appuie sur le clavier, j'ai le code clavier
correspondant à la touche appuyée qui apparait sur le terminal, mais
cela n'est pas pris en compte par le jeu, et le pacman continue a
avancer tout droit.

De plus, qui je clique autre part que sur la fenetre de jeu, et
que je reviens ds cette derniere, les keylisteners ne sont plus actifs!

par ailleurs, la fenetre a un probleme de clipping, j'ai bien
essayé d'y intégrer un double buffer(maladroitement je suppose) mais
n'a pas sensiblement amélioré le rendu.


Pouvez vous m'aider?








Code:, ----
import fr.jussieu.script.*;

import java.awt.event.*;

import javax.swing.*;

import java.io.*;

import java.awt.*;

import java.awt.image.*;

class Pacman implements Runnable {

public int[][] lab;

public int i,j;

public int x,y;

public char direction;

public Thread t;

public decor d;

public KeyListener k;

public Pacman(int[][] v, decor d) {

this.i= 0;

this.j=0;

this.lab=v;

this.direction='d';

this.t = new Thread();

this.d = d;

this.run();

}

public void run() {

this.d.start("Pacman");

this.d.getf().addKeyListener(this.d);

while(this.t.isAlive() || !this.t.isInterrupted()){

Deug.println(this.d.directionPressed);

try {

Thread.sleep(500);

} catch (InterruptedException e) {}

switch(this.direction) {

case 'h':

for (int x=this.i+1;x<0;x--){

if(!this.updatePacman(x,this.j) || this.updateDirection()) break;

Deug.println("haut");

try {

Thread.sleep(10);

} catch (InterruptedException e) {}

}

break;

case 'b':

for (int x=this.i+1;x -1 && this.i |-1 && this.j-1 && this.i |-1 && this.j-1 && this.i |-1 && this.j-1 && this.i |-1 && this.j<this.lab.length) {

this.direction = 'd';

this.d.directionPressed = 's';

return true;

}

return false;

}

}






et aussi





Code:, ----
import fr.jussieu.script.*;

import java.io.*;

import javax.swing.*;

import java.awt.*;

import java.awt.event.*;

import java.awt.image.*;

/**

* @author humel

*

*/

public class decor extends Canvas implements KeyListener {

public int[][] lab;

// private static Drawable d = null;

private static JFrame f=null;

private int width, height, x, y;

private Image Im;

private Graphics Gr;

private Image[][] Images;

public char directionPressed;

// private TexturePaint texture;

private Pacman pacman;

public decor(int[][] t,int h, int l){

this.lab=t;

this.width=l;

this.height=h;

Images = new Image[t.length][t[0].length];

}

public void setDirectionPressed(int i) {

if (i == 37) this.directionPressed='g';

if (i == 38) this.directionPressed='h';

if (i == 39) this.directionPressed='d';

if (i == 40) this.directionPressed='b';

}

public void keyPressed(KeyEvent e){

this.setDirectionPressed(e.getKeyCode());

Deug.println(e.getKeyCode());

}

public void keyReleased(KeyEvent e){ }

public void keyTyped(KeyEvent e){ }

public Dimension getPreferredSize() {

return new Dimension(width,height);

}

public JFrame getf() { return f;}

public void paint(Graphics g) {

if (this.Im==null) {

Im = createImage(this.width,this.height);

this.Gr = Im.getGraphics();

}

g.drawImage(Im,this.x,this.y,this);

}

public void update(Graphics g) {

paint(g);

}

public void start(String s) {

if (f!=null) return;

f = new JFrame(s);

f.setResizable(false);

f.getContentPane().add(this);

f.pack();

f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

f.setVisible(true);

try {

Thread.sleep(3000);

} catch(Exception e) {}

for(int j=0;j<lab.length;j++){

for(int i=0;i<lab[0].length;i++){

if(lab[i][j]==1){

traceBloc(i,j);

}

if (lab[i][j]==0){

traceVide(i,j);

}

f.getContentPane().add(this);

}

f.getContentPane().add(this);

}

// this.f.setVisible(true);

// this.t.start();

}

public void traceBloc(int i,int j){

this.Images[i][j]= f.getToolkit().getImage("brick.gif");

this.Gr.drawImage(this.Images[i][j],25*i,25*j,this.f);

/*// d.getGr().drawImage(f.getToolkit().getImage("brick.gif"),x,y,this.f);

this.bufferedImage = this.toBufferedImage(Toolkit.getDefaultToolkit().getImage("brick.gif"));

this.texture = new TexturePaint(Image,new Rectangle(0, 0, 25, 25));

Graphics2D g2d = (Graphics2D)this.Gr;

g2d.setPaint(texture);

g2d.fillRect(x,y,25,25);

f.getContentPane().add(); */

f.getContentPane().add(this);

}

public void traceVide(int i,int j){

this.Images[i][j]= f.getToolkit().getImage("vide.gif");

this.Gr.drawImage(this.Images[i][j],i*25,j*25,this.f);

// d.getGr().drawImage(f.getToolkit().getImage("brick.gif"),x,y,this.f);

/* this.x=x;

this.y=y;

this.Im = f.getToolkit().getImage("vide.gif");

this.Gr.drawImage(Im,x,y,this.f);

// this.Gr.drawImage(b,x,y,this.f); */

f.getContentPane().add(this);

}

public void tracePacman(int i,int j){

this.Images[i][j]= f.getToolkit().getImage("pacman.gif");

this.Gr.drawImage(this.Images[i][j],i*25,j*25,this.f);

f.getContentPane().add(this);

}

}

12 réponses

tucobouch Messages postés 194 Date d'inscription vendredi 17 février 2006 Statut Membre Dernière intervention 1 mai 2009 50
23 mars 2006 à 23:39
En fait c'est normal : c'est un probleme de perte de focus. Le focus est le composant qui reçoit les touches (et les evenements liés). Quand ta fenetre s'ouvre, ta fenetre a le focus donc les touches sont captées par ta fenetre. Quand tu clique en dehors de la fenetre, ta fenetre perd son focus au profit d'une autre fenetre (dans celle où tu clique). Quand tu reclique dans ta Frame, le focus n'est pas redonné automatiquement a ta fenetre donc elle ne reçevra toujours pas les touches. Pour remedier a cela, il faut ajouter un listener a ta JFrame, lorsque ta fenetre devient active, tu redemande le focus.

Voici le code a rajouter pour ta Frame :

addWindowListener(new WindowAdapter() {
public void windowActivated(WindowEvent e) {
requestFocusInWindow();
}
});

requestFocusInWindow(); demande le focus

En respectant ton code, a l'ouverture de ta frame, met les lignes suivante :

f.addWindowListener(new WindowAdapter() {

public void windowActivated(WindowEvent e) {

f.requestFocusInWindow();

}

});
1
tucobouch Messages postés 194 Date d'inscription vendredi 17 février 2006 Statut Membre Dernière intervention 1 mai 2009 50
23 mars 2006 à 13:52
1ere remarque :

c'est quoi tout ces this !! c'est trés lourd a lire et surtout inutile...



2eme remarque :

avec quelques lignes de commentaires dans ton code assez peu lisible ça aurait été cool!



Sinon, pour répondre a tes probleme, en regardant 5 min ton code :
-Prb de ton pacman qui va tout droit : t'es sur que tes tests de direction dans updateDirection() sont corrects ?! Si c'est buggué, ton pacman ne changera jamais de direction
-Pour ton KeyListener : essaye de l'attacher a ton Canvas au lieu de ta JFrame
0
superjoe3 Messages postés 7 Date d'inscription samedi 11 février 2006 Statut Membre Dernière intervention 29 mars 2006
23 mars 2006 à 15:36
Dsl pour le grand nombre de this, je suis débutant de porg et on m'a dit de les mettre à chaque fois lol.
Sinon pour le KeyListener, quel impact cela aura de l'attacher au Canvas plutot qu'a la Frame? Le résultat sera le mème non?
0
tucobouch Messages postés 194 Date d'inscription vendredi 17 février 2006 Statut Membre Dernière intervention 1 mai 2009 50
23 mars 2006 à 17:21
En fait je comprends pas trop ton prb de keyListener : ton application "capte" les touches au debut et quand tu quitte la fenetre, les touches ne sont plus captées au retour?

Pour tes this :
tu met this quand il peut y avoir une ambiguite avec un atribut de ta classe et un parametre d'une fonction. Par exemple :

public class Test
{
int a;

public void test(int a)
{
//modifie l'attribut a de la classe Test
this.a=1;

//modifie le parametre a de la fonction
a=1;
}
}

Voila, utilise vraiment this dans ces cas là!
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
superjoe3 Messages postés 7 Date d'inscription samedi 11 février 2006 Statut Membre Dernière intervention 29 mars 2006
23 mars 2006 à 22:51
L'application capte les touches tant que la fenetre est au 1er plan.
Ensuite si je clique ailleurs, sur mon bureau ou une autre fenetre par ex, et que je reclique sur l'application, le keylistener n'est plus actif
0
tucobouch Messages postés 194 Date d'inscription vendredi 17 février 2006 Statut Membre Dernière intervention 1 mai 2009 50
24 mars 2006 à 00:05
Je viens de relire la partie affichage de ton code :
mes commentaires sont en rouge

public void traceBloc(int i,int j){
//evite de faire getImage a chaque affichage : a chaque rafraichissement tu charge un fichier (imagine un jeu a 50 images par secondes!) : tu as un tableau d'Images alors charge y une fois pour toute tes images...meme remarque pour tracePacman et traceVide
this.Images[i][j]= f.getToolkit().getImage("brick.gif");
this.Gr.drawImage(this.Images[i][j],25*i,25*j,this.f);

//ligne virer : pas propre! fait plutot un f.repaint() ... en fait, je vois pas a quoi sert cette ligne...
f.getContentPane().add(this);
}

Pour faire un affichage propre dans les regles de l'art :

Creer un double buffer dans ton Canvas, dans l'initialisation de ton Canvas :

setSize(largeur,hauteur);
createBufferStrategy( 2 );
strategy = getBufferStrategy();
buffer = (Graphics2D) strategy.getDrawGraphics(); //ton Graphics où afficher

Change la fonction paint de decor en :

public void paint(Graphics g)
{
buffer.drawImage(Im,x,y,null);
strategy.show();
}

Tu peux meme si tu veux, ça serait mieux meme, virer ton Im (ton double buffer a la main) et n'utiliser pour l'affichage, que le graphics buffer.
Le double buffer créé ici est en hardware donc trés rapide. Tu peux voir un petit exemple de rendu en double buffer avec une de mes sources : "Map : Decors Infinis "...
0
superjoe3 Messages postés 7 Date d'inscription samedi 11 février 2006 Statut Membre Dernière intervention 29 mars 2006
24 mars 2006 à 11:43
Merci pour toutes ces infos!
Je viens d'essayer d'ajouter ton code pour la reprise de focus dans la Frame,
public void start(String s) {
if (f!=null) return;
f = new JFrame(s);
f.addWindowListener(new WindowAdapter() {
public void windowActivated(WindowEvent e) {
f.requestFocusInWindow();
}
});
f.setResizable(false);
f.getContentPane().add(this);
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
try {
Thread.sleep(3000);
} catch(Exception e) {}
for(int j=0;j<lab.length;j++){
for(int i=0;i<lab[0].length;i++){
if(lab[i][j]==1){
traceBloc(i,j);

}
if (lab[i][j]==0){
traceVide(i,j);
}
f.getContentPane().add(this);

}
f.getContentPane().add(this);

}
}

Pourtant, lorsque je clique en dehors de la fenetre et que j'y reviens, celle ci ne reprend toujours pas le focus.
L'aurai-je ajoutré au mauvais endroit?
0
superjoe3 Messages postés 7 Date d'inscription samedi 11 février 2006 Statut Membre Dernière intervention 29 mars 2006
24 mars 2006 à 15:56
j'ai corrigé le getImage, et l'affichage est + rapide, merci
Par contre :

//ligne virer : pas propre! fait plutot un f.repaint() ... en fait, je vois pas a quoi sert cette ligne...
f.getContentPane().add(this);

Si je vire cette ligne, une fenetre vide s'ouvre et le programme continue son éxécution
Et si je fais un repaint aussi!
0
tucobouch Messages postés 194 Date d'inscription vendredi 17 février 2006 Statut Membre Dernière intervention 1 mai 2009 50
24 mars 2006 à 18:24
Houla.. ton code est tellement un sac de noeud que je m'y perd...

Je comprends pas pourquoi tu fait par exemple dans ta boucle dans la fonction start de decor :

f.getContentPane().add(this);

Ceci ajoute ton decor dans la fenetre. On doit le faire une fois pour toute!

Je viens de voir aussi un truc pas normal dans ta classe Pacman, je pense que pas mal de prb peuvent venir de là... Tu veux faire un Thread non?
Pacman fait la heriter de Thread. Dans ton constructeur, ne fait pas run() mais start()! (start() demarre le thread et execute la fonction run() )

class Pacman extends Thread {
public Pacman(int[][] v, decor d) {
this.i=0;
this.j=0;
this.lab=v;
this.direction='d';
this.t = new Thread();
this.d = d;
start();
}

Voila
Corrige un peu ton code et rajoute des commentaires, je répondrai a tes nouvelles interrogations uniquement si ton code evolu...
0
superjoe3 Messages postés 7 Date d'inscription samedi 11 février 2006 Statut Membre Dernière intervention 29 mars 2006
29 mars 2006 à 23:42
Voila la classe décor est maintenant corrigée, et cette fois ci je n'ai plus de perte de focus qd je passe sur une autre fenètre, et avec le double buffer je n'ai plus de clipping!
Par contre, un autre problème est apparu:
en effet, lorsque je fais passer une autre fenetre au 1er plan, la partie de la Frame de pacman masquée devient toute blanche et plus rien ne s'affiche dessus, bien que le keylistener soit encore actif.
Est ce du au double buffer ou a la manière d'afficher ?
0
superjoe3 Messages postés 7 Date d'inscription samedi 11 février 2006 Statut Membre Dernière intervention 29 mars 2006
29 mars 2006 à 23:46
j'oublais le code ^^:

import java.io.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.Graphics2D;
import java.lang.Object;
import javax.imageio.*;
/**
* @author humel
*
*/
public class decor extends Canvas implements KeyListener{ //La classe décor s'occupe de tracer le décor et de le garder à jour, elle contient aussi le keylistener qui sera ajouté a la JFrame(propriété de notre classe décor)
public int[][] lab; //le labyrinthe passer en argument
private static JFrame f; //Notre frame, ou fenetre pour etre plus explicite
private int width, height, x,y; //La taille de frame, et 2 coordonnées utilisé par la méthode paint(Graphics g) pour mettre a jour le graphic et le redessiner en utilisant le double buffering hardware.(pour eviter les scintillements)
private Graphics Gr;
private Image Im;
private BufferedImage[] Images;
public char directionPressed;
public BufferStrategy strategy;

public decor(int c){ //a la place de int[][]t
this.lab=new int[c][c];
genLab2(this.lab);
Images = new BufferedImage[3];
this.x=0; this.y=0;
}

public void setDirectionPressed(int i) {
if (i == 37) this.directionPressed='g';
if (i == 38) this.directionPressed='h';
if (i == 39) this.directionPressed='d';
if (i == 40) this.directionPressed='b';
}
public void keyPressed(KeyEvent e){
this.setDirectionPressed(e.getKeyCode());
System.out.println(e.getKeyCode());
}
public void keyReleased(KeyEvent e){ }
public void keyTyped(KeyEvent e){ }
public Dimension getPreferredSize() {
return new Dimension(width,height);
}
public JFrame getf() { return f;}
public void paint(Graphics g) {
if (Im==null) {
Im = createImage(this.width,this.height);
Gr = Im.getGraphics();
}
g.drawImage(this.Im,this.x*25,this.y*25,this.f);
}
public void update(Graphics g) {
paint(g);
}
public void start(String s) {
if (f!=null) return;
f = new JFrame(s);
f.pack();
f.setLocation(0,0);
f.resize(lab.length*25,lab.length*25);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
sleep(3);
Images[0] = loadImage("C:\\Documents and Settings\\humel.TICTACTOE\\pacman\\src\\brick.gif");
Images[1] = loadImage("C:\\Documents and Settings\\humel.TICTACTOE\\pacman\\src\\vide.gif");
Images[2] = loadImage("C:\\Documents and Settings\\humel.TICTACTOE\\pacman\\src\\pacman.gif");
//this.f.setVisible(true);
f.createBufferStrategy( 2 );
f.setIgnoreRepaint( true );
strategy = f.getBufferStrategy();
this.Gr = strategy.getDrawGraphics();
f.getContentPane().add(this);
f.show();
}

public void sleep(double secondes) {
try {
Thread.sleep((int)(secondes*1000));
} catch(InterruptedException ie) {}
}
public void traceBloc(int i,int j){
this.Im = this.Images[0];
this.x=i;
this.y=j;
repaint();
}
public void traceVide(int i,int j){
this.Im = this.Images[1];
this.x=i;
this.y=j;
repaint();
}

public void tracePacman(int i,int j){
this.Im = this.Images[2];
this.x=i;
this.y=j;
repaint();
}

public static BufferedImage loadImage(String i)
{
try{
return ImageIO.read(new File(i));
}catch(Exception e)
{
System.out.println(e.toString());
return null;
}
}


public static void genLab2(int tab[][]) { //rasoir d'occam
int t,v,k;
for (int i=1;i<tab.length;i++) {
for(int j=1; j<tab[0].length-1;j++){
v=(int)(6*Math.random());
if(v < 5 && tab[i-1][j-1]==0 && tab[i-1][j]==0 && tab[i][j+1]==0 && tab[i-1][j+1]==0) tab[i][j]=1;
}
k=0;
while(k<tab[0].length-1){
t=min((int)(Math.random()*4),tab.length-i-1);
for (int j=k; j<tab[0].length;j++){
k++;
if (tab[i][j]==0) break;
for(int z=i;zb) return b;
return a;
}


}
0
tucobouch Messages postés 194 Date d'inscription vendredi 17 février 2006 Statut Membre Dernière intervention 1 mai 2009 50
29 mars 2006 à 23:53
Ton code est plus lisible deja...

Essaye de virer : f.setIgnoreRepaint( true ); pour voir
0
Rejoignez-nous