前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PyQt5 创建拼图游戏

PyQt5 创建拼图游戏

作者头像
用户6021899
发布2019-12-10 16:40:35
1.5K0
发布2019-12-10 16:40:35
举报

本篇代码由PtQt4官方example代码升级而来。其实现的功能是将图片分割后随机打散,以供用户拖放拼图。

源代码如下:

代码语言:javascript
复制
#!/usr/bin/env python
## Copyright (C) 2010 Riverbank Computing Limited
import random
from PyQt5 import QtCore, QtGui, QtWidgets
import puzzle_qrc


class PuzzleWidget(QtWidgets.QWidget):
    puzzleCompleted = QtCore.pyqtSignal()
    
    def __init__(self, parent=None):
        super().__init__(parent)
        self.piecePixmaps = []
        self.pieceRects = []
        self.pieceLocations = []
        self.highlightedRect = QtCore.QRect()
        self.inPlace = 0
        self.setAcceptDrops(True)
        self.setMinimumSize(400, 400)
        self.setMaximumSize(400, 400)
    def clear(self):
        self.pieceLocations = []
        self.piecePixmaps = []
        self.pieceRects = []
        self.highlightedRect = QtCore.QRect()
        self.inPlace = 0
        self.update()
        
    def dragEnterEvent(self, event):
        if event.mimeData().hasFormat('image/x-puzzle-piece'):
            event.accept()
        else:
            event.ignore()
        #ok
        
    def dragLeaveEvent(self, event):
        print("leave0")
        updateRect = self.highlightedRect
        self.highlightedRect = QtCore.QRect()
        self.update(updateRect)
        event.accept()
        print("leave1")
        
    def dragMoveEvent(self, event):
        updateRect = self.highlightedRect.united(self.targetSquare(event.pos()))
        if event.mimeData().hasFormat('image/x-puzzle-piece') and self.findPiece(self.targetSquare(event.pos())) == -1:
            self.highlightedRect = self.targetSquare(event.pos())
            event.setDropAction(QtCore.Qt.MoveAction)
            event.accept()
        else:
            self.highlightedRect = QtCore.QRect()
            event.ignore()
        self.update(updateRect)
        
    def dropEvent(self, event):
        if event.mimeData().hasFormat('image/x-puzzle-piece') and self.findPiece(self.targetSquare(event.pos())) == -1:
            pieceData = event.mimeData().data('image/x-puzzle-piece')
            dataStream = QtCore.QDataStream(pieceData, QtCore.QIODevice.ReadOnly)
            square = self.targetSquare(event.pos())
            pixmap = QtGui.QPixmap()
            location = QtCore.QPoint()
            dataStream >> pixmap >> location
            self.pieceLocations.append(location)
            self.piecePixmaps.append(pixmap)
            self.pieceRects.append(square)
            self.hightlightedRect = QtCore.QRect()
            self.update(square)
            event.setDropAction(QtCore.Qt.MoveAction)
            event.accept()
            if location == QtCore.QPoint(square.x() / 80, square.y() / 80):
                self.inPlace += 1
                if self.inPlace == 25:
                    self.puzzleCompleted.emit()
        else:
            self.highlightedRect = QtCore.QRect()
            event.ignore()
            
    def findPiece(self, pieceRect):
        try:
            return self.pieceRects.index(pieceRect)
        except ValueError:
            return -1
            
    def mousePressEvent(self, event):
        square = self.targetSquare(event.pos())
        found = self.findPiece(square)
        if found == -1:
            return
        location = self.pieceLocations[found]
        pixmap = self.piecePixmaps[found]
        del self.pieceLocations[found]
        del self.piecePixmaps[found]
        del self.pieceRects[found]
        if location == QtCore.QPoint(square.x() / 80, square.y() / 80):
            self.inPlace -= 1
        self.update(square)
        itemData = QtCore.QByteArray()
        dataStream = QtCore.QDataStream(itemData, QtCore.QIODevice.WriteOnly)
        dataStream << pixmap << location
        mimeData = QtCore.QMimeData()
        mimeData.setData('image/x-puzzle-piece', itemData)
        drag = QtGui.QDrag(self)
        drag.setMimeData(mimeData)
        drag.setHotSpot(event.pos() - square.topLeft())
        drag.setPixmap(pixmap)
        
        if drag.exec_(QtCore.Qt.MoveAction) != QtCore.Qt.MoveAction:
            self.pieceLocations.insert(found, location)
            self.piecePixmaps.insert(found, pixmap)
            self.pieceRects.insert(found, square)
            self.update(self.targetSquare(event.pos()))
            if location == QtCore.QPoint(square.x() / 80, square.y() / 80):
                self.inPlace += 1

    def paintEvent(self, event):
        painter = QtGui.QPainter()
        painter.begin(self)
        painter.fillRect(event.rect(), QtCore.Qt.white)
        if self.highlightedRect.isValid():
            painter.setBrush(QtGui.QColor("#ffcccc"))
            painter.setPen(QtCore.Qt.NoPen)
            painter.drawRect(self.highlightedRect.adjusted(0, 0, -1, -1))
        for rect, pixmap in zip(self.pieceRects, self.piecePixmaps):
            painter.drawPixmap(rect, pixmap)
        painter.end()     
          
    def targetSquare(self, position):
        return QtCore.QRect(position.x() // 80 * 80, position.y() // 80 * 80, 80, 80)
代码语言:javascript
复制
class PiecesList(QtWidgets.QListWidget):

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setDragEnabled(True)
        self.setViewMode(QtWidgets.QListView.IconMode)
        self.setIconSize(QtCore.QSize(60, 60))
        self.setSpacing(10)
        self.setAcceptDrops(True)
        self.setDropIndicatorShown(True)
        
    def dragEnterEvent(self, event):
        if event.mimeData().hasFormat('image/x-puzzle-piece'):
            event.accept()
        else:
            event.ignore()
        #ok
    def dragMoveEvent(self, event):
        if event.mimeData().hasFormat('image/x-puzzle-piece'):
            event.setDropAction(QtCore.Qt.MoveAction)
            event.accept()
        else:
            event.ignore()
        print('dragmove')
        #ok
        
    def dropEvent(self, event):
        if event.mimeData().hasFormat('image/x-puzzle-piece'):
            pieceData = event.mimeData().data('image/x-puzzle-piece')
            dataStream = QtCore.QDataStream(pieceData, QtCore.QIODevice.ReadOnly)
            pixmap = QtGui.QPixmap()
            location = QtCore.QPoint()
            dataStream >> pixmap >> location
            self.addPiece(pixmap, location)
            event.setDropAction(QtCore.Qt.MoveAction)
            event.accept()
        else:
            event.ignore()
        #ok
    def addPiece(self, pixmap, location):
        pieceItem = QtWidgets.QListWidgetItem(self)
        pieceItem.setIcon(QtGui.QIcon(pixmap))
        pieceItem.setData(QtCore.Qt.UserRole, pixmap)
        pieceItem.setData(QtCore.Qt.UserRole+1, location)
        pieceItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsDragEnabled)
        #ok
    def startDrag(self, supportedActions):
        item = self.currentItem()
        itemData = QtCore.QByteArray()
        dataStream = QtCore.QDataStream(itemData, QtCore.QIODevice.WriteOnly)
        pixmap = QtGui.QPixmap(item.data(QtCore.Qt.UserRole))
        location = item.data(QtCore.Qt.UserRole+1)
        dataStream << pixmap << location
        mimeData = QtCore.QMimeData()
        mimeData.setData('image/x-puzzle-piece', itemData)
        drag = QtGui.QDrag(self)
        drag.setMimeData(mimeData)
        drag.setHotSpot(QtCore.QPoint(pixmap.width()/2, pixmap.height()/2))
        drag.setPixmap(pixmap)
        print("startDrag1")
        if drag.exec_(QtCore.Qt.MoveAction) == QtCore.Qt.MoveAction:
            print("move action")
            self.takeItem(self.row(item))
        else:
            print("else")
        print("startDrag99")
代码语言:javascript
复制
class MainWindow(QtWidgets.QMainWindow):

    def __init__(self, parent=None):
        super().__init__(parent)
        self.puzzleImage = QtGui.QPixmap()
        self.setupMenus()
        self.setupWidgets()
        self.setSizePolicy(QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed))
        self.setWindowTitle("Puzzle")
        
    def openImage(self, path=None):
        if not path:
            path, filetype = QtWidgets.QFileDialog.getOpenFileName(self, "Open Image", '',
                    "Image Files (*.png *.jpg *.bmp)")
        if path:
            newImage = QtGui.QPixmap()
            if not newImage.load(path):
                QtWidgets.QMessageBox.warning(self, "Open Image", "The image file could not be loaded.", QtWidgets.QMessageBox.Cancel)
                return
            self.puzzleImage = newImage
            self.setupPuzzle()
    def setCompleted(self):
        QtWidgets.QMessageBox.information(self, "Puzzle Completed",
                "Congratulations! You have completed the puzzle!\nClick OK "
                "to start again.",
                QtWidgets.QMessageBox.Ok)
        self.setupPuzzle()
        
    def setupPuzzle(self):
        size = min(self.puzzleImage.width(), self.puzzleImage.height())
        self.puzzleImage = self.puzzleImage.copy(
                (self.puzzleImage.width() - size)/2,
                (self.puzzleImage.height() - size)/2, size, size).scaled(400, 400, QtCore.Qt.IgnoreAspectRatio, QtCore.Qt.SmoothTransformation)
        self.piecesList.clear()
        for y in range(5):
            for x in range(5):
                pieceImage = self.puzzleImage.copy(x*80, y*80, 80, 80)
                self.piecesList.addPiece(pieceImage, QtCore.QPoint(x,y))
        random.seed(QtGui.QCursor.pos().x() ^ QtGui.QCursor.pos().y())
        for i in range(self.piecesList.count()):
            if random.random() < 0.5:
                item = self.piecesList.takeItem(i)
                self.piecesList.insertItem(0, item)
        self.puzzleWidget.clear()
    def setupMenus(self):
        fileMenu = self.menuBar().addMenu("&File")
        openAction = fileMenu.addAction("&Open...")
        openAction.setShortcut("Ctrl+O")
        exitAction = fileMenu.addAction("E&xit")
        exitAction.setShortcut("Ctrl+Q")
        gameMenu = self.menuBar().addMenu("&Game")
        restartAction = gameMenu.addAction("&Restart")
        openAction.triggered.connect(self.openImage)
        exitAction.triggered.connect(QtWidgets.qApp.quit)
        restartAction.triggered.connect(self.setupPuzzle)
        
    def setupWidgets(self):
        frame = QtWidgets.QFrame()
        frameLayout = QtWidgets.QHBoxLayout(frame)
        self.piecesList = PiecesList()
        self.puzzleWidget = PuzzleWidget()
        self.puzzleWidget.puzzleCompleted.connect(self.setCompleted, QtCore.Qt.QueuedConnection)
        frameLayout.addWidget(self.piecesList)
        frameLayout.addWidget(self.puzzleWidget)
        self.setCentralWidget(frame)


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.openImage(':/images/example.jpg')
    window.show()
    sys.exit(app.exec_())

其用到的金丝猴图片保存在资源文件puzzle_qrc.py 中 。也可在程序文件菜单另打开其它任意图片用于拼图游戏。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-12-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python可视化编程机器学习OpenCV 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档