Create a tree using threads

Heads up! You've already completed this tutorial.

GiUnZ | 2021-06-27 18:56:12 UTC | #1

I am trying to create an application that will be getting data through an API and present them in QTreeView, using PySide6. As it takes a long time to get the data I want to retrieve them using a QThread. My example code is the following: import logging import time

python
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *

logging.basicConfig(
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
    level=logging.INFO)

class MainWindow(QMainWindow):
    gettingData = False
    counting = False


    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.counter = 0

        layout = QVBoxLayout()


        self.b = QPushButton("Start Counting with a Thread")
        self.bt1 = QPushButton("Generate tree with Thread")
        self.bt2 = QPushButton("Generate tree without a Thread")
        self.tree = QTreeView()

        layout.addWidget(self.b)
        layout.addWidget(self.bt1)
        layout.addWidget(self.bt2)
        layout.addWidget(self.tree)
        self.b.clicked.connect(self.startCounting)
        self.bt1.clicked.connect(self.startGenerating)
        self.bt2.clicked.connect(self.startGenerating2)

        w = QWidget()
        w.setLayout(layout)

        self.setCentralWidget(w)

        self.show()

        self.threadpool = QThreadPool()
        print("Multithreading with maximum %d threads" % self.threadpool.maxThreadCount())

    def startCounting(self):
        thread = Thread(self.counting)
        thread.signal.signal.connect(self.something)
        self.threadpool.start(thread)

    def something(self, signal):
        if signal == "False":
            logging.info("Counting is Complete")
        else:
            logging.info(signal)

    def startGenerating(self):
        thread = DataThread()
        thread.signals.signal_QStandardItemModel(self.treeAction)
        self.threadpool.start(thread)

    def treeAction(self,signal):
        self.tree.setModel(signal)

    def startGenerating2(self):
        start = time.perf_counter()
        siteTreeViewModel = QStandardItemModel()
        rootNode = siteTreeViewModel.invisibleRootItem()
        aItem = TreeStandardItem("A")
        bItem = TreeStandardItem("B")
        cItem = TreeStandardItem("C")
        rootNode.appendRow(aItem)
        time.sleep(3)
        rootNode.appendRow(bItem)
        time.sleep(3)
        bItem.appendRow(cItem)
        self.tree.setModel(siteTreeViewModel) 
        end = time.perf_counter() - start
        logging.info("Generated tree in "+str(end))



class Thread(QRunnable):

    def __init__(self, counting):
        super(Thread, self).__init__()
        self.counting = counting
        self.signal = Signal()

    def run(self):
        for x in range(10):
            self.signal.signal.emit(str(x))
            time.sleep(.1)
        counting = False
        self.signal.signal.emit(str(counting))

class Signal(QObject):
    signal = Signal(str)

class DataThread(QRunnable):

    def __init__(self):
        super(DataThread, self).__init__()
        self.signals = WorkerSignals()

    def run(self):
        logging.info("Start generating the tree")

        start = time.perf_counter()
        siteTreeViewModel = QStandardItemModel()
        rootNode = siteTreeViewModel.invisibleRootItem()
        aItem = TreeStandardItem("A")
        bItem = TreeStandardItem("B")
        cItem = TreeStandardItem("C")
        rootNode.appendRow(aItem)
        time.sleep(2)
        rootNode.appendRow(bItem)
        time.sleep(2)
        bItem.appendRow(cItem)
        end = time.perf_counter() - start
        self.signals.signal_QStandardItemModel.emit(siteTreeViewModel)
        logging.info("Generated tree in "+str(end))
        self.signals.finished.emit()

class TreeStandardItem(QStandardItem):
    def __init__(self, txt=''):
        super().__init__()
        self.setEditable = False
        self.setForeground(QColor(255, 255, 255))
        self.setText(txt)

class WorkerSignals(QObject):
    signal_QStandardItemModel = Signal()
    finished = Signal()

app = QApplication([])
window = MainWindow()
app.exec()

The first counting button works as expected creating a thread. Generating the tree without a thread, confirms that the code I am trying to run using a thread is working Once I try running the tree generation using thread, I get the following error:

python
Traceback (most recent call last):
  File "/home/giunz/code/tutorial/threaded-tree-01.py", line 61, in startGenerating
    thread.signals.signal_QStandardItemModel(self.treeAction)
TypeError: 'Signal' object is not callable

Any help on how to generate the tree using a thread, would be appreciated.

Thanks in advance


Create GUI Applications with Python & Qt6 by Martin Fitzpatrick — (PySide6 Edition) The hands-on guide to making apps with Python — Over 10,000 copies sold!

More info Get the book

Well done, you've finished this tutorial! Mark As Complete
[[ user.completed.length ]] completed [[ user.streak+1 ]] day streak

Create a tree using threads was written by Martin Fitzpatrick .

Martin Fitzpatrick has been developing Python/Qt apps for 8 years. Building desktop applications to make data-analysis tools more user-friendly, Python was the obvious choice. Starting with Tk, later moving to wxWidgets and finally adopting PyQt.