IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

AWT/Swing Java Discussion :

Rotation des éléments d'un JPanel


Sujet :

AWT/Swing Java

  1. #1
    Membre habitué
    Homme Profil pro
    Ingénieur Informatique et Réseaux
    Inscrit en
    Avril 2011
    Messages
    232
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur Informatique et Réseaux
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2011
    Messages : 232
    Points : 182
    Points
    182
    Par défaut Rotation des éléments d'un JPanel
    Bonjour,
    Dans le cadre de la réalisation d'un Monopoly, j'aimerai tourner un JPanel ou du moins son contenu afin de dessiner correctement les terrains.
    J'ai donc overridé la méthode paint() et fait une rotation avant d'appeler la méthode paint() de la classe mère:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    	public void paint(Graphics g) {
    		Graphics2D g2d = (Graphics2D) g;
    		g2d.rotate(Math.PI,this.getPreferredSize().width / 2, this.getPreferredSize().height / 2);
    		super.paint(g2d);
    	}
    Mais voila le résultat est un peu inattendu (voir pièce jointe).
    Je ne comprends pas ce qu'il se passe, est-ce que quelqu'un pourrait m'expliquer?

    Merci,
    Images attachées Images attachées  

  2. #2
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Salut,

    Le premier paramètre est l'angle en radians et les 2 autres sont les coordonnées du centre de la rotation. Un cercle faisant 2PI radians (360 degrés), PI est l'équivalent d'une rotation de 180 degrés, donc l'affichage se retrouve la tête en bas, normal. Ensuite, le centre du composant c'est getWidth()/2, getHeight()/2. La taille préférentielle n'est pas sûre d'être respectée : ça dépend du LayoutManager utilisé. Donc il se peut que, dans le contexte de ton affichage, la rotation soit excentrée.

    A mon avis, vu qu'il y a 4 côtés identiques à un plateau de monopoly, il faudrait que tu gères l'affichage en quatre parties, chacune avec une rotation de PI/2 par rapport à la précédente. Mais c'est assez compliqué de le gérer, parce que chaque nouvelle rotation va dépendre de l'état du repère, modifié par les rotations précédentes. Il est plus simple de faire ça par rapport à un repère fixe, celui d'origine, en tournant de pi/2, de pi, puis de 3pi/2 (ou de -pi/2). En plus, ceci ne peut fonctionner qu'avec un panel carré, ou alors il faut adapter la largeur et la hauteur selon la partie affichée (la première partie s'adapte en largeur, la seconde en hauteur, la troisième en largeur, la quatrième en hauteur), ce qui est nettement plus complexe.

    Voici le code qui fonctionne dans tous les cas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    public class ExempleMonopoly extends JPanel {
     
    	private final static int CASECOINS=4;// une case coin fait 2 fois la hauteur d'une case de bord vertical et 2 fois la largeur d'une case de bord horizontal
    	private final static int NBCASES = 10 + CASECOINS;
     
    	public ExempleMonopoly() {
    		super();
    	}
     
    	public static void main(String[] args) {
     
    		JFrame frame = new JFrame("Monopoly");
    		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    		JPanel panel = new ExempleMonopoly();
     
     
    		frame.getContentPane().add(panel);
     
    		frame.setSize(400, 400);
    		frame.setLocationRelativeTo(null);
    		frame.setVisible(true);
     
    	}
     
    	@Override
    	public void paint(Graphics g) {
     
    		super.paint(g);
     
    		g = g.create(); // il vaut mieux travailler sur une copie, pour éviter de laisser le contexte graphique dans un état modifié
     
    		int width = getWidth()-1;
    		int height = getHeight()-1;
     
    		int largeurCase = width/NBCASES;
    		int hauteurCase = height/NBCASES;
     
    		// on compense les arrondis dans la derrermination des largeurs et hauteurs de cases
    		width = largeurCase*NBCASES;
    		height = hauteurCase*NBCASES; 
     
    		// on centre pour prendre comptre la différence entre largeurxhauteur du composant et celles compensées
    		AffineTransform centrage = AffineTransform.getTranslateInstance(getWidth()/2-width/2, getHeight()/2-height/2);
    		((Graphics2D)g).setTransform(centrage);
     
    		// ligne du bas
    		g.setColor(Color.BLACK);
    		dessineLigne(g, 0, height, largeurCase, hauteurCase*2);
     
    		// ligne de gauche
    		AffineTransform rotation1 = new AffineTransform(centrage);
    		rotation1.concatenate(AffineTransform.getRotateInstance(Math.PI/2, height/2, width/2));
    		((Graphics2D)g).setTransform(rotation1);		
    		g.setColor(Color.RED);
    		dessineLigne(g, height/2-width/2, width/2+height/2, hauteurCase, largeurCase*2);
     
    		// ligne d'en haut
    		AffineTransform rotation2 = new AffineTransform(centrage);
    		rotation2.concatenate(AffineTransform.getRotateInstance(Math.PI, height/2, width/2));
    		((Graphics2D)g).setTransform(rotation2);		
    		g.setColor(Color.BLUE);
    		dessineLigne(g, height-width, width, largeurCase, hauteurCase*2);
     
    		// ligne de droite
    		AffineTransform rotation3 = new AffineTransform(centrage);
    		rotation3.concatenate(AffineTransform.getRotateInstance(-Math.PI/2, height/2, width/2));
    		((Graphics2D)g).setTransform(rotation3);		
    		g.setColor(Color.GREEN.darker());
    		dessineLigne(g, width/2-height/2, width+(width-height)/2, hauteurCase, largeurCase*2);
     
    		g.dispose();
     
    	}
     
    	private void dessineLigne(Graphics g, int offset, double hauteur, int largeurCase, int hauteurCase) {
    		// case du coin
    		g.drawRect(offset, (int)(hauteur-hauteurCase), largeurCase*2, hauteurCase);
    		// autres cases
    		offset += largeurCase*2;
    		for(int i=NBCASES-CASECOINS; i>0; i--) {
    			g.drawRect(offset, (int)(hauteur-hauteurCase), largeurCase, hauteurCase);
    			offset+=largeurCase;
    		}
    	}
     
    }
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  3. #3
    Membre habitué
    Homme Profil pro
    Ingénieur Informatique et Réseaux
    Inscrit en
    Avril 2011
    Messages
    232
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur Informatique et Réseaux
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2011
    Messages : 232
    Points : 182
    Points
    182
    Par défaut
    Bonjour,
    Merci pour votre réponse, j'avais dans un premier temps fait du dessin 2D pour dessiner mes cases en 4 blocs distincts.
    Le problème que j'ai eu et c'est pourquoi je suis repassé en composant swing, c'est que je n'arrivai pas a gérer les événements de sélection d'un terrain (ou groupe de terrain) via un clic sur une case.
    En fait je ne savais pas sur quel terrain (case) j'ai cliqué.

    As-tu une solution pour gérer ça?

    Merci,

  4. #4
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Le principe de base est d'au lieu de dessiner directement avec des drawRect, on va créer des Rectangle2D qui correspondent. Si on stocke ces rectangles dans une liste, on peut parcourir cette liste au clic pour déterminer à quel rectangle appartient le clic, donc connaitre la case cliquée. Il faut juste appliquer la transformée au rectangle avant de tester l'appartenance du point de la souris.
    On peut encapsuler le rectangle dans une classe Case qui porte les informations de la zone, et introduire une classe Block pour porter la transformée affine associée, qui contient toutes les instances de Case du bloc. Comme les dimensions des rectangles et les transformées affines ne dépendent que de la taille du panel, on peut recalculer tout ça uniquement sur l'évenement ComponentListener.componentResized(). La méthode paint ne fait que parcourir la liste des instances de Bloc, puis des instances de Case du bloc, pour dessiner les rectangles associés. On gagne ainsi en vitesse de rafraichissement.
    Idem pour le clic souris, ou le mouseEnter, mouseExit..., pour faire du hover par exemple. On peut ajouter à la Case des états, du type survolé, sélectionné... : avec une gestion simple de propriétés à base de SwingPropertyChangeSupport, on peut gérer facilement le rafraichissement.

    On peut même gérer l'offset et la taille de la case par transformée affine, ce qui simplifie le dessin d'une case, qui se fait toujours pas coordonnées et dimensions fixes. C'est particulièrement bénéfique pour l'affichage de chaines de caractères, en particulier au niveau performance (c'est toujours plus rapide d'affiche une chaine avec grande police par agrandissement, que par augmentation de la chasse. Par contre, il faut penser à gérer l'épaisseur de trait par transformée inverse sinon la transformée d'échelle due à la taille de case s'applique aux traits et on se retrouve avec des lignes super épaisses.

    Après, pour éviter d'avoir à programmer tout ça soi-même, on peut utiliser une API, comme Piccolo2D par exemple, qui simplifie tout ça. Surtout que ça permet facilement de gérer l'affichage des pions, des cartes (de chance), de faire des animations (pour déplacer les pions, les cartes, ou simplement tourner le plateau à loisir, pour choisir le bloc qu'on veut voir en bas, etc...), de ne pas se prendre la tête pour le placement des textes...
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  5. #5
    Membre habitué
    Homme Profil pro
    Ingénieur Informatique et Réseaux
    Inscrit en
    Avril 2011
    Messages
    232
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur Informatique et Réseaux
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2011
    Messages : 232
    Points : 182
    Points
    182
    Par défaut
    Merci pour la réponse, j'avais fait un truc dans le genre mais je ne suis pas allé plus loin parce que je pensai que ça ne marcherai pas du fait de la manière de dessiner:
    En fait chaque case savait se dessiner (méthode draw(g)) donc je faisais une translation du graphic pour chaque case et une rotation quand j'arrivais au bout de la ligne.
    Du coup chaque rectangle de mes cases étaient positionné au même endroit...

    Est ce qu'il y a une manière de contourner ce problème?

  6. #6
    Membre habitué
    Homme Profil pro
    Ingénieur Informatique et Réseaux
    Inscrit en
    Avril 2011
    Messages
    232
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur Informatique et Réseaux
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2011
    Messages : 232
    Points : 182
    Points
    182
    Par défaut
    Bonjour,
    Je réponds car j'ai trouvé la solution.
    Il faut que je découpe en sous panel et que j'applique à chacun d'eux un mouseListener en parcourant les rectangles représentant ma case.

    Merci beaucoup de votre aide.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. jPanel, et positionnement des éléments autour
    Par knice dans le forum Agents de placement/Fenêtres
    Réponses: 1
    Dernier message: 04/04/2009, 17h10
  2. tranférer des éléments d'une base
    Par john_wayne dans le forum Décisions SGBD
    Réponses: 1
    Dernier message: 21/06/2004, 15h33
  3. [VB.NET] Enregistrement des éléments d'une listBox
    Par Hoegaarden dans le forum Windows Forms
    Réponses: 9
    Dernier message: 18/05/2004, 14h48
  4. couleurs des éléments 3D d'une appli
    Par Eugénie dans le forum MFC
    Réponses: 29
    Dernier message: 12/03/2004, 11h31
  5. [TShellListView] Tri des éléments
    Par M.Dlb dans le forum Composants VCL
    Réponses: 4
    Dernier message: 16/12/2003, 22h35

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo