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

Discussion :

Deplacement de pièce d'un puzzle

  1. #1
    Nouveau Candidat au Club
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    2
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2010
    Messages : 2
    Points : 1
    Points
    1
    Par défaut
    Tout d'abord Bonjour et Bonne Année !!!

    Je débute avec qT et je travaille actuellement à l'élaboration d'un Puzzle.
    Pour réaliser le damier (au centre) j'ai utiliser un QGridLayout où chaque case contient un qLabel qui contient une image d'une case vide.

    Sur la droite j'ai aussi un QGridLayout où chaque case contient un QLabel qui contient l'image d'une pièce.

    Pour gérer le fait de pouvoir déplacer les pièces j'avais comme projet de :

    - Récupérer l'adresse du widget sur lequel l'utilisateur a cliqué (QLabel* focus)
    - Si cette adresse correspond à un QLabel contenu dans les QGridlayout précédent, "grisé" ce QLabel et stocker son adresse dans une variable qu'on appellera ici "buffer".
    - Si le buffer pointait sur NULL, il stocke à présent le QLabel ou on a cliqué
    - S'il pointait déjà sur une pièce, on échange les 2 QLabel (celui ou l'utilisateur à cliqué et celui contenu dans buffer)

    - J'ai pensé au drag and drop mais cela m'a l'air encore plus compliqué...

    Je pense ajouter un signal à ma classe "MaFenetre" qui sera du type "l'utilisateur à cliqué" et 2 attributs "QWidget * focus" et "QLabel *buffer". Puis ensuite connecter ce signal à un slot "echange" où je me servirai de ces 2 attributs.

    Le problème est que je ne sais pas comment récupérer l'adresse du Widget sur lequel l'utilisateur à cliquer. Je pense qu'il faut jouer avec les QMouseEvent etc...
    Je me demandai aussi s'il y avait une méthode simple pour vérifier que le widget sur lequel on a cliqué est bien une pièce (cad s'il est contenu dans un de mes 2QGridLayout et/ou s'il est de type QLabel). Je peux toujours faire un "gros if" mais bon :/

    Après de nombreuses recherches et de nombreuses compilations infructeuses, j'ai tout de même réussi à avancer un peu, je me suis surtout aidé de l'exemple "puzzle" de la doc de qT. Je vous link ici les parties importants du code.


    Code MainWindows.h

    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
    class MainWindow : public QMainWindow
        {
            Q_OBJECT
     
        public:
            MainWindow(QWidget *parent = 0);
     
        public slots:
            void openImage(const QString &path = QString());
            void setupPuzzle();
     
        private slots:
            void setCompleted();
     
        private:
            void setupMenus();
            void setupWidgets();
     
            QPixmap puzzleImage;
            PiecesList *piecesList;
            PuzzleWidget *puzzleWidget;
        };
    Code intéressant dans MainWindow.cpp


    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
    void MainWindow::setupWidgets()
        {
            QFrame *frame = new QFrame;
            QHBoxLayout *frameLayout = new QHBoxLayout(frame);
     
            piecesList = new PiecesList;
            puzzleWidget = new PuzzleWidget;
     
            connect(puzzleWidget, SIGNAL(puzzleCompleted()),
                    this, SLOT(setCompleted()), Qt::QueuedConnection);
     
            frameLayout->addWidget(piecesList);
            frameLayout->addWidget(puzzleWidget);
            setCentralWidget(frame);
        }
     
        void MainWindow::setupPuzzle()
        {
            int size = qMin(puzzleImage.width(), puzzleImage.height());
            puzzleImage = puzzleImage.copy((puzzleImage.width() - size)/2,
                (puzzleImage.height() - size)/2, size, size).scaled(400,
                    400, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
     
            piecesList->clear();
     
            for (int y = 0; y < 5; ++y) {
                for (int x = 0; x < 5; ++x) {
                    QPixmap pieceImage = puzzleImage.copy(x*80, y*80, 80, 80);
                    piecesList->addPiece(pieceImage, QPoint(x, y));
                }
            }
     
            qsrand(QCursor::pos().x() ^ QCursor::pos().y());
     
            for (int i = 0; i < piecesList->count(); ++i) {
                if (int(2.0*qrand()/(RAND_MAX+1.0)) == 1) {
                    QListWidgetItem *item = piecesList->takeItem(i);
                    piecesList->insertItem(0, item);
                }
            }
     
            puzzleWidget->clear();
        }
    Code "intéressant" dans puzzlewidget.h

    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
     class PuzzleWidget : public QWidget
        {
            Q_OBJECT
     
        public:
            PuzzleWidget(QWidget *parent = 0);
            void clear();
     
        signals:
            void puzzleCompleted();
     
        protected:
            void mousePressEvent(QMouseEvent *event);
     
        private:
            int findPiece(const QRect &pieceRect) const;
            const QRect targetSquare(const QPoint &position) const;
     
            QList<QPixmap> piecePixmaps;
            QList<QRect> pieceRects;
            QList<QPoint> pieceLocations;
            QRect highlightedRect;
            int inPlace;
        };
    Code "interessant" dans puzzlewidget.cpp

    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
    PuzzleWidget::PuzzleWidget(QWidget *parent)
            : QWidget(parent)
        {
            setAcceptDrops(true);
            setMinimumSize(400, 400);
            setMaximumSize(400, 400);
        }
     
        const QRect PuzzleWidget::targetSquare(const QPoint &position) const
        {
            return QRect(position.x()/80 * 80, position.y()/80 * 80, 80, 80);
        }
     
        int PuzzleWidget::findPiece(const QRect &pieceRect) const
        {
            for (int i = 0; i < pieceRects.size(); ++i) {
                if (pieceRect == pieceRects[i]) {
                    return i;
                }
            }
            return -1;
        }
     
     
        void PuzzleWidget::mousePressEvent(QMouseEvent *event)
        {
            QRect square = targetSquare(event->pos());
            int found = findPiece(square);
     
            if (found == -1)
                return;
     
            QPoint location = pieceLocations[found];
            QPixmap pixmap = piecePixmaps[found];
            pieceLocations.removeAt(found);
            piecePixmaps.removeAt(found);
            pieceRects.removeAt(found);
     
            if (location == QPoint(square.x()/80, square.y()/80))
                inPlace--;
     
            update(square);
     
            QByteArray itemData;
            QDataStream dataStream(&itemData, QIODevice::WriteOnly);
     
            dataStream << pixmap << location;
     
            QMimeData *mimeData = new QMimeData;
            mimeData->setData("image/x-puzzle-piece", itemData);
     
            QDrag *drag = new QDrag(this);
            drag->setMimeData(mimeData);
            drag->setHotSpot(event->pos() - square.topLeft());
            drag->setPixmap(pixmap);
     
            if (!(drag->exec(Qt::MoveAction) == Qt::MoveAction)) {
                pieceLocations.insert(found, location);
                piecePixmaps.insert(found, pixmap);
                pieceRects.insert(found, square);
                update(targetSquare(event->pos()));
     
                if (location == QPoint(square.x()/80, square.y()/80))
                    inPlace++;
            }
        }
    Code de piecelist.h

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class PiecesList : public QListWidget
        {
            Q_OBJECT
     
        public:
            PiecesList(QWidget *parent = 0);
            void addPiece(QPixmap pixmap, QPoint location);
     
        protected:
            void dragEnterEvent(QDragEnterEvent *event);
            void dragMoveEvent(QDragMoveEvent *event);
            void dropEvent(QDropEvent *event);
            void startDrag(Qt::DropActions supportedActions);
        };
    La partie vraiment intéressante est celle ci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
        void PuzzleWidget::mousePressEvent(QMouseEvent *event)
        {
            QRect square = targetSquare(event->pos());
            int found = findPiece(square);
     
            if (found == -1)
                return;
     
            QPoint location = pieceLocations[found];
            QPixmap pixmap = piecePixmaps[found];
            pieceLocations.removeAt(found);
            piecePixmaps.removeAt(found);
            pieceRects.removeAt(found);
    Ce que j'ai compris c'est donc qu'il récupère le "square" où l'utilisateur à cliqué avec (en gros) cette opération :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    QRect square(event->x()/80 * 80, event->y()/80 * 80, 80, 80);
    Je n'arrive d'ailleurs pas à comprendre ce que fais cette opération :/

    Puis il essaye de trouver la pièce qui correspond à ce carré ( fonction findpiece) celle ci retourne le numéro de la pièce.
    J'en ai conclu que chaque pièce avait le meme index dans les 3 QList :
    - pieceRects qui stockent donc le rectangle clickable correspondant à la pièce
    - piecePixmaps stockent l'image de la pièce
    - pieceLocations qui sert à vérifier si la pièce est au bonne endroit ou pas sur le puzzle

    Je n'ai pas réussi à trouver où toutes ces QList sont initialisées si quelqu'un sait...
    J'ai donc comme projet de créer une Qlist<QRect> et une QList<QLabel> (chaque pièce aura le même index dans les 2 Qlist)
    Ma liste <Qlabel> correspondra aux pièces affichées (j'utilise des QLabel qui contiennet un QPixmap).
    Ma liste <Qrect> contenant tous les "square" correspondant à chaque pièce
    Puis de créer une fonction qui récupère la position du click et vérifie si cette position est comprise dans un des Qlist<QRect>, si oui elle renverra le numéro d'index.

    Cependant je ne vois pas d'initialisation "légère" pour Qlist<QRect>.
    (je compte récupérer les coordonnées les coordonnées des 4 sommets de chaque pièce en utilisant 2 Qlcdnumber pour un grand puzzle avec fenêtre à "scroll" cela me semble ingérable...)

  2. #2
    Membre actif Avatar de cayou66
    Inscrit en
    Décembre 2008
    Messages
    286
    Détails du profil
    Informations personnelles :
    Âge : 36

    Informations forums :
    Inscription : Décembre 2008
    Messages : 286
    Points : 273
    Points
    273
    Par défaut
    Salut
    si j'ai bien compris tu abandonne l'idée du drag&drop, pourquoi?
    si tu regardes les exemples dans Qt concernant le principe, tu peux récupérer les informations de l'objet au drag, le détruire, puis le reconstruire avec ces informations lors du drop, et tu peux même le dessiner sous la souris pendant la manip.
    J'ai pas lu ton code, je ne connais pas la complexité, mais tu pourrais déjà essayer avec des boutons, pour commencer
    Ta méthode m'a l'air assez complexe...

  3. #3
    Nouveau Candidat au Club
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    2
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2010
    Messages : 2
    Points : 1
    Points
    1
    Par défaut
    En fait je ne vois pas de méthode facile pour savoir sur quelle pièce l'utilisateur a cliqué

    J'aimerai avoir un signal qui me dis "on a cliqué sur une de mes pièces" et un algo simple pour savoir sur laquelle l'utilisateur a cliqué.

    Après pour le drag and drop, on verra cela plus tard, pour le moment je me contenterai d'un
    - L'utilisateur clique sur la pièce qu'il veut positionner, celle ci passe en surbrillance, l'utilisateur clique sur la case où il veut la mettre et pouf le mouvement est fait.

    A moins qu'il y est un truc super simple du genre "l'utilisateur clique dessus, paf l'objet passe en mode "drag".

Discussions similaires

  1. [8] Rotation pièces puzzle
    Par mehun dans le forum ActionScript 1 & ActionScript 2
    Réponses: 2
    Dernier message: 25/02/2013, 19h04
  2. Deplacement pièce jeu de Dame
    Par totomania dans le forum GTK+ avec C & C++
    Réponses: 47
    Dernier message: 22/06/2012, 15h28
  3. Découper image en pièce de puzzle
    Par shaytan dans le forum Débuter
    Réponses: 2
    Dernier message: 14/12/2009, 23h14
  4. Puzzle 72 pièces en flash
    Par Ivady dans le forum Projets
    Réponses: 9
    Dernier message: 15/02/2009, 22h08
  5. [VB6] [Form] Interdire le déplacement d'une feuille
    Par Loïc dans le forum VB 6 et antérieur
    Réponses: 9
    Dernier message: 23/09/2002, 15h02

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