2017-01-25 1 views
2

현재 PyQt의 스레딩에 대한 this 스레딩 자습서 (here 코드)를 따르고 있습니다. PyQt4 (및 Python2)로 작성 되었기 때문에 PyQt5 및 Python3에서 작동하도록 코드를 수정했습니다.PyQt5 : 객체에 '연결'속성이 없습니다.

# -*- coding: utf-8 -*- 

# Form implementation generated from reading ui file 'threading_design.ui' 
# 
# Created by: PyQt5 UI code generator 5.6 
# 
# WARNING! All changes made in this file will be lost! 

from PyQt5 import QtCore, QtGui, QtWidgets 

class Ui_MainWindow(object): 
    def setupUi(self, MainWindow): 
     MainWindow.setObjectName("MainWindow") 
     MainWindow.resize(526, 373) 

     self.centralwidget = QtWidgets.QWidget(MainWindow) 
     self.centralwidget.setObjectName("centralwidget") 
     self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget) 
     self.verticalLayout.setObjectName("verticalLayout") 
     self.subreddits_input_layout = QtWidgets.QHBoxLayout() 
     self.subreddits_input_layout.setObjectName("subreddits_input_layout") 
     self.label_subreddits = QtWidgets.QLabel(self.centralwidget) 
     self.label_subreddits.setObjectName("label_subreddits") 
     self.subreddits_input_layout.addWidget(self.label_subreddits) 
     self.edit_subreddits = QtWidgets.QLineEdit(self.centralwidget) 
     self.edit_subreddits.setObjectName("edit_subreddits") 
     self.subreddits_input_layout.addWidget(self.edit_subreddits) 
     self.verticalLayout.addLayout(self.subreddits_input_layout) 
     self.label_submissions_list = QtWidgets.QLabel(self.centralwidget) 
     self.label_submissions_list.setObjectName("label_submissions_list") 
     self.verticalLayout.addWidget(self.label_submissions_list) 
     self.list_submissions = QtWidgets.QListWidget(self.centralwidget) 
     self.list_submissions.setBatchSize(1) 
     self.list_submissions.setObjectName("list_submissions") 
     self.verticalLayout.addWidget(self.list_submissions) 
     self.progress_bar = QtWidgets.QProgressBar(self.centralwidget) 
     self.progress_bar.setProperty("value", 0) 
     self.progress_bar.setObjectName("progress_bar") 
     self.verticalLayout.addWidget(self.progress_bar) 
     self.buttons_layout = QtWidgets.QHBoxLayout() 
     self.buttons_layout.setObjectName("buttons_layout") 
     self.btn_stop = QtWidgets.QPushButton(self.centralwidget) 
     self.btn_stop.setEnabled(False) 
     self.btn_stop.setObjectName("btn_stop") 
     self.buttons_layout.addWidget(self.btn_stop) 
     self.btn_start = QtWidgets.QPushButton(self.centralwidget) 
     self.btn_start.setObjectName("btn_start") 
     self.buttons_layout.addWidget(self.btn_start) 
     self.verticalLayout.addLayout(self.buttons_layout) 
     MainWindow.setCentralWidget(self.centralwidget) 

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

    def retranslateUi(self, MainWindow): 
     _translate = QtCore.QCoreApplication.translate 
     MainWindow.setWindowTitle(_translate("MainWindow", "Threading Tutorial - nikolak.com ")) 
     self.label_subreddits.setText(_translate("MainWindow", "Subreddits:")) 
     self.edit_subreddits.setPlaceholderText(_translate("MainWindow", "python,programming,linux,etc (comma separated)")) 
     self.label_submissions_list.setText(_translate("MainWindow", "Submissions:")) 
     self.btn_stop.setText(_translate("MainWindow", "Stop")) 
     self.btn_start.setText(_translate("MainWindow", "Start")) 

메인 스크립트 (main.py) :

AttributeError: 'ThreadingTutorial' object has no attribute 'connect'

:

from PyQt5 import QtWidgets 
from PyQt5.QtCore import QThread, pyqtSignal, QObject 
import sys 
import newdesign 
import urllib.request 
import json 
import time 


class getPostsThread(QThread): 
    def __init__(self, subreddits): 
     """ 
     Make a new thread instance with the specified 
     subreddits as the first argument. The subreddits argument 
     will be stored in an instance variable called subreddits 
     which then can be accessed by all other class instance functions 

     :param subreddits: A list of subreddit names 
     :type subreddits: list 
     """ 
     QThread.__init__(self) 
     self.subreddits = subreddits 

    def __del__(self): 
     self.wait() 

    def _get_top_post(self, subreddit): 
     """ 
     Return a pre-formatted string with top post title, author, 
     and subreddit name from the subreddit passed as the only required 
     argument. 

     :param subreddit: A valid subreddit name 
     :type subreddit: str 
     :return: A string with top post title, author, 
        and subreddit name from that subreddit. 
     :rtype: str 
     """ 
     url = "https://www.reddit.com/r/{}.json?limit=1".format(subreddit) 
     headers = {'User-Agent': '[email protected] tutorial code'} 
     request = urllib.request.Request(url, header=headers) 
     response = urllib.request.urlopen(request) 
     data = json.load(response) 
     top_post = data['data']['children'][0]['data'] 
     return "'{title}' by {author} in {subreddit}".format(**top_post) 

    def run(self): 
     """ 
     Go over every item in the self.subreddits list 
     (which was supplied during __init__) 
     and for every item assume it's a string with valid subreddit 
     name and fetch the top post using the _get_top_post method 
     from reddit. Store the result in a local variable named 
     top_post and then emit a pyqtSignal add_post(QString) where 
     QString is equal to the top_post variable that was set by the 
     _get_top_post function. 

     """ 
     for subreddit in self.subreddits: 
      top_post = self._get_top_post(subreddit) 
      self.emit(pyqtSignal('add_post(QString)'), top_post) 
      self.sleep(2) 


