簡體   English   中英

在PyQt中使用自定義小部件?

[英]Using custom widget in PyQt?

我按照此示例 (PyQT4)在PyQT5中創建了“自定義小部件”,並最終得到了以下代碼:

progress.py

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import (QApplication,QMainWindow)

class Ui_Form(QMainWindow):
    def __init__(self, name, parent=None):
        super(Ui_Form,self).__init__(parent)
        #Form.setObjectName("Form")
        self.resize(619, 202)
        self.formLayoutWidget = QtWidgets.QWidget()
        self.formLayoutWidget.setGeometry(QtCore.QRect(0, 0, 621, 201))
        self.formLayoutWidget.setObjectName("formLayoutWidget")
        self.formLayout = QtWidgets.QFormLayout(self.formLayoutWidget)
        self.formLayout.setContentsMargins(0, 0, 0, 0)
        self.formLayout.setObjectName("formLayout")
        self.progressBar = QtWidgets.QProgressBar(self.formLayoutWidget)
        self.progressBar.setProperty("value", 24)
        self.progressBar.setObjectName("progressBar")
        self.formLayout.setWidget(2, QtWidgets.QFormLayout.SpanningRole, self.progressBar)
        self.graphicsView = QtWidgets.QGraphicsView(self.formLayoutWidget)
        self.graphicsView.setObjectName("graphicsView")
        self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.graphicsView)
        self.label_Title = QtWidgets.QLabel(self.formLayoutWidget)
        font = QtGui.QFont()
        font.setFamily("Verdana")
        font.setPointSize(22)
        font.setBold(True)
        font.setWeight(75)
        self.label_Title.setFont(font)
        self.label_Title.setObjectName("label_Title")
        self.formLayout.setWidget(0, QtWidgets.QFormLayout.SpanningRole, self.label_Title)
        self.timer = QtCore.QBasicTimer()
        self.step = 0
        self.timer.start(100,self)

        self.retranslateUi()
        QtCore.QMetaObject.connectSlotsByName(self)


        def timerEvent(self, e):
            if self.step>= 100:
                self.timer.stop()
                return
            self.step = self.step + 1
            self.progressBar.setValue(self.step)   

    def retranslateUi(self):
        _translate = QtCore.QCoreApplication.translate
        self.setWindowTitle(_translate("Form", "Form"))
        self.label_Title.setText(_translate("Form", "TextLabel"))

new_ui.py

import sys
from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(742, 538)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton_Start = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_Start.setGeometry(QtCore.QRect(630, 20, 91, 31))
        self.pushButton_Start.setObjectName("pushButton_Start")
        self.lineEdit_URL = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit_URL.setGeometry(QtCore.QRect(20, 20, 601, 31))
        self.lineEdit_URL.setObjectName("lineEdit_URL")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(20, 460, 46, 13))
        self.label.setObjectName("label")
        self.label_status = QtWidgets.QLabel(self.centralwidget)
        self.label_status.setGeometry(QtCore.QRect(73, 460, 651, 16))
        self.label_status.setObjectName("label_status")
        self.listWidget = QtWidgets.QListWidget(self.centralwidget)
        self.listWidget.setGeometry(QtCore.QRect(20, 60, 701, 391))
        self.listWidget.setObjectName("listWidget")
        #MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 742, 21))
        self.menubar.setObjectName("menubar")
        #MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        #MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)


    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "My Downloader"))
        self.pushButton_Start.setText(_translate("MainWindow", "Start"))
        self.label.setText(_translate("MainWindow", "Status :"))
        self.label_status.setText(_translate("MainWindow", "Ideal..."))




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_())

main.py

import sys
import threading
import logging
from PyQt5 import QtCore, QtGui, QtWidgets
import json
import urllib.request
from new_ui import Ui_MainWindow
import progress
import random

class MyForm(QtWidgets.QDialog):
  def __init__(self, parent=None):
    super(MyForm, self).__init__(parent)
    self.ui = Ui_MainWindow()
    self.ui.setupUi(self)
    self.ui.pushButton_Start.clicked.connect(self.thread_start)

  def thread_start(self):
    p = threading.Thread(name='worker', target=self.start_download)
    #Do UI updates
    self.ui.label_status.setText('Fetching information...')
    #self.listWidget.addItem(prgstr)
    p.start()

  def start_download(self):

        ............
        code to fetch information from web
        ............

        #itm = self.ui.listWidget.addItem(json_data['entries'][0]['title'])
        self.ui.label_status.setText(json_data['entries'][0]['title'])
        item = QtWidgets.QListWidgetItem(self.ui.listWidget)
        item_widget = progress.Ui_Form("It works")
        item.setSizeHint(item_widget.sizeHint())
        self.ui.listWidget.addItem(item)
        self.ui.listWidget.setItemWidget(item,item_widget)


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    myapp = MyForm()
    myapp.show()
    sys.exit(app.exec_())

上面的代碼沒有任何錯誤,但是下面的代碼無法添加任何列表項(自定義窗口小部件), label_status正確地填充了檢索到的數據-我在這里缺少什么?

    self.ui.label_status.setText(json_data['entries'][0]['title'])
    item = QtWidgets.QListWidgetItem(self.ui.listWidget)
    item_widget = progress.Ui_Form("It works")
    item.setSizeHint(item_widget.sizeHint())
    self.ui.listWidget.addItem(item)
    self.ui.listWidget.setItemWidget(item,item_widget)

你應該永遠只能從主界面線程更新GUI元素。

工作線程應該在完成時發出信號,或者應該定期發出信號,以便可以處理掛起的GUI事件(即,通過調用qApp.processEvents() )。

如果輔助線程生成數據,請使用隊列,以便可以從主線程安全地訪問它。

更新

這是有關如何將QThread與輔助對象一起使用的基本示例(僅適用於python3)。 GUI線程和輔助線程之間的所有通信都是使用信號和插槽完成的(有關更多信息,請參見Qt文檔中的“ 跨線程的信號和插槽 ”)。

import urllib.request
from PyQt4 import QtCore, QtGui

class Worker(QtCore.QObject):
    finished = QtCore.pyqtSignal()
    error = QtCore.pyqtSignal(object)
    dataReady = QtCore.pyqtSignal(object)

    @QtCore.pyqtSlot(str)
    def process(self, url):
        try:
            response = urllib.request.urlopen(url, timeout=20)
            try:
                self.dataReady.emit(response.read())
            finally:
                response.close()
        except urllib.error.URLError as exception:
            self.error.emit(exception.reason)
        except BaseException as exception:
            self.error.emit(str(exception))
        finally:
            self.finished.emit()

class Window(QtGui.QWidget):
    downloadRequest = QtCore.pyqtSignal(str)

    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.viewer = QtGui.QPlainTextEdit(self)
        self.edit = QtGui.QLineEdit(self)
        self.edit.setFocus()
        self.button = QtGui.QPushButton('Download', self)
        self.button.clicked.connect(self.handleButton)
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.viewer)
        layout.addWidget(self.edit)
        layout.addWidget(self.button)
        # worker must not have a parent
        self._worker = Worker()
        self._thread = QtCore.QThread(self)
        self._worker.moveToThread(self._thread)
        self._worker.finished.connect(self._thread.quit)
        self._worker.error.connect(self.handleError)
        self._worker.dataReady.connect(self.handleDataReady)
        self.downloadRequest.connect(self._worker.process)

    def handleButton(self):
        url = self.edit.text().strip()
        if url and not self._thread.isRunning():
            self.viewer.clear()
            self._thread.start()
            # safely communicate with worker via signal
            self.downloadRequest.emit(url)

    def handleError(self, reason):
        self.viewer.clear()
        print('ERROR:', reason)

    def handleDataReady(self, data):
        self.viewer.setPlainText(data.decode('utf-8'))

    def closeEvent(self, event):
        if self._thread.isRunning():
            # Qt will complain if thread is still
            # running, so quit it before closing
            self._thread.quit()
            self._thread.wait()
        QtGui.QWidget.closeEvent(self, event)

if __name__ == '__main__':

    import sys
    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.edit.setText('http://stackoverflow.com')
    window.setGeometry(500, 300, 300, 300)
    window.show()
    sys.exit(app.exec_())

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM