为啥当我单击提交按钮时,此 PyQt5 发票 GUI 应用程序的“Python 停止工作”? [复制]
Posted
技术标签:
【中文标题】为啥当我单击提交按钮时,此 PyQt5 发票 GUI 应用程序的“Python 停止工作”? [复制]【英文标题】:Why does the "Python stop working" for this PyQt5 invoice GUI application when i clicked submit button? [duplicate]为什么当我单击提交按钮时,此 PyQt5 发票 GUI 应用程序的“Python 停止工作”? [复制] 【发布时间】:2020-09-17 13:38:40 【问题描述】:如果您能帮我解决这个问题,我会很高兴。我正在练习 PyQt5 Gui 应用程序的编码。这是生成发票的简单 GUI 应用程序。但是每当我单击提交(创建发票)按钮时,它就会停止。我无法弄清楚问题所在。请帮我解决问题。
更新:任何人都可以无错误地修复代码吗? 错误信息是:
>>> Exception "unhandled AttributeError"
'InvoiceForm' object has no attribute 'setCentralWidget'
代码如下:-
import sys
from PyQt5.QtCore import pyqtSignal, QSize, QSizeF, QDate
from PyQt5.QtGui import QTextDocument, QTextCursor
from PyQt5.QtWidgets import QWidget, QFormLayout, QLineEdit, QPlainTextEdit, QSpinBox, QDateEdit, QTableWidget, \
QHeaderView, QPushButton, QHBoxLayout, QTextEdit, QApplication, QMainWindow
class InvoiceForm(QWidget):
submitted = pyqtSignal(dict)
def __init__(self):
super().__init__()
self.setLayout(QFormLayout())
self.inputs = dict()
self.inputs['Customer Name'] = QLineEdit()
self.inputs['Customer Address'] = QPlainTextEdit()
self.inputs['Invoice Date'] = QDateEdit(date=QDate.currentDate(), calendarPopup=True)
self.inputs['Days until Due'] = QSpinBox()
for label, widget in self.inputs.items():
self.layout().addRow(label, widget)
self.line_items = QTableWidget(rowCount=10, columnCount=3)
self.line_items.setHorizontalHeaderLabels(['Job', 'Rate', 'Hours'])
self.line_items.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.layout().addRow(self.line_items)
for row in range(self.line_items.rowCount()):
for col in range(self.line_items.columnCount()):
if col > 0:
w = QSpinBox()
self.line_items.setCellWidget(row, col, w)
submit = QPushButton('Create Invoice', clicked=self.on_submit)
self.layout().addRow(submit)
def on_submit(self):
data = 'c_name': self.inputs['Customer Name'].text(),
'c_addr': self.inputs['Customer Address'].toPlainText(),
'i_date': self.inputs['Invoice Date'].date().toString(),
'i_due': self.inputs['Invoice Date'].date().addDays(self.inputs['Days until Due'].value()).toString(),
'i_terms': ' days'.format(self.inputs['Days until Due'].value()),
'line_items': list()
for row in range(self.line_items.rowCount()):
if not self.line_items.item(row, 0):
continue
job = self.line_items.item(row, 0).text()
rate = self.line_items.cellWidget(row, 1).value()
hours = self.line_items.cellWidget(row, 2).value()
total = rate * hours
row_data = [job, rate, hours, total]
if any(row_data):
data['line_items'].append(row_data)
data['total_due'] = sum(x[3] for x in data['line_items'])
self.submitted.emit(data)
main = QWidget()
main.setLayout(QHBoxLayout())
self.setCentralWidget(main)
form = InvoiceForm()
main.layout().addWidget(form)
self.preview = InvoiceView()
main.layout().addWidget(self.preview)
form.submitted.connect(self.preview.build_invoice)
class InvoiceView(QTextEdit):
dpi = 72
doc_width = 8.5 * dpi
doc_height = 11 * dpi
def __init__(self):
super().__init__(readOnly=True)
self.setFixedSize(QSize(self.doc_width, self.doc_height))
def build_invoice(self, data):
document = QTextDocument()
self.setDocument(document)
document.setPageSize(QSizeF(self.doc_width, self.doc_height))
cursor = QTextCursor(document)
cursor.insertText("Invoice, woohoo!")
def main():
app = QApplication(sys.argv)
window = InvoiceForm()
window.show()
app.exec_()
if __name__ == '__main__':
main()
【问题讨论】:
首先您可以使用print()
来查看执行了哪部分代码以及您在变量中的内容。也许它运行长时间运行的代码,这会阻止 GUI,它不能工作 - 所以它会冻结。
如果程序崩溃,那么您应该在控制台中运行以查看错误消息 - 并将此错误消息(不是评论)添加为文本(不是图像)
粘贴代码时请多加小心,在问题预览中始终确保格式正确,否则我们将无法区分错误缩进导致的错误。在formatting code 上阅读更多信息。
谢谢大家。我刚刚更新了这个问题。我是***的新手。您的评论对我学习很有帮助。
【参考方案1】:
如果你在 shell/prompt 中运行你的代码,你会清楚地看到错误:
>>> Exception "unhandled AttributeError"
'InvoiceForm' object has no attribute 'setCentralWidget'
问题是setCentralWidget
是QMainWindow 的一个函数,而您使用的是一个简单的QWidget。
虽然您可以尝试从 QMainWindow 继承 InvoiceForm
并相应地修改其布局和逻辑,但它不会很好地工作,因为您犯了一些概念性错误:最重要的是尝试添加一个 InvoiceForm
实例到本身,但您也发出了submitted
信号 将其连接到build_invoice
,因此它不会按预期工作。
最好的解决方案是创建一个 QMainWindow 子类并将这些小部件的实例添加到其中。
import sys
from PyQt5.QtCore import pyqtSignal, QSize, QSizeF, QDate
from PyQt5.QtGui import QTextDocument, QTextCursor
from PyQt5.QtWidgets import QWidget, QFormLayout, QLineEdit, QPlainTextEdit, QSpinBox, QDateEdit, QTableWidget, \
QHeaderView, QPushButton, QHBoxLayout, QTextEdit, QApplication, QMainWindow
class InvoiceForm(QWidget):
submitted = pyqtSignal(dict)
def __init__(self):
super().__init__()
self.setLayout(QFormLayout())
self.inputs = dict()
self.inputs['Customer Name'] = QLineEdit()
self.inputs['Customer Address'] = QPlainTextEdit()
self.inputs['Invoice Date'] = QDateEdit(date=QDate.currentDate(), calendarPopup=True)
self.inputs['Days until Due'] = QSpinBox()
for label, widget in self.inputs.items():
self.layout().addRow(label, widget)
self.line_items = QTableWidget(rowCount=10, columnCount=3)
self.line_items.setHorizontalHeaderLabels(['Job', 'Rate', 'Hours'])
self.line_items.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.layout().addRow(self.line_items)
for row in range(self.line_items.rowCount()):
for col in range(self.line_items.columnCount()):
if col > 0:
w = QSpinBox()
self.line_items.setCellWidget(row, col, w)
submit = QPushButton('Create Invoice', clicked=self.on_submit)
self.layout().addRow(submit)
def on_submit(self):
data = 'c_name': self.inputs['Customer Name'].text(),
'c_addr': self.inputs['Customer Address'].toPlainText(),
'i_date': self.inputs['Invoice Date'].date().toString(),
'i_due': self.inputs['Invoice Date'].date().addDays(self.inputs['Days until Due'].value()).toString(),
'i_terms': ' days'.format(self.inputs['Days until Due'].value()),
'line_items': list()
for row in range(self.line_items.rowCount()):
if not self.line_items.item(row, 0):
continue
job = self.line_items.item(row, 0).text()
rate = self.line_items.cellWidget(row, 1).value()
hours = self.line_items.cellWidget(row, 2).value()
total = rate * hours
row_data = [job, rate, hours, total]
if any(row_data):
data['line_items'].append(row_data)
data['total_due'] = sum(x[3] for x in data['line_items'])
self.submitted.emit(data)
# remove everything else in this function below this point
class InvoiceView(QTextEdit):
# ...
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
central = QWidget()
self.setCentralWidget(central)
layout = QHBoxLayout(central)
self.invoiceForm = InvoiceForm()
layout.addWidget(self.invoiceForm)
self.invoiceView = InvoiceView()
layout.addWidget(self.invoiceView)
# hide the widget right now...
self.invoiceView.setVisible(False)
self.invoiceForm.submitted.connect(self.showPreview)
def showPreview(self, data):
self.invoiceView.setVisible(True)
self.invoiceView.build_invoice(data)
def main():
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
if __name__ == '__main__':
main()
【讨论】:
您好,由于我是 GUI 新手,我无法理解您的意思。我已经从互联网上复制了代码用于学习目的。我没能跑。你能修复代码的特定部分吗?然后,我将研究错误。非常感谢。 @MinarMahmud 查看更新。以上是关于为啥当我单击提交按钮时,此 PyQt5 发票 GUI 应用程序的“Python 停止工作”? [复制]的主要内容,如果未能解决你的问题,请参考以下文章