[英]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.