gui在处理过程中没有响应?
Posted
技术标签:
【中文标题】gui在处理过程中没有响应?【英文标题】:gui not responding during process? 【发布时间】:2018-11-20 10:20:12 【问题描述】:我有 sql 查询。我的按钮与 sql 连接 - 这需要很长时间。在此期间,我的 GUI 没有响应 - 是否可以让它响应?
QtCore.QCoreApplication.processEvents()
不起作用。
QApp.py
># -- coding: utf-8 --
from PyQt5 import QtGui, QtWidgets, QtCore
import qdarkstyle
import pyodbc
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow,self).__init__(parent)
self.main_frame()
self.center() #center frame
self.layout_init() #widgets layout
def main_frame(self):
### actions on meenubar
exitAct = QtWidgets.QAction('&Exit', self)
exitAct.setShortcut('Ctrl+Q')
exitAct.setStatusTip('Exit application')
exitAct.triggered.connect(self.close)
self.statusBar()
moreinfo = QtWidgets.QAction('&Help',self)
moreinfo.setStatusTip('More information')
moreinfo.triggered.connect(self.information)
self.statusBar()
### menubar
menubar = self.menuBar()
fileMenu = menubar.addMenu('&File')
fileMenu.addAction(exitAct)
fileMenu = menubar.addMenu('&Help')
fileMenu.addAction(moreinfo)
### basic geometry and color
self.setWindowTitle('Villain')
self.setWindowIcon(QtGui.QIcon('dc1.png'))
self.setStyleSheet((qdarkstyle.load_stylesheet_pyqt5()))
def layout_init(self):
self.grid = QtWidgets.QGridLayout()
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
### widgets
self.tablewidget = QtWidgets.QTableWidget()
self.tablewidget.setColumnCount(4)
self.tablewidget.setHorizontalHeaderLabels(["FileNameTransformed", "OrderItemCode", "Imported", "Row"])
self.tablewidget.horizontalHeader().setDefaultAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
self.tablewidget.horizontalHeader().setStretchLastSection(True)
self.tablewidget.resizeColumnsToContents()
self.tablewidget.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
self.tablewidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
#self.tablewidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.textbox = QtWidgets.QLineEdit()
self.textbox.setPlaceholderText('IMEI')
self.textbox.setEnabled(True)
regexp = QtCore.QRegExp('^(0\d+|[1-9][0-9]+)$') #IMEI = only int
self.textbox.setValidator(QtGui.QRegExpValidator(regexp))
self.pb = QtWidgets.QPushButton(self.tr("Run process"))
self.pb.setDisabled(True)
self.textbox.textChanged.connect(self.disableButton)
self.pb.clicked.connect(self.on_clicked_pb)
self.clearbutton = QtWidgets.QPushButton(self.tr("Clear all"))
self.clearbutton.setDisabled(True)
self.clearbutton.clicked.connect(self.on_clicked_clear)
### make vidgets alive
self.centralWidget().setLayout(self.grid)
self.grid.addWidget(self.textbox)
self.grid.addWidget(self.tablewidget)
self.grid.addWidget(self.pb)
self.grid.addWidget(self.clearbutton)
### center main window
def center(self):
qr = self.frameGeometry()
cp = QtWidgets.QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
def information(self):
QtWidgets.QMessageBox.information(self,'Information','Version: 1.19.11.18\n'\
'This is the prototype of the application\n\n'\
'Please, contact karol.chojnowski@digitalcaregroup.com for comments and suggestions\n\n'\
'Digital Care - Data Processing Team')
def disableButton(self):
if len(self.textbox.text())> 0:
self.pb.setDisabled(False)
self.clearbutton.setDisabled(False)
else:
self.pb.setDisabled(True)
self.clearbutton.setDisabled(True)
### run process button
@QtCore.pyqtSlot()
def on_clicked_pb(self):
if len(self.textbox.text()) == 0:
pass
else:
self.sql_query()
### clear all
@QtCore.pyqtSlot()
def on_clicked_clear(self):
if len(self.textbox.text())> 0:
self.textbox.clear()
self.tablewidget.setRowCount(0)
self.tablewidget.setColumnWidth(3, 200)
def setCredentials(self, credentials):
self._credentials = credentials
def sql_query(self):
ser = "10.96.6.14"
base = "PROD_WAREX2"
username, pwd = self._credentials
QtCore.QCoreApplication.processEvents()
try:
self.connection = pyodbc.connect(driver='SQL Server', server=ser, database=base,
user=username, password=pwd)
cursor = self.connection.cursor()
self.res = cursor.execute(""" SELECT FI.FileNameTransformed,
FI.OrderItemCode,
FIR.Imported,
FR.Row
FROM [FileRows] AS FR
JOIN [FileImportRows] AS FIR ON FR.RowId = FIR.RowId
JOIN [FileImports] AS FI ON FIR.FileImportId = FI.Id
WHERE FR.Row LIKE ? """, ('%' + self.textbox.text() + '%'))
if not cursor.rowcount:
QtWidgets.QMessageBox.information(self, 'IMEI', "No items found")
cursor.close()
pass
else:
self.tablewidget.setRowCount(0)
for row, form in enumerate(self.res):
self.tablewidget.insertRow(row)
for column, item in enumerate(form):
newitem = QtWidgets.QTableWidgetItem(str(item))
self.tablewidget.setItem(row, column, newitem)
cursor.close()
self.table_performance()
self.tablewidget.sortItems(0, order=QtCore.Qt.DescendingOrder)
except:
QtWidgets.QMessageBox.warning(self, 'Error', "Something went wrong\n\n"\
"Contact karol.chojnowski@digitalcaregroup.com")
QtWidgets.QMessageBox.setStyleSheet((qdarkstyle.load_stylesheet_pyqt5()))
def table_performance(self):
self.tablewidget.resizeColumnsToContents()
self.tablewidget.setColumnWidth(3, 2500)
self.tablewidget.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
主.py:
恶棍.py
># -- coding: utf-8 --
import sys
from PyQt5 import QtWidgets,QtGui
from QLogin import LoginDialog
from QApp import MainWindow
import os
def resource_path(relative_path):
if hasattr(sys, '_MEIPASS'):
return os.path.join(sys._MEIPASS, relative_path)
return os.path.join(os.path.abspath("."), relative_path)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
login = LoginDialog()
login.setWindowIcon(QtGui.QIcon(resource_path('dc1.png')))
if login.exec_() != QtWidgets.QDialog.Accepted:
sys.exit(-1)
window = MainWindow()
window.setWindowIcon(QtGui.QIcon(resource_path('dc1.png')))
window.setGeometry(500, 150, 800, 500)
window.setCredentials(login.credentials()) # <----
window.show()
sys.exit(app.exec_())
【问题讨论】:
【参考方案1】:processEvents()
的使用在大多数情况下意味着糟糕的设计。如果你有一个繁重的任务,不要在主线程中执行它,在另一个线程中执行它并通过信号或QMetaObject::invokeMethod()
将必要的数据发送到主线程(最后一个选项将被使用,因为它不是需要如此多的联系)。
另一方面,您应该只添加一次样式表,如果有新的小部件,它们将作为样式表的基础。
# -- coding: utf-8 --
import threading
from PyQt5 import QtGui, QtWidgets, QtCore
import qdarkstyle
import pyodbc
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow,self).__init__(parent)
self.main_frame()
self.center() #center frame
self.layout_init() #widgets layout
def main_frame(self):
### actions on meenubar
exitAct = QtWidgets.QAction('&Exit', self, shortcut='Ctrl+Q', statusTip='application')
exitAct.triggered.connect(self.close)
moreinfo = QtWidgets.QAction('&Help',self, statusTip='More information')
moreinfo.triggered.connect(self.information)
### menubar
menubar = self.menuBar()
fileMenu = menubar.addMenu('&File')
fileMenu.addAction(exitAct)
fileMenu = menubar.addMenu('&Help')
fileMenu.addAction(moreinfo)
### basic geometry and color
self.setWindowTitle('Villain')
self.setWindowIcon(QtGui.QIcon('dc1.png'))
self.setStyleSheet((qdarkstyle.load_stylesheet_pyqt5()))
def layout_init(self):
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
### widgets
self.tablewidget = QtWidgets.QTableWidget()
self.tablewidget.setColumnCount(4)
self.tablewidget.setHorizontalHeaderLabels(["FileNameTransformed", "OrderItemCode", "Imported", "Row"])
self.tablewidget.horizontalHeader().setDefaultAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
self.tablewidget.horizontalHeader().setStretchLastSection(True)
self.tablewidget.resizeColumnsToContents()
self.tablewidget.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
self.tablewidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
#self.tablewidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.textbox = QtWidgets.QLineEdit()
self.textbox.setPlaceholderText('IMEI')
self.textbox.setEnabled(True)
regexp = QtCore.QRegExp('^(0\d+|[1-9][0-9]+)$') #IMEI = only int
self.textbox.setValidator(QtGui.QRegExpValidator(regexp))
self.pb = QtWidgets.QPushButton(self.tr("Run process"))
self.pb.setDisabled(True)
self.textbox.textChanged.connect(self.disableButton)
self.pb.clicked.connect(self.on_clicked_pb)
self.clearbutton = QtWidgets.QPushButton(self.tr("Clear all"))
self.clearbutton.setDisabled(True)
self.clearbutton.clicked.connect(self.on_clicked_clear)
### make vidgets alive
grid = QtWidgets.QGridLayout(central_widget)
grid.addWidget(self.textbox)
grid.addWidget(self.tablewidget)
grid.addWidget(self.pb)
grid.addWidget(self.clearbutton)
self.table_performance()
### center main window
def center(self):
qr = self.frameGeometry()
cp = QtWidgets.QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
def information(self):
QtWidgets.QMessageBox.information(self,'Information','Version: 1.19.11.18\n'\
'This is the prototype of the application\n\n'\
'Please, contact karol.chojnowski@digitalcaregroup.com for comments and suggestions\n\n'\
'Digital Care - Data Processing Team')
@QtCore.pyqtSlot()
def disableButton(self):
val = bool(self.textbox.text())
self.pb.setDisabled(not val)
self.clearbutton.setDisabled(not val)
### run process button
@QtCore.pyqtSlot()
def on_clicked_pb(self):
if self.textbox.text():
threading.Thread(target=self.sql_query, daemon=True).start()
### clear all
@QtCore.pyqtSlot()
def on_clicked_clear(self):
if self.textbox.text():
self.textbox.clear()
self.tablewidget.setRowCount(0)
self.tablewidget.setColumnWidth(3, 200)
def setCredentials(self, credentials):
self._credentials = credentials
def table_performance(self):
self.tablewidget.resizeColumnsToContents()
self.tablewidget.setColumnWidth(3, 2500)
self.tablewidget.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
@QtCore.pyqtSlot(str, str)
def show_warning(self, title, msg):
QtWidgets.QMessageBox.information(self, title, msg)
@QtCore.pyqtSlot()
def clear_items(self):
self.tablewidget.setRowCount(0)
@QtCore.pyqtSlot(int, int, str)
def add_item(self, row, column, val):
if row >= self.tablewidget.rowCount():
self.tablewidget.insertRow(self.tablewidget.rowCount())
newitem = QtWidgets.QTableWidgetItem(val)
self.tablewidget.setItem(row, column, newitem)
@QtCore.pyqtSlot()
def sort_items(self):
self.tablewidget.sortItems(0, order=QtCore.Qt.DescendingOrder)
def sql_query(self):
ser = "10.96.6.14"
base = "PROD_WAREX2"
username, pwd = self._credentials
try:
connection = pyodbc.connect(driver='SQL Server', server=ser, database=base,
user=username, password=pwd)
cursor = connection.cursor()
res = cursor.execute(""" SELECT FI.FileNameTransformed,
FI.OrderItemCode,
FIR.Imported,
FR.Row
FROM [FileRows] AS FR
JOIN [FileImportRows] AS FIR ON FR.RowId = FIR.RowId
JOIN [FileImports] AS FI ON FIR.FileImportId = FI.Id
WHERE FR.Row LIKE ? """, ('%' + self.textbox.text() + '%'))
if not cursor.rowcount:
QtCore.QMetaObject.invokeMethod(self, "show_warning",
QtCore.Qt.QueuedConnection,
QtCore.Q_ARG(str, 'IMEI'), QtCore.Q_ARG(str, "No items found"))
else:
QtCore.QMetaObject.invokeMethod(self, "clear_items", QtCore.Qt.QueuedConnection)
QtCore.QThread.msleep(10)
for row, form in enumerate(res):
for column, item in enumerate(form):
QtCore.QMetaObject.invokeMethod(self, "add_item",
QtCore.Qt.QueuedConnection,
QtCore.Q_ARG(int, row), QtCore.Q_ARG(int, column), QtCore.Q_ARG(str, str(item)))
QtCore.QThread.msleep(10)
QtCore.QMetaObject.invokeMethod(self, "sort_items", QtCore.Qt.QueuedConnection)
cursor.close()
except:
QtCore.QMetaObject.invokeMethod(self, "show_warning",
QtCore.Qt.QueuedConnection,
QtCore.Q_ARG(str, 'Error'), QtCore.Q_ARG(str, "Something went wrong\n\n"\
"Contact karol.chojnowski@digitalcaregroup.com"))
【讨论】:
嗯,好像不能完全正常工作。线程有效,但是当我调用sql_query
方法时它有效,然后它使用pycharm 信息Process finished with exit code -1073740791 (0xC0000409)
关闭程序似乎问题出在写入表?在我的主线程中,单击任何内容都会停止工作 sql_query?
我找到并更正了它:self.tablewidget.insertRow(self.tablewidget.rowCount())
但只有第一列,其余为空。错误:QBasicTimer::start: QBasicTimer can only be used with threads started with QThread QBasicTimer::start: QBasicTimer can only be used with threads started with QThread
哦,我太快了:QMetaObject::invokeMethod: No such method MainWindow::show_warning(QString,QString) Candidates are: show_warning(int) QMetaObject::invokeMethod: No such method MainWindow::show_warning(QString,QString) Candidates are: show_warning(int) Exception in thread Thread-1: Traceback (most recent call last): File "C:\Users\kchojnowski\Documents\Python_projects\GUI Natalia\QApp.py", line 187, in sql_query QtCore.Q_ARG(str, 'IMEI'), QtCore.Q_ARG(str, "No items found")) RuntimeError: QMetaObject.invokeMethod() call failed
@Karol357 你用过我最后的代码吗?我已经纠正了这些错误。以上是关于gui在处理过程中没有响应?的主要内容,如果未能解决你的问题,请参考以下文章
使用 QThread 两次单击按钮 2 后 Pyqt GUI 突然没有响应