简体   繁体   English

使用 QPainter 绘制刽子手

[英]using QPainter to draw a hangman

I am using python and am new to PyQt (and a bit new to python as well).我正在使用 python 并且是 PyQt 的新手(对 python 也有点陌生)。 I want to create a basic hangman game, and I have all of the controls figured out except I don't know how to draw the head, body, etc when a wrong letter is pressed.我想创建一个基本的刽子手游戏,我已经弄清楚了所有的控件,除了当按下错误的字母时我不知道如何绘制头部、身体等。 I tried using QPainter somehow but it doesn't work and upon research, some people say I have to use QPix map which I haven't heard of before so I am a bit confused.我尝试以某种方式使用 QPainter,但它不起作用,经过研究,有人说我必须使用我以前从未听说过的 QPix map,所以我有点困惑。 Here is the main bit of my code (I skipped me configuring the buttons for letters):这是我的代码的主要部分(我跳过了为字母配置按钮):

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QInputDialog, QWidget
from PyQt5.QtGui import QPainter, QBrush, QPen
from PyQt5.QtCore import Qt
import re

allowed = re.compile('[a-zA-Z ]')


class Ui_MainWindow(object):
    answer = [] #list of correct charcters they have inputted
    required = '' #string containing the solution
    indicies = {} #indicies mapping the index of each correct character in solution to the actual character
    wrong_count = 0

    def setupUi(self, MainWindow):
        ### sets up all the buttons for letters of the alphabet, lines, etc. I have this figured out.
        self.newgame = QtWidgets.QPushButton(self.centralwidget)
        self.newgame.setGeometry(QtCore.QRect(800, 290, 231, 51))
        font = QtGui.QFont()
        font.setPointSize(20)
        self.newgame.setFont(font)
        self.newgame.setObjectName("newgame")
        self.newgame.setText('New game')
        self.newgame.clicked.connect(self.restart)
        self.newgame.hide()

        self.start = QtWidgets.QPushButton(self.centralwidget)
        self.start.setGeometry(QtCore.QRect(480, 380, 231, 51))
        font = QtGui.QFont()
        font.setPointSize(20)
        self.start.setFont(font)
        self.start.setObjectName("start")
        self.start.setText("Begin")
        self.start.clicked.connect(self.get_name)

        self.answerbox = QtWidgets.QLabel(self.centralwidget)
        self.answerbox.setGeometry(QtCore.QRect(340, 480, 601, 91))
        font = QtGui.QFont()
        font.setPointSize(28)
        self.answerbox.setFont(font)
        self.answerbox.setText("")
        self.answerbox.setObjectName("answerbox")

        self.win = QtWidgets.QLabel(self.centralwidget)
        self.win.setGeometry(QtCore.QRect(340, 400, 601, 91))
        font = QtGui.QFont()
        font.setPointSize(28)
        self.win.setFont(font)
        self.win.setText("")
        self.win.setObjectName("win")

        self.wrongtext = QtWidgets.QLabel(self.centralwidget)
        self.wrongtext.setGeometry(QtCore.QRect(340, 500, 601, 91))
        font = QtGui.QFont()
        font.setPointSize(28)
        self.wrongtext.setFont(font)
        self.wrongtext.setText("Sorry, please type a valid string, without any special characters")
        self.wrongtext.adjustSize()
        self.wrongtext.setObjectName("wrongtext")
        self.wrongtext.hide()

        self.lost = QtWidgets.QLabel(self.centralwidget)
        self.lost.setGeometry(QtCore.QRect(340, 500, 601, 91))
        font = QtGui.QFont()
        font.setPointSize(28)
        self.lost.setFont(font)
        self.lost.setText("Sorry, you lost")
        self.lost.adjustSize()
        self.lost.setObjectName("lost")
        self.lost.hide()

    def get_name(self):
        text = App().text ##prompts user input for word
        if text == '':
            return
        elif allowed.match(text):
            Ui_MainWindow.required = text
            self.answerbox.setText('_ '*len(text))
            self.wrongtext.hide()
            self.check_space(text)
            self.answerbox.adjustSize()
            self.start.hide()
        else:
            self.wrongtext.show()


    def check_space(self, text):
        list1 = list(text)
        for ch in list1:
            if ch == ' ':
                self.revealer(ch)
                Ui_MainWindow.answer.append(ch)

    def clicked(self, ans): ### connected to letter buttons
        if ans.lower() in Ui_MainWindow.required:
            for _ in range(Ui_MainWindow.required.count(ans.lower())):
                Ui_MainWindow.answer.append(ans.lower())
            self.revealer(ans.lower())
            self.checker()
        else:
            Ui_MainWindow.wrong_count += 1
            self.paintEvent()

    def paintEvent(self): ##### this is what doesn't work but I want it to be something like this
        if Ui_MainWindow.wrong_count == 1: ### face
            painter = QPainter(self)
            painter.setPen(QPen(Qt.black, 10, Qt.SolidLine))
            painter.drawEllipse(250, 320, 20, 20)
            return
        if Ui_MainWindow.wrong_count == 2: ### body
            painter = QPainter(self)
            painter.begin(self)
            painter.setRenderHint(QPainter.Antialiasing)
            painter.setPen(QtCore.Qt.black)
            painter.setBrush(QtCore.Qt.black)
            painter.drawLine(250, 340, 250, 360)
            return
        if Ui_MainWindow.wrong_count == 3: ###legs
            painter = QPainter(self)
            painter.begin(self)
            painter.setRenderHint(QPainter.Antialiasing)
            painter.setPen(QtCore.Qt.black)
            painter.setBrush(QtCore.Qt.black)
            painter.drawLine(250, 360, 260, 370)
            return
        if Ui_MainWindow.wrong_count == 4:
            painter = QPainter(self)
            painter.begin(self)
            painter.setRenderHint(QPainter.Antialiasing)
            painter.setPen(QtCore.Qt.black)
            painter.setBrush(QtCore.Qt.black)
            painter.drawLine(250, 360, 240, 370)
            return
        if Ui_MainWindow.wrong_count == 5: ####arms
            painter = QPainter(self)
            painter.begin(self)
            painter.setRenderHint(QPainter.Antialiasing)
            painter.setPen(QtCore.Qt.black)
            painter.setBrush(QtCore.Qt.black)
            painter.drawLine(250, 350, 260, 340)
            return
        if Ui_MainWindow.wrong_count == 6:
            painter = QPainter(self)
            painter.begin(self)
            painter.setRenderHint(QPainter.Antialiasing)
            painter.setPen(QtCore.Qt.black)
            painter.setBrush(QtCore.Qt.black)
            painter.drawLine(250, 350, 240, 340)
            self.lost.show()
            self.newgame.show()


    def revealer(self, ans):
        index = Ui_MainWindow.required.index(ans) #find the index of a character from answer list in required list
        Ui_MainWindow.indicies[index*2] = ans #assigns index to the character, to be used for displayed
        try:
            while True: ##checks if clicked character appears multiple times in the answer string and appends all of them
                index = Ui_MainWindow.required.index(ans, index+1)
                Ui_MainWindow.indicies[index*2] = ans
        except:
            pass
        displayed = '_ '*len(Ui_MainWindow.required)
        temp_list = list(displayed)
        for index, ch in Ui_MainWindow.indicies.items():
            temp_list[index] = ch
        str2 = ''
        displayed = str2.join(temp_list)
        self.answerbox.setText(displayed)

    def checker(self):
        if sorted(Ui_MainWindow.answer) == sorted(list(Ui_MainWindow.required)):
            self.win.setText("You won!")
            self.newgame.show()
    def restart(self):
        Ui_MainWindow.answer = []
        Ui_MainWindow.required = ''
        Ui_MainWindow.indicies = {}
        Ui_MainWindow.wrong_count = 1
        self.win.setText("")
        self.answerbox.setText("")
        self.newgame.hide()
        self.lost.hide()
        self.start.show()

