I
I
Ilya Kaznacheev2015-04-21 14:37:48
Python
Ilya Kaznacheev, 2015-04-21 14:37:48

How to implement the interaction of the gui and the program, using the example of PyQt and python?

I never wrote gui only cli, only hardcore , but now I need to write. There are several private questions that are, as it were, part of one:
How is the interaction of the program with the graphical interface usually implemented?
How is it implemented?
How does the gui communicate with the program?
How should the program modules (logic, interface) be launched, who should control whom?
I read about MVC / MVP, etc., about the design of interfaces, but I didn’t understand anything about how to technically implement the interaction between them (how to write arrows from the diagram in the code).
I am a complete noob in this matter, so links with descriptions of everything and examples, good practices and good manners, as well as just advice are welcome :)
UPD: Need to write a gui for an existing console application

Answer the question

In order to leave comments, you need to log in

1 answer(s)
B
bobrovskyserg, 2015-04-21
@bobrovskyserg

Catch Tetris under Python3

import sys
from random import randint
from PyQt4 import QtCore, QtGui


class Tetris(QtGui.QMainWindow):
    def __init__(self):
        super(Tetris, self).__init__()
        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(180, 380)
        self.center()
        self.setWindowTitle('Tetris')
        self.show()

    def center(self):
        screen = QtGui.QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.move((screen.width() - size.width()) // 2, (screen.height() - size.height()) // 2)


class Board(QtGui.QFrame):
    msg2Statusbar = QtCore.pyqtSignal(str)
    BoardWidth, BoardHeight, Speed = 10, 22, 300
    EmptyLine = [0] * BoardWidth
    geometry = (None,
                (((0, 0), (-1, -1), (0, -1), (-1, -2)), ((-1, 0), (0, 0), (0, -1), (1, -1)),
                 ((0, 0), (-1, -1), (0, -1), (-1, -2)), ((-1, 0), (0, 0), (0, -1), (1, -1))),
                (((-1, 0), (-1, -1), (0, -1), (0, -2)), ((0, 0), (1, 0), (-1, -1), (0, -1)),
                 ((-1, 0), (-1, -1), (0, -1), (0, -2)), ((0, 0), (1, 0), (-1, -1), (0, -1))),
                (((0, 0), (0, -1), (0, -2), (0, -3)), ((-2, -1), (-1, -1), (0, -1), (1, -1)),
                 ((0, 0), (0, -1), (0, -2), (0, -3)), ((-2, -1), (-1, -1), (0, -1), (1, -1))),
                (((-1, 0), (0, 0), (1, 0), (0, -1)), ((1, 0), (0, -1), (1, -1), (1, -2)),
                 ((0, 0), (-1, -1), (0, -1), (1, -1)), ((-1, 0), (-1, -1), (0, -1), (-1, -2))),
                (((-1, 0), (0, 0), (-1, -1), (0, -1)), ((-1, 0), (0, 0), (-1, -1), (0, -1)),
                 ((-1, 0), (0, 0), (-1, -1), (0, -1)), ((-1, 0), (0, 0), (-1, -1), (0, -1))),
                (((0, 0), (1, 0), (0, -1), (0, -2)), ((-1, 0), (0, 0), (1, 0), (1, -1)),
                 ((0, 0), (0, -1), (-1, -2), (0, -2)), ((-1, 0), (-1, -1), (0, -1), (1, -1))),
                (((-1, 0), (0, 0), (0, -1), (0, -2)), ((1, 0), (-1, -1), (0, -1), (1, -1)),
                 ((0, 0), (0, -1), (0, -2), (1, -2)), ((-1, 0), (0, 0), (1, 0), (-1, -1))))

    def __init__(self, parent):
        super(Board, self).__init__(parent)
        self.timer = QtCore.QBasicTimer()
        self.isWaitingAfterLine = self.isStarted = self.isPaused = False
        self.numLinesRemoved = 0
        self.setFocusPolicy(QtCore.Qt.StrongFocus)

    def start(self):
        if self.isPaused:
            return
        self.isStarted = True
        self.isWaitingAfterLine = False
        self.numLinesRemoved = 0
        self.board = [Board.EmptyLine.copy() for _ in range(Board.BoardHeight)]
        self.msg2Statusbar.emit(str(self.numLinesRemoved))
        self.newPiece()
        self.timer.start(Board.Speed, self)

    def paintEvent(self, event):
        glass = [l.copy() for l in self.board]
        if self.shape:
            s, a, X, Y = self.shape
            for x, y in self.geometry[s][a]:
                glass[y + Y][x + X] = s
        h, w = self.contentsRect().height() // Board.BoardHeight, self.contentsRect().width() // Board.BoardWidth
        painter = QtGui.QPainter(self)
        for y, l in enumerate(glass):
            y = self.contentsRect().bottom() - (y + 1) * h
            for x, s in enumerate(l):
                if s:
                    x *= w
                    color = QtGui.QColor(
                        (None, 0xCC6666, 0x66CC66, 0x6666CC, 0xCCCC66, 0xCC66CC, 0x66CCCC, 0xDAAA00)[s])
                    painter.fillRect(x + 1, y + 1, w - 2, h - 2, color)
                    painter.setPen(color.light())
                    painter.drawLine(x, y + h - 1, x, y)
                    painter.drawLine(x, y, x + w - 1, y)
                    painter.setPen(color.dark())
                    painter.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1)
                    painter.drawLine(x + w - 1, y + h - 1, x + w - 1, y + 1)


    def keyPressEvent(self, event):
        if not (self.isStarted and self.shape):
            super(Board, self).keyPressEvent(event)
            return
        key = event.key()
        if key == QtCore.Qt.Key_P:
            self.isPaused ^= True
            if self.isPaused:
                self.timer.stop()
                self.msg2Statusbar.emit('paused')
            else:
                self.timer.start(Board.Speed, self)
                self.msg2Statusbar.emit(str(self.numLinesRemoved))
        elif key == QtCore.Qt.Key_Left:
            self.nextshape[2] -= 1
            self.tryMove()
        elif key == QtCore.Qt.Key_Right:
            self.nextshape[2] += 1
            self.tryMove()
        elif key == QtCore.Qt.Key_Down:
            self.nextshape[1] = (self.shape[1] + 1) % 4
            self.tryMove()
        elif key == QtCore.Qt.Key_Up:
            self.nextshape[1] = (self.shape[1] + 3) % 4
            self.tryMove()
        elif key == QtCore.Qt.Key_Space:
            self.dropDown()
        elif key == QtCore.Qt.Key_D:
            self.oneLineDown()
        else:
            super(Board, self).keyPressEvent(event)

    def timerEvent(self, 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 dropDown(self):
        while self.tryMove():
            self.nextshape[3] -= 1
        self.pieceDropped()

    def oneLineDown(self):
        self.nextshape[3] -= 1
        if not self.tryMove():
            self.pieceDropped()

    def pieceDropped(self):
        s, a, X, Y = self.shape
        for x, y in self.geometry[s][a]:
            self.board[y + Y][x + X] = s
        self.board = [l for l in self.board if not all(l)]
        numFullLines = Board.BoardHeight - len(self.board)
        if numFullLines:
            for i in range(numFullLines):
                self.board.append(Board.EmptyLine.copy())
            self.numLinesRemoved += numFullLines
            self.msg2Statusbar.emit(str(self.numLinesRemoved))
            self.isWaitingAfterLine = True
            self.shape = None
            self.update()
        if not self.isWaitingAfterLine:
            self.newPiece()

    def newPiece(self):
        self.nextshape = [randint(1, 7), 0, Board.BoardWidth // 2, Board.BoardHeight - 1]
        if not self.tryMove():
            self.shape = None
            self.timer.stop()
            self.isStarted = False
            self.msg2Statusbar.emit("Game over")

    def tryMove(self):
        s, a, X, Y = self.nextshape
        for x, y in self.geometry[s][a]:
            x += X
            y += Y
            if not (0 <= x < Board.BoardWidth and 0 <= y) or self.board[y][x]:
                self.nextshape = self.shape.copy()
                return False
        self.shape = self.nextshape.copy()
        self.update()
        return True


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

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question