接上篇文章(http://www.chenjianqu.com/show-34.html)继续。

上一篇文章已经给出了主菜单的实现,以及操作数字数组的Brick类。在介绍游戏界面的实现之前,先自定义Button控件。

mButton.py

from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt,QObject,pyqtSignal
import sys
from PyQt5.QtGui import QFont
import timeclass MySignal(QObject):doubleClick=pyqtSignal()rightClick=pyqtSignal()leftClick=pyqtSignal()class MyButton(QPushButton):def __init__(self,text,parent=None):super().__init__(text,parent)self.c=MySignal()self.lastTime=0def mousePressEvent(self,e):#当信号发射时,连接的槽函数将会自动执行。if(e.buttons()==Qt.RightButton):self.c.rightClick.emit()elif(e.buttons()==Qt.LeftButton):#左键事件处理current=time.time()delta=current-self.lastTimeself.lastTime=currentif(delta<0.2):#鼠标双击时self.c.doubleClick.emit()else:self.c.leftClick.emit()

PyQt默认的点击事件只有单击左键,若想获得鼠标的双击和右击只能自己实现。类MySignal定义三个信号量,左键单击、右键单击、左键双击。MyButton继承QPushButton,当发生鼠标事件时,会触发mousePressEvent()函数。右键按下,则发送右键单击信号量,左键按下时,判断两次按下的时间间隔,可判断是单击还是双击,发送相应的信号量。

content.py

先看构造函数:

class Content(QMainWindow):def __init__(self):super().__init__()self.size=(8,8)self.n=10self.kernal=Noneself.initMenu(self)@staticmethoddef initMenu(self):#退出游戏self.basePath=os.path.join(os.getcwd(),'Saolei')pathIcon=os.path.join(self.basePath,r'res/icon/close.png')exitAction = QAction(QIcon(pathIcon), '&退出', self)exitAction.setShortcut('Ctrl+Q')exitAction.setStatusTip('Exit application')exitAction.triggered.connect(qApp.quit)#回到主菜单pathIcon=os.path.join(self.basePath,r'res/icon/toindex.png')backAction = QAction(QIcon(pathIcon), '&回到首页', self)backAction.setShortcut('Ctrl+B')backAction.setStatusTip('Back to index')backAction.triggered.connect(self.close)self.statusBar()#创建一个菜单栏self.menubar = self.menuBar()fileMenu = self.menubar.addMenu('&File')#添加菜单fileMenu.addAction(exitAction)#添加事件fileMenu.addAction(backAction)#创建一个工具栏self.toolbar = self.addToolBar('Exit')self.toolbar.addAction(exitAction)self.toolbar.addAction(backAction)iconPath=os.path.join(os.getcwd(),r'Saolei/res/icon/window.png')#设置图标self.setWindowIcon(QIcon(iconPath))self.setWindowTitle('扫雷-游戏界面')self.setGeometry(300, 300, 300, 200)

构造函数主要实现菜单栏和工具栏的初始化,这里只添加了两个动作:完全退出程序和关闭当前页面,这段代码比较简单,没有什么需要特别解释的。

下面这个函数用于初始化并显示游戏界面,它们在主菜单界面中被调用用于开启游戏窗口。

def setSize8x8(self):self.size=(8,8)self.n=10self.initUI()self.show()
def setSize16x16(self):self.size=(16,16)self.n=30self.initUI()self.show()
def setSize16x30(self):self.n=40self.size=(16,30)self.initUI()self.show()
def setSize30x20(self):self.n=100self.size=(30,20)self.initUI()self.show()

接下来就是游戏主界面的初始化显示了。

def initUI(self):self.grid=QGridLayout()self.kernal=Brick(self.size,self.n)if(self.size[1]==8):brickSize=(80,60)self.grid.setSpacing(6)#设置组件之间的间距。elif(self.size[1]==16):brickSize=(50,40)self.grid.setSpacing(4)elif(self.size[1]==30):brickSize=(40,30)self.grid.setSpacing(1)elif(self.size[0]==30):brickSize=(40,20)self.grid.setSpacing(1)for i in range(self.size[0]):for j in range(self.size[1]):button=MyButton("")button.setObjectName(str((i,j)))button.setFixedSize(brickSize[0],brickSize[1])button.setStyleSheet("font-size:20px;background-color:rgb(230.230.230)")button.c.leftClick.connect(partial(self.display,button))button.c.rightClick.connect(partial(self.markBrick,button))button.c.doubleClick.connect(partial(self.doubleHandle,button))self.grid.addWidget(button,i,j)self.lblTimer = QLabel('时间',self)self.lblTimer.setStyleSheet('font-size:20px;font-family:"黑体";color:rgb(150,150,255)')self.lblNumber = QLabel('剩余',self)self.lblNumber.setStyleSheet('font-size:20px;font-family:"黑体";color:rgb(150,150,255)')self.timer=QTimer()self.timer.timeout.connect(self.showTimer)self.timer.start()self.initTime=time.time()lblLayout=QHBoxLayout()lblLayout.addWidget(self.lblNumber)lblLayout.addWidget(self.lblTimer)self.mainLayout=QVBoxLayout()self.mainLayout.addLayout(lblLayout)self.mainLayout.addLayout(self.grid)widget=QWidget()widget.setLayout(self.mainLayout)self.setCentralWidget(widget)

首先获得Brick对象,然后根据不同的方块数设置方块不同大小和间距。通过双重循环创建方块,并让左键、右键、左键双击信号量连接到不同的信号槽函数,使用偏函数传递参数给信号槽函数,同时为了区分各个方块,将Button对象名设置为他们的位置元组字符串。将所有的方块都放入网格布局中。接下来是添加两个Lable控件用于显示剩余的炸弹数和时间。后面就是将各个控件排列好,放置到页面上。

从上面的代码可以看到,当方块单击执行的函数是display(),右键执行markBrick()函数,双击执行doubleHandle()函数。下面先看display函数。

def display(self,btn):pos=eval(btn.objectName())#解析位置元组self.expand(pos)

pos是btn在网状布局中的位置,因为扫雷有这样的规则:单击一个值为0的方块时,它能自动将0方块周围所有的方块都掀开。为了达到这样的效果,这里定义expand()函数,递归的掀开方块。

def expand(self,pos):if(self.kernal.OpenFlagArr[pos[0],pos[1]]==1 or self.kernal.OpenFlagArr[pos[0],pos[1]]==2):#掀开这个方块的标记returnn=self.kernal.getSurplusNumber()self.lblNumber.setText('剩余数量:'+str(n))if(self.kernal.isVictory()):self.victory()self.kernal.OpenFlagArr[pos[0],pos[1]]=1n=self.kernal.getBrickArr()[pos[0],pos[1]]#获得对应的值#获取gridlayout中对应的按钮lyitem=self.grid.itemAtPosition(pos[0],pos[1])btn=lyitem.widget()btn.setStyleSheet("background-color:rgb(200,200,255)")if(n==10):btn.setText('*')btn.setStyleSheet("background-color:rgb(150,255,150)")self.failure()elif(n==0):btn.setText('')i=pos[0]j=pos[1]#四个角落的值if(i==0 and j==0):self.expand((i,j+1))self.expand((i+1,j))self.expand((i+1,j+1))elif(i==self.size[0]-1 and j==0):self.expand((i-1,j))self.expand((i,j+1))self.expand((i-1,j+1))elif(i==0 and j==self.size[1]-1):self.expand((i,j-1))self.expand((i+1,j))self.expand((i+1,j-1))elif(i==self.size[0]-1 and j==self.size[1]-1):self.expand((i,j-1))self.expand((i-1,j))self.expand((i-1,j-1))#四个边缘的值elif(i==0):self.expand((i,j-1))self.expand((i,j+1))self.expand((i+1,j-1))self.expand((i+1,j))self.expand((i+1,j+1))elif(i==self.size[0]-1):self.expand((i-1,j-1))self.expand((i-1,j))self.expand((i-1,j+1))self.expand((i,j-1))self.expand((i,j+1))elif(j==0):self.expand((i-1,j))self.expand((i-1,j+1))self.expand((i,j+1))self.expand((i+1,j))self.expand((i+1,j+1))elif(j==self.size[1]-1):self.expand((i-1,j-1))self.expand((i-1,j))self.expand((i,j-1))self.expand((i+1,j-1))self.expand((i+1,j))else:self.expand((i-1,j-1))self.expand((i-1,j))self.expand((i-1,j+1))self.expand((i,j-1))self.expand((i,j+1))self.expand((i+1,j-1))self.expand((i+1,j))self.expand((i+1,j+1))else:btn.setText(str(n))

上面这个函数定义了当鼠标点击时,方块会怎么进行变化。接下来看,右键时会把方块标记为炸弹,右键时间处理函数:

#右击,设定方块标记
def markBrick(self,btn):pos=eval(btn.objectName())if(self.kernal.OpenFlagArr[pos[0],pos[1]]==0):self.kernal.OpenFlagArr[pos[0],pos[1]]=2if(self.kernal.isVictory()):self.victory()btn.setStyleSheet("background-color:rgb(255,150,150)")else:self.kernal.OpenFlagArr[pos[0],pos[1]]=0btn.setStyleSheet("background-color:rgb(230,230,230)")n=self.kernal.getSurplusNumber()self.lblNumber.setText('剩余数量:'+str(n))

双击事件处理函数:

def doubleHandle(self,btn):pos=eval(btn.objectName())if(self.kernal.isNoBomb(pos)):i=pos[0]j=pos[1]#四个角落的值if(i==0 and j==0):self.dbButton((i,j+1))self.dbButton((i+1,j))self.dbButton((i+1,j+1))elif(i==self.size[0]-1 and j==0):self.dbButton((i-1,j))self.dbButton((i,j+1))self.dbButton((i-1,j+1))elif(i==0 and j==self.size[1]-1):self.dbButton((i,j-1))self.dbButton((i+1,j))self.dbButton((i+1,j-1))elif(i==self.size[0]-1 and j==self.size[1]-1):self.dbButton((i,j-1))self.dbButton((i-1,j))self.dbButton((i-1,j-1))#四个边缘的值elif(i==0):self.dbButton((i,j-1))self.dbButton((i,j+1))self.dbButton((i+1,j-1))self.dbButton((i+1,j))self.dbButton((i+1,j+1))elif(i==self.size[0]-1):self.dbButton((i-1,j-1))self.dbButton((i-1,j))self.dbButton((i-1,j+1))self.dbButton((i,j-1))self.dbButton((i,j+1))elif(j==0):self.dbButton((i-1,j))self.dbButton((i-1,j+1))self.dbButton((i,j+1))self.dbButton((i+1,j))self.dbButton((i+1,j+1))elif(j==self.size[1]-1):self.dbButton((i-1,j-1))self.dbButton((i-1,j))self.dbButton((i,j-1))self.dbButton((i+1,j-1))self.dbButton((i+1,j))else:self.dbButton((i-1,j-1))self.dbButton((i-1,j))self.dbButton((i-1,j+1))self.dbButton((i,j-1))self.dbButton((i,j+1))self.dbButton((i+1,j-1))self.dbButton((i+1,j))self.dbButton((i+1,j+1))def dbButton(self,pos):lyitem=self.grid.itemAtPosition(pos[0],pos[1])btn=lyitem.widget()self.display(btn)

完整代码:https://github.com/chenjianqu/MineSweeper_PyQt5

基于PyQt的扫雷游戏实现_下篇相关推荐

  1. 基于PyQt的扫雷游戏实现_上篇

    个人博客:http://www.chenjianqu.com/ 原文链接:http://www.chenjianqu.com/show-34.html 最近突然很喜欢玩<扫雷>这个小游戏, ...

  2. 基于java的扫雷论文_毕业论文基于java的扫雷游戏的设计与实现.doc

    毕业论文基于java的扫雷游戏的设计与实现 JAVA程序设计A课程设计 题 目 基于JAVA的扫雷游戏的设计与实现 院 (系) 信息工程学院 专 业 班 级 计算机科学与技术(2)班 学 生 姓 名 ...

  3. 基于java的扫雷论文_毕业论文基于JAVA的扫雷游戏设计

    毕业论文基于JAVA的扫雷游戏设计 课 程 设 计 报 告 课程名称: 计算机技术综合课程设计 题 目: 基于JAVA语言的扫雷游戏设计 学 院: 信息工程 系: 计算机 专 业: 计算机科学与技术 ...

  4. 基于EasyX的扫雷游戏

    基于EasyX的扫雷游戏 一.预备知识 二.游戏逻辑 1.扫雷元素 2.扫雷规则 三.游戏设计 1.地图设计 2.点击设计 3.结束设计 4.整体设计 一.预备知识 1.使用EasyX必须要知道的一些 ...

  5. 基于jQuery经典扫雷游戏源码

    分享一款基于jQuery经典扫雷游戏源码.这是一款网页版扫雷小游戏特效代码下载.效果图如下: 在线预览   源码下载 实现的代码. html代码: <center><h1>jQ ...

  6. 扫雷程序设计Android答辩,基于QT的扫雷游戏设计与实现扫雷游戏答辩.ppt

    基于QT的扫雷游戏设计与实现扫雷游戏答辩.ppt 程序设计 基于QT语言的扫雷游戏,答辩学生,一.分析扫雷游戏的基本功能,1.从外观上分析 方块 笑脸 计时器 有雷标识 无雷标识 胜利画面 失败画面, ...

  7. 基于java的扫雷游戏设计01

    开发工具eclipse,jdk1.7 扫雷:游戏说明 扫雷是一种具有迷惑性的对记忆和推理能力的简单测试,它是长久以来最受欢迎的 Windows 游戏之一. 游戏目标:找出空方块,同时避免触雷. 启动游 ...

  8. 基于java的扫雷游戏的设计

    扫雷游戏的基本功能:点击鼠标左键于未知区域,如果未知区域有雷,游戏停止,显示所有的地雷.如果没雷,则显示周围雷数,如果周围没雷,则再查看周围八个区域是否有雷直到有雷为止并显示,玩家需要尽快找出雷区中的 ...

  9. 基于python的2048游戏设计_用python写一个2048游戏

    self.randomGenerateNumberself.randomGenerateNumber 然后,当玩家按下方向键(↑↓←→)时,这个二维列表要根据玩家的操作指令进行更新,主要分为两个部分: ...

最新文章

  1. 手把手教你熟悉Git操作
  2. 【FPGA】SRIO IP核系统介绍之事务类型(Transaction)
  3. 乔布斯成功的七条秘诀
  4. Android --- Android Studio 内无法直接运行 main 方法
  5. c语言单链表中头结点的创立,一个关于C语言链表头结点的问题
  6. anaconda安装keras_一定要看的Tensorflow-GPU+Keras安装教程
  7. 服务器系统盘单独硬盘,我的服务器今天加了个硬盘,可以实现双系统吗?
  8. r语言清除变量_R语言:结构方程模型、潜变量分析
  9. 简单的Python购物流程
  10. 新唐单片机选型手册_Nuvoton新唐8位8051单片机选型指南
  11. ESP32S 数据手册
  12. 放弃有道词典和有道云笔记
  13. 数独大师级技巧_数独游戏技巧(图解)
  14. Pytorch入门教程学习笔记(六)循环神经网络RNN(学周杰伦写歌)
  15. 示波器基本原理之一:带宽
  16. python求三重积分_python Scipy积分运算大全(一重、二重及三重积分)
  17. 如何保持较长时间的专注
  18. shell 编程 小案例
  19. 通过setTimeout 实现 setInterval
  20. 手机 查看java源码_pin.java 源代码在线查看 - 一个专门为手机写的程序 资源下载 虫虫电子下载站...

热门文章

  1. php压缩zip文件类
  2. 11 Django组件-分页器
  3. Lucene中string docvalues使用utf-16的优化
  4. U811.1接口EAI系列之二-BOM构成-委外BOM构成--VB语言
  5. “Lephone.Data.DbEntry”的类型初始值设定项引发异常。(DbEntry.net3.9)
  6. 11月14日,西安,听说有一节百度AI快车道课程在等你上车
  7. 光流估计——从传统方法到深度学习
  8. 奥迪推出大型自动驾驶数据集A2D2
  9. 基于YOLOv3 与CRNN的中文自然场景文字检测与识别
  10. 5行Python 代码就能让你的电脑永不息屏