class App(QWidget):

    def __init__(self):
        super().__init__()
        self.title = 'PyQt5 input dialogs - pythonspot.com'
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(380, 280, 640, 480)
        self.get_name()

    def get_name(self):
        text, ok = QInputDialog.getText(self, 'Text Input Dialog', 'Enter your word:')
        self.text = text
        if text and ok:
            return str(text)

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

Sorry it's quite long.对不起,它很长。 Basically when I run it everything works the way I want it, except if I press the wrong letter, nothing happens.基本上,当我运行它时,一切都按我想要的方式运行,除非我按错字母,否则什么都不会发生。 It doesn't throw an error or anything.它不会抛出错误或任何东西。 I tried using just QPainter separately to see how it works, and I made it draw a circle, line, etc, but not one by one the way I want.我尝试单独使用 QPainter 来查看它是如何工作的,我让它画了一个圆圈、线条等,但不是按照我想要的方式一个一个地画。 Thanks for reading and I'd appreciate any answers.感谢您的阅读,我将不胜感激。 Sorry if my layout for my question was bad, I only started using this website yesterday, so am not familiar with how things work just yet.抱歉,如果我的问题布局不好,我昨天才开始使用这个网站,所以还不熟悉事情的运作方式。

paintEvent should be part of your QMainWindow instance, not of the object you use for setting up the ui. paintEvent应该是您的QMainWindow实例的一部分,而不是您用于设置 ui 的 object 的一部分。 In fact, most of the methods in Ui_MainWindow really belong to your MainWindow instance, so probably the easiest way to fix this is to just make Ui_MainWindow a subclass of QMainWindow , ie实际上, Ui_MainWindow中的大多数方法确实属于您的MainWindow实例,因此解决此问题的最简单方法可能是使Ui_MainWindow成为QMainWindow的子类,即

