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 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 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 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
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 "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 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 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
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++; } }
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
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); };
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
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);
Je n'arrive d'ailleurs pas à comprendre ce que fais 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);
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...)
Partager