class ThreadingTutorial(QtWidgets.QMainWindow, newdesign.Ui_MainWindow): 
    """ 
    How the basic structure of PyQt GUI code looks and behaves like is 
    explained in this tutorial 
    http://nikolak.com/pyqt-qt-designer-getting-started/ 
    """ 

    def __init__(self): 
     super(self.__class__, self).__init__() 
     self.setupUi(self) 
     self.btn_start.clicked.connect(self.start_getting_top_posts) 

    def start_getting_top_posts(self): 
     # Get the subreddits user entered into an QLineEdit field 
     # this will be equal to '' if there is no text entered 
     subreddit_list = str(self.edit_subreddits.text()).split(',') 
     if subreddit_list == ['']: # since ''.split(',') == [''] we use that to check 
            # whether there is anything there to fetch from 
            # and if not show a message and abort 
      QtWidgets.QMessageBox.critical(self, "No subreddits", 
             "You didn't enter any subreddits.", 
             QtWidgets.QMessageBox.Ok) 
      return 
     # Set the maximum value of progress bar, can be any int and it will 
     # be automatically converted to x/100% values 
     # e.g. max_value = 3, current_value = 1, the progress bar will show 33% 
     self.progress_bar.setMaximum(len(subreddit_list)) 
     # Setting the value on every run to 0 
     self.progress_bar.setValue(0) 

     # We have a list of subreddits which we use to create a new getPostsThread 
     # instance and we pass that list to the thread 
     self.get_thread = getPostsThread(subreddit_list) 

     # Next we need to connect the events from that thread to functions we want 
     # to be run when those pyqtSignals get fired 

     # Adding post will be handeled in the add_post method and the pyqtSignal that 
     # the thread will emit is pyqtSignal("add_post(QString)") 
     # the rest is same as we can use to connect any pyqtSignal 
     self.connect(self.get_thread, pyqtSignal("add_post(QString)"), self.add_post) 

     # This is pretty self explanatory 
     # regardless of whether the thread finishes or the user terminates it 
     # we want to show the notification to the user that adding is done 
     # and regardless of whether it was terminated or finished by itself 
     # the finished pyqtSignal will go off. So we don't need to catch the 
     # terminated one specifically, but we could if we wanted. 
     self.connect(self.get_thread, pyqtSignal("finished()"), self.done) 

     # We have all the events we need connected we can start the thread 
     self.get_thread.start() 
     # At this point we want to allow user to stop/terminate the thread 
     # so we enable that button 
     self.btn_stop.setEnabled(True) 
     # And we connect the click of that button to the built in 
     # terminate method that all QThread instances have 
     self.btn_stop.clicked.connect(self.get_thread.terminate) 
     # We don't want to enable user to start another thread while this one is 
     # running so we disable the start button. 
     self.btn_start.setEnabled(False) 

    def add_post(self, post_text): 
     """ 
     Add the text that's given to this function to the 
     list_submissions QListWidget we have in our GUI and 
     increase the current value of progress bar by 1 

     :param post_text: text of the item to add to the list 
     :type post_text: str 
     """ 
     self.list_submissions.addItem(post_text) 
     self.progress_bar.setValue(self.progress_bar.value()+1) 

    def done(self): 
     """ 
     Show the message that fetching posts is done. 
     Disable Stop button, enable the Start one and reset progress bar to 0 
     """ 
     self.btn_stop.setEnabled(False) 
     self.btn_start.setEnabled(True) 
     self.progress_bar.setValue(0) 
     QtWidgets.QMessageBox.information(self, "Done!", "Done fetching posts!") 


def main(): 
    app = QtWidgets.QApplication(sys.argv) 
    form = ThreadingTutorial() 
    form.show() 
    app.exec_() 

if __name__ == '__main__': 
    main() 

지금 나는 다음과 같은 오류가있어 여기에

는 GUI 파일 ( newdesign.py)입니다

아무도 말해 줄 수 없습니까? 이 문제를 해결하는 방법? 어떤 도움도 언제나처럼 대단히 감사하게 될 것입니다. 더 이상 QObject.connect() 및 PyQt4 유사은 "이전 스타일 신호"로 알려져 있으며, is not supported in PyQt5를 사용

답변

3

, 그것은 이미 PyQt4에 신호를 연결하기 위해 권장되는 방법이었다 만 "New style signals" 지원합니다.

PyQt5에서 바운드 신호의 connect()emit() 방법을 직접 사용해야합니다. 대신 :

self.emit(pyqtSignal('add_post(QString)'), top_post) 
... 
self.connect(self.get_thread, pyqtSignal("add_post(QString)"), self.add_post) 
self.connect(self.get_thread, pyqtSignal("finished()"), self.done) 

사용 :

self.add_post.emit(top_post) 
... 
self.get_thread.add_post.connect(self.add_post) 
self.get_thread.finished.connect(self.done) 

그러나 이것에 대한 그렇지 않으면 속성 오류가 발생합니다, 당신은 명시 적으로 getPostsThread 처음에 add_post 신호를 정의 할 필요가 작동합니다. 이전 스타일 신호와 PyQt4에서

class getPostsThread(QThread): 
    add_post = pyqtSignal(str) 
    ... 

신호가 사용되었다

는이 지금은 명시 적으로 수행 될 필요가 automatically defined했다.

+0

아주 좋은 설명을 해주셔서 감사합니다! – dliv

관련 문제