class Ui_MainWindow(QtWidgets.QMainWindow):
    # You could consider making these instance variables instead of class variables
    answer = [] #list of correct charcters they have inputted
    required = '' #string containing the solution
    indicies = {} #indicies mapping the index of each correct character in solution to the actual character
    wrong_count = 0

    def __init__(self):
        super().__init__()
        self.centralwidget = QWidget(self)
        self.setCentralWidget(self.centralwidget)

        self.setupUi(self)

    def paintEvent(self, event):    # <-- paintEvent receives the paint event as an input parameter
        ....

    # all other methods as before


if __name__ == "__main__":
    app = QtWidgets.QApplication([])
    MainWindow = Ui_MainWindow()
    MainWindow.show()
    MainWindow.resize(800,600)
    app.exec()

This will at least call the paintEvent , but there are still a number of issues with the implementation of paintEvent .这至少会调用paintEvent ,但是paintEvent的实现仍然存在许多问题。 For one, painEvent is called automatically every time the window needs redrawing.一方面,每次painEvent需要重绘时,都会自动调用 painEvent。 You shouldn't try to call this function yourself.您不应该尝试自己调用此 function。 If you think your widget needs redrawing you could use update instead.如果您认为您的小部件需要重绘,您可以使用update代替。

Also, paintEvent is meant just for painting a widget and nothing else.此外, paintEvent仅用于绘制小部件,仅用于绘制小部件。 This means that everything not-paint related like showing or hiding widgets should be moved elsewhere.这意味着所有与绘制无关的东西,比如显示或隐藏小部件都应该移到别处。 In your case, the lines在你的情况下,线条

self.lost.show()
self.newgame.show()

should be removed from paintEvent and moved to for example clicked instead, eg应该从paintEvent中删除并移动到例如clicked ,例如

def clicked(self, ans): ### connected to letter buttons
    if ans.lower() in Ui_MainWindow.required:
        for _ in range(Ui_MainWindow.required.count(ans.lower())):
            Ui_MainWindow.answer.append(ans.lower())
        self.revealer(ans.lower())
        self.checker()
    else:
        Ui_MainWindow.wrong_count += 1
        if self.wrong_count >= 6:
            self.lost.show()
            self.newgame.show()

Finally, since you only check for equality of wrong_count in paintEvent , at most one limb will be drawn at any time.最后,由于您只在paintEvent中检查wrong_count的相等性,因此在任何时候最多会绘制一个肢体。 This can be fixed by checking if wrong_count is larger than a certain value instead of equal to, eg这可以通过检查wrong_count是否大于某个值而不是等于来解决,例如

    def paintEvent(self, event): 
        painter = QPainter(self)
        painter.begin(self)
        if Ui_MainWindow.wrong_count >= 1: ### face
            painter.setPen(QPen(Qt.black, 10, Qt.SolidLine))
            painter.drawEllipse(250, 320, 20, 20)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.setPen(QtCore.Qt.black)
        painter.setBrush(QtCore.Qt.black)
        if Ui_MainWindow.wrong_count >= 2: ### body
            painter.drawLine(250, 340, 250, 360)
        if Ui_MainWindow.wrong_count >= 3: ###legs
            painter.drawLine(250, 360, 260, 370)
        if Ui_MainWindow.wrong_count >= 4:
            painter.drawLine(250, 360, 240, 370)
        if Ui_MainWindow.wrong_count >= 5: ####arms
            painter.drawLine(250, 350, 260, 340)
        if Ui_MainWindow.wrong_count >= 6:
            painter.drawLine(250, 350, 240, 340)
        painter.end()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM