python -- PyQt5(designer)中文详细教程(十一)实例:俄罗斯方块游戏

俄罗斯方块游戏

本章我们要制作⼀个俄罗斯方块游戏。

Tetris

 译注:称呼:方块是由四个小方格组成的

俄罗斯方块游戏是世界上最流行的游戏之⼀。是由⼀名叫Alexey Pajitnov的俄罗斯程序员在1985年制作的,从那时起,这个游戏就风靡了各个游戏平台。 俄罗斯⽅块归类为下落块迷宫游戏。游戏有7个基本形状:S、Z、T、L、反向L、 直线、⽅块,每个形状都由4个方块组成,方块最终都会落到屏幕底部。所以玩家 通过控制形状的左右位置和旋转,让每个形状都以合适的位置落下,如果有⼀行全部被方块填充,这行就会消失,并且得分。游戏结束的条件是有形状接触到了屏幕 顶部。

方块展示:

PyQt5是专为创建图形界面产⽣的,⾥⾯⼀些专⻔为制作游戏⽽开发的组件,所 以PyQt5是能制作小游戏的。

from PyQt5.QtWidgets import QMainWindow, QFrame, QDesktopWidget, QApplication
from PyQt5.QtCore import Qt, QBasicTimer, pyqtSignal
from PyQt5.QtGui import QPainter, QColor
import sys, random

class Tetris(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()
    def initUI(self):
# '''initiates application UI'''
        self.tboard = Board(self)
        self.setCentralWidget(self.tboard)
        self.statusbar = self.statusBar()
        self.tboard.msg2Statusbar[str].connect(self.statusbar.showMessage)
        self.tboard.start()
        self.resize(300, 500)
        self.center()
        self.setWindowTitle('Tetris')
        self.show()
    def center(self):
# '''centers the window on the screen'''
        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.move((screen.width()-size.width())/2, (screen.height()-size.height())/2)
class Board(QFrame):
    msg2Statusbar = pyqtSignal(str)
    BoardWidth = 10
    BoardHeight = 22
    Speed = 300
    def __init__(self, parent):
        super().__init__(parent)
        self.initBoard()
    def initBoard(self):
#  '''initiates board'''
        self.timer = QBasicTimer()
        self.isWaitingAfterLine = False
        self.curX = 0
        self.curY = 0
        self.numLinesRemoved = 0
        self.board = []
        self.setFocusPolicy(Qt.StrongFocus)
        self.isStarted = False
        self.isPaused = False
        self.clearBoard()
    def shapeAt(self, x, y):
# '''determines shape at the board position'''
        return self.board[(y * Board.BoardWidth) + x]
    def setShapeAt(self, x, y, shape):
# '''sets a shape at the board'''
        self.board[(y * Board.BoardWidth) + x] = shape
    def squareWidth(self):
#  '''returns the width of one square'''
        return self.contentsRect().width() // Board.BoardWidth
    def squareHeight(self):
#  '''returns the height of one square'''
        return self.contentsRect().height() // Board.BoardHeight
    def start(self):
# '''starts game'''
        if self.isPaused:
            return
        self.isStarted = True
        self.isWaitingAfterLine = False
        self.numLinesRemoved = 0
        self.clearBoard()
        self.msg2Statusbar.emit(str(self.numLinesRemoved))
        self.newPiece()
        self.timer.start(Board.Speed, self)
    def pause(self):
# '''pauses game'''
        if not self.isStarted:
            return
        self.isPaused = not self.isPaused
        if self.isPaused:
            self.timer.stop()
            self.msg2Statusbar.emit("paused")
        else:
            self.timer.start(Board.Speed, self)
            self.msg2Statusbar.emit(str(self.numLinesRemoved))
        self.update()
    def paintEvent(self, event):
# '''paints all shapes of the game'''
        painter = QPainter(self)
        rect = self.contentsRect()
        boardTop = rect.bottom() - Board.BoardHeight * self.squareHeight()
        for i in range(Board.BoardHeight):
            for j in range(Board.BoardWidth):
                shape = self.shapeAt(j, Board.BoardHeight - i - 1)
                if shape != Tetrominoe.NoShape:
                    self.drawSquare(painter,
                    rect.left() + j * self.squareWidth(),
                    boardTop + i * self.squareHeight(), shape)
        if self.curPiece.shape() != Tetrominoe.NoShape:
            for i in range(4):
                x = self.curX + self.curPiece.x(i)
                y = self.curY - self.curPiece.y(i)
                self.drawSquare(painter, rect.left() + x * self.squareWidth(),
                boardTop + (Board.BoardHeight - y - 1) * self.squareHeight(),
                self.curPiece.shape())
    def keyPressEvent(self, event):
# '''processes key press events'''
        if not self.isStarted or self.curPiece.shape() == Tetrominoe.NoShape:
            super(Board, self).keyPressEvent(event)
            return
        key = event.key()
        if key == Qt.Key_P:
            self.pause()
            return
        if self.isPaused:
            return
        elif key == Qt.Key_Left:
            self.tryMove(self.curPiece, self.curX - 1, self.curY)
        elif key == Qt.Key_Right:
            self.tryMove(self.curPiece, self.curX + 1, self.curY)
        elif key == Qt.Key_Down:
            self.tryMove(self.curPiece.rotateRight(), self.curX, self.curY)
        elif key == Qt.Key_Up:
            self.tryMove(self.curPiece.rotateLeft(), self.curX, self.curY)
        elif key == Qt.Key_Space:
            self.dropDown()
        elif key == Qt.Key_D:
            self.oneLineDown()
        else:
            super(Board, self).keyPressEvent(event)
    def timerEvent(self, event):
# '''handles timer event'''
        if event.timerId() == self.timer.timerId():
            if self.isWaitingAfterLine:
                self.isWaitingAfterLine = False
                self.newPiece()
            else:
                self.oneLineDown()
        else:
            super(Board, self).timerEvent(event)
    def clearBoard(self):
# '''clears shapes from the board'''
        for i in range(Board.BoardHeight * Board.BoardWidth):
            self.board.append(Tetrominoe.NoShape)
    def dropDown(self):
# '''drops down a shape'''
        newY = self.curY
        while newY > 0:
            if not self.tryMove(self.curPiece, self.curX, newY - 1):
                break
        newY -= 1
        self.pieceDropped()
    def oneLineDown(self):
# '''goes one line down with a shape'''
        if not self.tryMove(self.curPiece, self.curX, self.curY - 1):
            self.pieceDropped()
    def pieceDropped(self):
# '''after dropping shape, remove full lines and create new shape'''
        for i in range(4):
            x = self.curX + self.curPiece.x(i)
            y = self.curY - self.curPiece.y(i)
            self.setShapeAt(x, y, self.curPiece.shape())
            self.removeFullLines()
        if not self.isWaitingAfterLine:
            self.newPiece()
    def removeFullLines(self):
# '''removes all full lines from the board'''
        numFullLines = 0
        rowsToRemove = []
        for i in range(Board.BoardHeight):
            n = 0
            for j in range(Board.BoardWidth):
                if not self.shapeAt(j, i) == Tetrominoe.NoShape:
                    n = n + 1
                    if n == 10:
                        rowsToRemove.append(i)
                        rowsToRemove.reverse()
        for m in rowsToRemove:
            for k in range(m, Board.BoardHeight):
                for l in range(Board.BoardWidth):
                    self.setShapeAt(l, k, self.shapeAt(l, k + 1))
        numFullLines = numFullLines + len(rowsToRemove)
        if numFullLines > 0:
            self.numLinesRemoved = self.numLinesRemoved + numFullLines
            self.msg2Statusbar.emit(str(self.numLinesRemoved))
            self.isWaitingAfterLine = True
            self.curPiece.setShape(Tetrominoe.NoShape)
            self.update()
    def newPiece(self):
# '''creates a new shape'''
        self.curPiece = Shape()
        self.curPiece.setRandomShape()
        self.curX = Board.BoardWidth // 2 + 1
        self.curY = Board.BoardHeight - 1 + self.curPiece.minY()
        if not self.tryMove(self.curPiece, self.curX, self.curY):
            self.curPiece.setShape(Tetrominoe.NoShape)
            self.timer.stop()
            self.isStarted = False
            self.msg2Statusbar.emit("Game over")
    def tryMove(self, newPiece, newX, newY):
# '''tries to move a shape'''
        for i in range(4):
            x = newX + newPiece.x(i)
            y = newY - newPiece.y(i)
            if x < 0 or x >= Board.BoardWidth or y < 0 or y >= Board.BoardHeight:
                return False
            if self.shapeAt(x, y) != Tetrominoe.NoShape:
                return False
        self.curPiece = newPiece
        self.curX = newX
        self.curY = newY
        self.update()
        return True
    def drawSquare(self, painter, x, y, shape):
# '''draws a square of a shape'''
        colorTable = [0x000000, 0xCC6666, 0x66CC66, 0x6666CC,
                            0xCCCC66, 0xCC66CC, 0x66CCCC, 0xDAAA00]
        color = QColor(colorTable[shape])
        painter.fillRect(x + 1, y + 1, self.squareWidth() - 2, self.squareHeight() - 2, color)
        painter.setPen(color.lighter())
        painter.drawLine(x, y + self.squareHeight() - 1, x, y)
        painter.drawLine(x, y, x + self.squareWidth() - 1, y)
        painter.setPen(color.darker())
        painter.drawLine(x + 1, y + self.squareHeight() - 1,
            x + self.squareWidth() - 1, y + self.squareHeight() -1)

        painter.drawLine(x + self.squareWidth() - 1,
            y + self.squareHeight() - 1, x + self.squareWidth() - 1, y +1)
class Tetrominoe(object):
    NoShape = 0
    ZShape = 1
    SShape = 2
    LineShape = 3
    TShape = 4
    SquareShape = 5
    LShape = 6
    MirroredLShape = 7
class Shape(object):
    coordsTable = (
 ((0, 0), (0, 0), (0, 0), (0, 0)),
 ((0, -1), (0, 0), (-1, 0), (-1, 1)),
 ((0, -1), (0, 0), (1, 0), (1, 1)),
 ((0, -1), (0, 0), (0, 1), (0, 2)),
 ((-1, 0), (0, 0), (1, 0), (0, 1)),
 ((0, 0), (1, 0), (0, 1), (1, 1)),
 ((-1, -1), (0, -1), (0, 0), (0, 1)),
 ((1, -1), (0, -1), (0, 0), (0, 1))
 )
    def __init__(self):
        self.coords = [[0,0] for i in range(4)]
        self.pieceShape = Tetrominoe.NoShape
        self.setShape(Tetrominoe.NoShape)
    def shape(self):
# '''returns shape'''
        return self.pieceShape
    def setShape(self, shape):
# '''sets a shape'''
        table = Shape.coordsTable[shape]
        for i in range(4):
            for j in range(2):
                self.coords[i][j] = table[i][j]
                self.pieceShape = shape
    def setRandomShape(self):
# '''chooses a random shape'''
        self.setShape(random.randint(1, 7))
    def x(self, index):
# '''returns x coordinate'''
        return self.coords[index][0]
    def y(self, index):
# '''returns y coordinate'''
        return self.coords[index][1]
    def setX(self, index, x):
# '''sets x coordinate'''
        self.coords[index][0] = x
    def setY(self, index, y):
# '''sets y coordinate'''
        self.coords[index][1] = y
    def minX(self):
# '''returns min x value'''
        m = self.coords[0][0]
        for i in range(4):
            m = min(m, self.coords[i][0])
        return m
    def maxX(self):
# '''returns max x value'''
        m = self.coords[0][0]
        for i in range(4):
            m = max(m, self.coords[i][0])
        return m
    def minY(self):
# '''returns min y value'''
        m = self.coords[0][1]
        for i in range(4):
            m = min(m, self.coords[i][1])
        return m
    def maxY(self):
# '''returns max y value'''
        m = self.coords[0][1]
        for i in range(4):
            m = max(m, self.coords[i][1])
        return m
    def rotateLeft(self):
# '''rotates shape to the left'''
        if self.pieceShape == Tetrominoe.SquareShape:
            return self
        result = Shape()
        result.pieceShape = self.pieceShape
        for i in range(4):
            result.setX(i, self.y(i))
            result.setY(i, -self.x(i))
        return result
    def rotateRight(self):
# '''rotates shape to the right'''
        if self.pieceShape == Tetrominoe.SquareShape:
            return self
        result = Shape()
        result.pieceShape = self.pieceShape
        for i in range(4):
            result.setX(i, -self.y(i))
            result.setY(i, self.x(i))

        return result
if __name__ == '__main__':
    app = QApplication([])
    tetris = Tetris()
    sys.exit(app.exec_())

游戏很简单,所以也就很好理解。程序加载之后游戏也就直接开始了,可以用P键暂停游戏,空格键让方块直接落到最下面。游戏的速度是固定的,并没有实现加速的功能。分数就是游戏中消除的行数。

        self.tboard = Board(self)

        self.setCentralWidget(self.tboard)

创建了⼀个Board类的实例,并设置为应用的中心组件。

        self.statusbar = self.statusBar()         self.tboard.msg2Statusbar[str].connect(self.statusbar.showMessage

创建⼀个 statusbar 来显示三种信息:消除的行数,游戏暂停状态或者游戏结束状态。 msg2Statusbar 是⼀个自定义的信号,用在(和)Board类(交 互), showMessage() 方法是⼀个内建的,用来在statusbar上显示信息的方法。

        self.tboard.start()

初始化游戏:

class Board(QFrame):

        msg2Statusbar = pyqtSignal(str)

        ...

创建了⼀个自定义信号 msg2Statusbar ,当我们想往 statusbar 里显示信息的时 候,发出这个信号就行了。

        BoardWidth = 10

        BoardHeight = 22

        Speed = 300

这些是 Board 类的变量。 BoardWidth 和 BoardHeight 分别是board的宽度和高度。 Speed 是游戏的速度,每300ms出现⼀个新的方块。

...

self.curX = 0

self.curY = 0

self.numLinesRemoved = 0

self.board = []

...

在 initBoard()里初始化了⼀些重要的变量。 self.board 定义了方块的形状和位 置,取值范围是0-7。

def shapeAt(self, x, y):

        return self.board[(y * Board.BoardWidth) + x]

shapeAt() 决定了board里方块的的种类。

        def squareWidth(self):

                return self.contentsRect().width() // Board.BoardWidth

board的大小可以动态的改变。所以方格的大小也应该随之变化。 squareWidth() 计算并返回每个块应该占用多少像素--也即 Board.BoardWidth 。

def pause(self):
# '''pauses game'''
        if not self.isStarted:
            return
        self.isPaused = not self.isPaused
        if self.isPaused:
            self.timer.stop()
            self.msg2Statusbar.emit("paused")
        else:
            self.timer.start(Board.Speed, self)
            self.msg2Statusbar.emit(str(self.numLinesRemoved))
        self.update()

pause() 方法⽤来暂停游戏,停止计时并在 statusbar 上显示⼀条信息。

'''

    def paintEvent(self, event):
# '''paints all shapes of the game'''
        painter = QPainter(self)
        rect = self.contentsRect()

'''

渲染是在paintEvent()f 法里发生的 QPainter 负责PyQt5里所有低级绘画操作。 

for i in range(Board.BoardHeight):
    for j in range(Board.BoardWidth):
        shape = self.shapeAt(j, Board.BoardHeight - i - 1)
        if shape != Tetrominoe.NoShape:
            self.drawSquare(painter,
            rect.left() + j * self.squareWidth(),
            boardTop + i * self.squareHeight(), shape)

渲染游戏分为两步。第⼀步是先画出所有已经落在最下面的的图,这些保存 在 self.board ⾥。可以使用 shapeAt() 查看这个这个变量。 

if self.curPiece.shape() != Tetrominoe.NoShape:
    for i in range(4):
        x = self.curX + self.curPiece.x(i)
        y = self.curY - self.curPiece.y(i)
        self.drawSquare(painter, rect.left() + x * self.squareWidth(),
        boardTop + (Board.BoardHeight - y - 1) * self.squareHeight(),
        self.curPiece.shape())

第⼆步是画出更在下落的方块。 

elif key == Qt.Key_Right:

        self.tryMove(self.curPiece, self.curX + 1, self.curY)

在 keyPressEvent() 方法获得用户按下的按键。如果按下的是右方键,就尝试把方块向右移动,说尝试是因为有可能到边界不能移动了。

elif key == Qt.Key_Up:
上⽅向键是把⽅块向左旋转⼀下

elif key == Qt.Key_Space:

        self.dropDown()

空格键会直接把方块放到底部

elif key == Qt.Key_D:

        self.oneLineDown()

D键是加速⼀次下落速度。

def tryMove(self, newPiece, newX, newY):
# '''tries to move a shape'''
        for i in range(4):
            x = newX + newPiece.x(i)
            y = newY - newPiece.y(i)
            if x < 0 or x >= Board.BoardWidth or y < 0 or y >= Board.BoardHeight:
                return False
            if self.shapeAt(x, y) != Tetrominoe.NoShape:
                return False
        self.curPiece = newPiece
        self.curX = newX
        self.curY = newY
        self.update()

tryMove() 是尝试移动方块的方法。如果方块已经到达board的边缘或者遇到了其他方块,就返回False。否则就把方块下落到想要位置。

 def timerEvent(self, event):
# '''handles timer event'''
        if event.timerId() == self.timer.timerId():
            if self.isWaitingAfterLine:
                self.isWaitingAfterLine = False
                self.newPiece()
            else:
                self.oneLineDown()
        else:
            super(Board, self).timerEvent(event)

在计时器事件里,要么是等⼀个方块下落完之后创建⼀个新的方块,要么是让⼀个方块直接落到底(move a falling piece one line down)。

def clearBoard(self):

        for i in range(Board.BoardHeight * Board.BoardWidth):

                self.board.append(Tetrominoe.NoShape)

clearBoard( )方法通过 Tetrominoe.NoShape 清空 broad 。

'''

 def removeFullLines(self):
# '''removes all full lines from the board'''
        numFullLines = 0
        rowsToRemove = []
        for i in range(Board.BoardHeight):
            n = 0
            for j in range(Board.BoardWidth):
                if not self.shapeAt(j, i) == Tetrominoe.NoShape:
                    n = n + 1
                    if n == 10:
                        rowsToRemove.append(i)
                        rowsToRemove.reverse()
        for m in rowsToRemove:
            for k in range(m, Board.BoardHeight):
                for l in range(Board.BoardWidth):
                    self.setShapeAt(l, k, self.shapeAt(l, k + 1))
        numFullLines = numFullLines + len(rowsToRemove)

'''

如果f 块碰到了底部,就调用 removeFullLines() 方法,找到所有能消除的行消除它们。消除的具体动作就是把符合条件的行消除掉之后,再把它上面的行下降⼀行。注意移除满行的动作是倒着来的,因为我们是按照重力来表现游戏的,如果不这样就有可能出现有些方块浮在空中的现象。

def newPiece(self):
# '''creates a new shape'''
        self.curPiece = Shape()
        self.curPiece.setRandomShape()
        self.curX = Board.BoardWidth // 2 + 1
        self.curY = Board.BoardHeight - 1 + self.curPiece.minY()
        if not self.tryMove(self.curPiece, self.curX, self.curY):
            self.curPiece.setShape(Tetrominoe.NoShape)
            self.timer.stop()
            self.isStarted = False
            self.msg2Statusbar.emit("Game over")

newPiece() 方法是用来创建形状随机的方块。如果随机的方块不能正确的出现在预设的位置,游戏结束。

class Tetrominoe(object):
    NoShape = 0
    ZShape = 1
    SShape = 2
    LineShape = 3
    TShape = 4
    SquareShape = 5
    LShape = 6
    MirroredLShape = 7

Tetrominoe 类保存了所有方块的形状。我们还定义了⼀个 NoShape 的空形状。 Shape类保存类方块内部的信息。

'''

class Shape(object):
    coordsTable = (
 ((0, 0), (0, 0), (0, 0), (0, 0)),
 ((0, -1), (0, 0), (-1, 0), (-1, 1)),
 ((0, -1), (0, 0), (1, 0), (1, 1)),
 ((0, -1), (0, 0), (0, 1), (0, 2)),
 ((-1, 0), (0, 0), (1, 0), (0, 1)),
 ((0, 0), (1, 0), (0, 1), (1, 1)),
 ((-1, -1), (0, -1), (0, 0), (0, 1)),
 ((1, -1), (0, -1), (0, 0), (0, 1))
 )

'''

coordsTable元组保存了所有的f 块形状的组成。是⼀个构成f 块的坐标模版。

        self.coords = [[0,0] for i in range(4)]

上面创建了⼀个新的空坐标数组,这个数组将来用保存方块的坐标。 坐标系示意图:

 

上面的图片可以帮助我们更好的理解坐标值的意义。比如元组 (0, -1), (0, 0), (-1, 0), (-1, -1) 代表了⼀个Z形状的方块。这个图表就描绘了这个形状。

def rotateLeft(self):
# '''rotates shape to the left'''
        if self.pieceShape == Tetrominoe.SquareShape:
            return self
        result = Shape()
        result.pieceShape = self.pieceShape
        for i in range(4):
            result.setX(i, self.y(i))
            result.setY(i, -self.x(i))
        return result
    def rotateRight(self):
# '''rotates shape to the right'''
        if self.pieceShape == Tetrominoe.SquareShape:
            return self
        result = Shape()
        result.pieceShape = self.pieceShape
        for i in range(4):
            result.setX(i, -self.y(i))
            result.setY(i, self.x(i))

        return result

rotateLeft()方法向右旋转⼀个方块。正方形的方块就没必要旋转,就直接返回 了。其他的是返回⼀个新的,能表示这个形状旋转了的坐标。

程序展示:

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
pyqt4精彩实例讲解,适合pyqt4初级学习者,经供参考第6行创建了一个 QPush Button对象,并设置它的显示文木为“ Hello Kitty!",由于此处并 没有指定按钮的父窗体,因此以自己作为主窗凵 第7行调用show()方法,显示此按钮。控件被创建时,默认是不显示的,必须调用show() 区数来显示它。 第8行的 connect方法是αt最重要的特征,即信号与槽的机制。当按钮被按下则触发 clicked 信号,与之相连的 APplication对象的槽quit(响应按钮单击信号,执行退出应用程序的操 作。关于信号与槽机制在本实例最后将进行详细的分析。 最后调用 APplication的exec()方法,程序进入消息循环,等待可能输入进行响应。Qt 完成事件处理及显示的工作,并在应用程序退出时返叫exec_Q)的值 最后执行程序即可出现上图所示的对话框,一个简单的 Hello Kitty!例子完成。 信号与槽机制作为αt最重要的特性,提供了任意两个Qt对象之间的通信机制。其中,信 号会在某个特定情况或动作下被触发,槽是用于接收并处理信号的函数。例如,要将一个窗 口中的变化情况通知给另一个窗口,则一个窗口发送信号,另一个窗口的槽接收此信号并进 行相应的操作,即可实现两个窗∏之间的通信。这比传统的图形化程序采用回调函数的方式 实现对象间通信要简单灵活得多。每个Qt对象都包含预定的信号和槽,当一某一特定事件 发生时,一个信号被发射,与信号相关联的槽则会响应信号完成相应的处理。 信号与槽机制常用的连接方式为 connect(Object1, SIGNAL(signal), Object2, SLOT (slot) signal|为对象 Object1的信号,sot为对象 Object2的槽,Qt的窗口部件都包含若十个预定 义的信号和若干个预定乂的槽。当一个类被继承时,该类的信号和槽也同时被继承。开始人 也可以根据需要定义自己的信号和槽。 信号与槽机制可以有多种连接方式,下图描述了信号与槽的多种可能连接方式。 Object 1 Object 2 signal 1 si巴nall signal 2 SeFa 2 slot 1 slot 1 lot 2 Object 3 signal 2 slot 1 slot 2 个信号可以与另一个信号相连 connect(object1, SIGNAL(signal1),Object2, SIGNAL(signal 1)) 即表示 Object11的信号1发射可以触发 Object2的信号1发射 2.表示一个信号可以与多个槽相连 connect(Object1, SIGNAL(signal2), Object2, SLOT(slot2)) connect(object1, SIGNAL(signal2), Object3. SLOT(slot1) 3表示同一个槽可以响应多个信号 connect(object1, SIGNAL(signal2), Object2, SLOT(slot2)) connect(object3, SIGNAL(signal2),object2, SLOT (slot2)) 注:本文基本上是经过改编的《 Linux窗口程序设计-Qt4精彩实例分析》一书的PyQt4for windows版本 可以这么写: b clicked. connect( app. quit) 这样就少了一些 hardcode的字符串了,更加 pythonic 实例2标准对话框的使用 分类:-PyQ42010-12-0310:342105人阅读评论(2)收藏举报 和人多数操作系统一样, Windows及Linuⅹ都提供了一系列的标准对话框,如文件选择, 字体选择,颜色选择等,这些标准对话框为应用程序提供了一致的观感。Qt对这些标准对 话框都定义了相关的类,这些类让使用者能够很方便地使用标准对话框进行文件,颜色以及 字体的选择。标准对话框在软件设计过程中是经常需要使用的。 αt提供的标准对话框除了本实例提到的,还有 QErrorMessage, QInputDialog, QMessage Box, QPrintDialog, QProcess Dialog等,这些标准对话框的使用在本书的后续 部分将会陆续介绍。 本实例主要演示上面几种标准对话框的使用,如下图所示 St andard dialog 文件对话框 颜色对话框 字体对话框 Hello wor1l! 在上图中,单击“文件对话框”按钮,会弹出文件选择对话框,选中的文件名将显示在右连, 单击“颜色对话栏”按钮,会弹岀颜色选择对话框,选中的颜色将显小在右边,单击“字体对话 框”按钮,会弹出字体选择对话框,选中的字体将更新右边显示的字符串。 实现代码如下: [python] view plaincopyprint? 1.*-* -coding: utf-8 2. from PyQt4.QtGui import 3. from PyQt4. QtCore import 4. import sys 6.QText Codec. setCodecForTr(QText Codec codec ForName(utf8")) 8 class Standard Dialog(QDialog) 9 10. def init (self, parent=None) 1. super(StandardDialog, self). init (parent) 12 13. self. setWindow Title( Standard Dialog") 14 15. file Push Button= QPush Button(sefr("文件对话恒") 16 colorPushButton= QPush Button( self.tr-色对话框") font PushButton= QPushButton( self.tr("字体对话框") 19 self. fileLine Edit=QLine Edito self. colorFrame=QFrame( 21 self. colorFrame setFrame Shape(QFrame. Box) 22 self. colorFrame.setAutoFillBackground(True 23. self. fontAine Edit=QLine Edit( Hello World! " 24 25 layout=Q GridLayouto 26 layout. addWidget(filePushButton, 0, 0) layout. addWidget(self. fileLineEdit, 0, 1) 28 layout. addWidget(color PushButton, 1, 0) 29 layout. addWidget(self. colorFrame, 1,1) 30. layout. addWidget(fontPush Button, 2,0) layout. addWidget(self. fontLineEdit, 2, 1) 32 33. self. setLayout(layout) 34 35. self connect(filePushButton, SIGNALCclickedo"), self. open File) 36 self connect(colorPushButton, SIGNAL(clicked(), self. open Color) 37. self connect(fontPush Button, SIGNAL(clicked("), self. openFont) 38 39. def open File(self) 40. s=QFile Dialog getOpen FileName(self, Open file dialog","/","Python files( py)") 42. self. fileLineEdit. setText(str(s)) 43 44. def open Color(selt 45 46. c=Q Color Dialog. get Color(Qt. blue 47. if c is Valid(: 48. self. colorFrame. setPalette(QPalette(c)) 49 50. def open Font(self) 51 52 f, ok=QFontDialog getFont 53 if ok. 54 self. fontLineEdit setFont(f) 55 56. app=QApplication(sys. argv) 57 form= StandardDialogo 58 form. showO 69. app. exec O 第6行设定tr方法使用u邯8编码来解析文字。 第13行设置程序的标题。 第15到17行创建各个按钮控件。 第19行创建一个 LIne edit类实例 filelineedit,用米显示选择的文件名。 第20行创建一个 FRame类实例 doorframe,当用户选择不同的颜色时, color frame会 根据用户选择的颜色更新其背景 第23行创建一个 QLine Edit类实例 fontaine edit.,当用户选择不同的字体时, fontaine edit 会根据用户选择的字体更新其内容。 第25到33行将各个控件进行布局 第35到37行将各个按钮的 clicked信号相应的槽进行连接 sottIle(方法是文件对话框按钮的 clicked信号的槽,其中 getopenFileName()是 QFileDialog类的一个静态方法,返回用户选择的文件名,如果用户选择取消,则返回一个 空串。函数形式如下: QString getopen FileName(QWidget parent= None, QString caption= QString(, Q String directory = QString(, QString filter= QString(, Options options =0) QString getOpen FileName(QWidget parent None, QString caption QString(, QString directory= QString(), QString filter=QStringo, QString selectedFilter= None, Options options = 0) 调用 getOpen FileName(函数将创建一个模态的文件对话框,如下图所示。 directory参数 指定了默认的目录,如果 directory参数带有文件名,则该文件将是默认选中的文件,fter 参数对文件类型走行过滤,只有与过滤器匹配的文件类型才显示, filter可以同时指定多种 过滤方式供用户选择,多种过滤器之间用";"隔开,用广选择的过滤器通过参数 selectedFilter 返回 Open file dialog ②区 查找范围):「本地避盘(:) OMy Book My Doc 我最近的文档yFim @My Hidden aMy Music 桌面 laMy Othe oMy Pic 品 7 Softwa 我的文档 My Study aMy Work 我的电脑 网上邻居 文件名① [打开@)1 文件类型): Python files(,py) 取消 QFileDialog类还提供了类似的其他静态函数,如卜表,通过这些函数,用户可以方使地定 制自己的文件对话框。 静态函数 说明 ge lOpenFilename 获得用户选择的文件名 getsaveFileName 获得用户保存的文件名 getExistingdirectory 获得用户选择的已存在的目录名 getOpenl'ileNames 获得用户选择的文件名列表 slotcolor()函数是颜色对话框按钮 clicked信号的槽。其中 decolor()是 QColorDialog的 个静态函数,返回用户选择的颜色值,函数形式如下: QColor Q Dialog getColor(Q Color initial=Qt. white, QWidget parent= None) QColor Q Color Dialog. getColor(QColor, QWidget, QString, Color DialogOptions options 0 调用 getcolor(函数将创建一个模态的颜色对话框,如下图所示。 initial参数指定了默认的 颜色,默认为白色,通过 is valid(可以判断用户选择的颜色是否有效,若用户选择取消, isValid将返回 false Select Font 冈 Font Font style eIze Normal 仿宋GB2312 Normal 华文中宋 工 telic 华文仿 Bold 8 华文宋体 Bold italic 9 华文彩云 10 华文新魏 11 华文楷体 12 华文琥珀 华文细黑 1日 文 18 华文隶书 2 2在-1Rnn 4 E£ Eects Sample □ Strikeout 口 nderline AaBblyLr Writing System ty OK[ Cancel slotFont()函数是字体对话框按钮 clicked信号的槽。其中 getFont(是 QFontDialog的个 静态函数,返回用户选择的字体,函数形式如下: (QFont, bool) getFont(QFont, QWidget, QString, FontDialogOptions) (QFont, bool) getFont(QFont, QWidget, QString) (QFont, bool) getFont(QFont, QWidget parent= None) (QFont, bool) getFont(QWidget parent = None 调用 getFont()函数将创建个模态的字体对话框,如下图所示。用户选择OK,函数返回(用 户选择的字体True)否则返回(默认字体, False) ■ Select font Font Font styl Size 宋体 Normal 仿宋GB2312 orm 文中宋 工taic 华文仿 Bold 8 华文宋体 Bold italic 9 10 华文新魏 11 华文楷体 12 华文琥 华文细 1日 18 华文隶 2 22 宋体-1Rn3n Effects ample □ Strikeout □nler1ine AaBbyyli Writing System Any 匚[caca 实例3各类位置信 分类:-PyQt42010-12-0417:071226人阅读评论()收藏举报 Qt提供了很多关于获取窗体位置及显示区域大小的函数,本实例利用一个简单的对话框显 示窗体的各种位置信息,包括窗体的所在点位置,长,宽信息等。木实例的目的是分析各个 有关位置信息的函数之间的区别,如x(,yO,posO),rect), size(), geometry)等,以及在不同的 情况下应使用哪个函数来获取位置信息。实现的效果如下图

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值