1

The code below gives an error msg: "QObject::startTimer: timers cannot be started from another thread." I dont really get the reason why. Mostly because i just nearly get this threading issue and signal and slot mechanism. How can i pass the "int(percent)" variable to the dialog or the Main GUI's dialog to get a realtime refresh of the progressbar object?

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys
import urllib.request

class Main(QWidget):
    def __init__(self, parent = None):
        super(Main, self).__init__()
        self.label = QLabel("TheMainGUI")
        self.pushbutton = QPushButton("Download")

        layout = QHBoxLayout()
        layout.addWidget(self.label)
        layout.addWidget(self.pushbutton)
        self.setLayout(layout)

        self.pushbutton.clicked.connect(self.download)

    def download(self):
        self.filedownloadthread = FileDownloadThread()
        self.filedownloadthread.start()

class Dialog(QDialog):
    def __init__(self, parent = None):
        super(Dialog, self).__init__()
        self.progbar = QProgressBar()
        layout = QVBoxLayout()
        layout.addWidget(self.progbar)
        self.setLayout(layout)

class FileDownloadThread(QThread):
    def __init__(self):
        super(FileDownloadThread, self).__init__()
        self.dialog = Dialog()
        self.dialog.show()

    def run(self):
        url = "http://mysource.net//myfile"
        outputfile = "d://file//path//etc//myfile"

        def reporthook(blocknum, blocksize, totalsize):
            readsofar = blocknum * blocksize
            if totalsize > 0:
                percent = readsofar * 1e2 / totalsize

                self.dialog.progbar.setValue(int(percent))
                s = "\r%5.1f%% %*d / %d" % (
                    percent, len(str(totalsize)), readsofar, totalsize)
                sys.stderr.write(s)
                if readsofar >= totalsize:
                    sys.stderr.write("\n")
            else:
                sys.stderr.write("read %d\n" % (readsofar,))

        proxy = urllib.request.ProxyHandler({'http': "myproxy"})
        opener = urllib.request.build_opener(proxy)
        urllib.request.install_opener(opener)
        urllib.request.urlretrieve(url, outputfile, reporthook)

app = QApplication(sys.argv)
form = Main()
form.show()
app.exec_()
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Qfwfq
  • 185
  • 1
  • 7
  • You can't create or act on GUI elements outside of the main thread. You should instantiate `Dialog` outside of `FileDownloadThread` (eg. inside of `Main`) and send signals to it from `FileDownloadThread` to update the progress bar. – user3419537 Aug 04 '14 at 13:55
  • i updated the code. is this right then? – Qfwfq Aug 04 '14 at 14:58
  • 1
    You appear to have the right idea. Does it work now? I'm not so familiar with the old-style signals and slots mechanism you are using so I can't comment on whether it's correct or not. Also, try not to modify your original post with updates that make the code inconsistent with your original question as it only serves to confuse others. Adding updates to the end of the original post is preferable – user3419537 Aug 04 '14 at 15:31
  • 1
    Take a look at this article: http://pyqt.sourceforge.net/Docs/PyQt4/new_style_signals_slots.html I'd suggest you switch to the "new" style signal/slot mechanism for PyQt. – Bo Milanovich Aug 04 '14 at 15:56
  • @user3419537 I recommend you move your comment to an answer – Oliver Aug 04 '14 at 23:31
  • Thanks for the answers! Could you help me figure the new signalslot mechanism out? I don't really get it even after the article :D But using the oldstyle mechanism it works. – Qfwfq Aug 05 '14 at 09:07

1 Answers1

1

it works fine using the old signal and slot mechanism.

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys
import urllib.request

class Main(QWidget):
    def __init__(self, parent = None):
        super(Main, self).__init__()
        self.label = QLabel("TheMainGUI")
        self.pushbutton = QPushButton("Download")

        layout = QHBoxLayout()
        layout.addWidget(self.label)
        layout.addWidget(self.pushbutton)
        self.setLayout(layout)

        self.pushbutton.clicked.connect(self.download)

    def download(self):
        self.dialog = Dialog()
        self.dialog.show()

class Dialog(QDialog):
    def __init__(self, parent = None):
        super(Dialog, self).__init__()
        self.progbar = QProgressBar()
        layout = QVBoxLayout()
        layout.addWidget(self.progbar)
        self.setLayout(layout)

        self.filedownloadthread = FileDownloadThread()
        self.connect(self.filedownloadthread, SIGNAL('signal'), self.update)
        self.filedownloadthread.start()

    def update(self, percent):
        self.progbar.setValue(percent)

class FileDownloadThread(QThread):
    def __init__(self):
        super(FileDownloadThread, self).__init__()

    def run(self):
        url = "http://mysource.net//myfile"
        outputfile = "d://file//path//etc//myfile"

        def reporthook(blocknum, blocksize, totalsize):
            readsofar = blocknum * blocksize
            if totalsize > 0:
                percent = readsofar * 1e2 / totalsize

                self.dialog.progbar.setValue(int(percent))
                s = "\r%5.1f%% %*d / %d" % (
                    percent, len(str(totalsize)), readsofar, totalsize)
                sys.stderr.write(s)
                if readsofar >= totalsize:
                    sys.stderr.write("\n")
            else:
                sys.stderr.write("read %d\n" % (readsofar,))
            self.emit(SIGNAL('signal'), int(percent))

        proxy = urllib.request.ProxyHandler({'http': "myproxy"})
        opener = urllib.request.build_opener(proxy)
        urllib.request.install_opener(opener)
        urllib.request.urlretrieve(url, outputfile, reporthook)

app = QApplication(sys.argv)
form = Main()
form.show()
app.exec_()
Qfwfq
  • 185
  • 1
  • 7