threads in PyQt - TypeError: function () missing 2 required positional arguments:

1

Good afternoon, I hope someone can help me with this error: The code is executed but it throws me an error:

from PyQt5.QtWidgets import QMainWindow,QApplication, QTableWidgetItem
from PyQt5 import uic
import firebase_admin
from firebase_admin import credentials
from firebase_admin import db
import threading

class Principal(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        uic.loadUi("tabla-p.ui",self)



        self.funcion(self.tabla)

    def funcion(self,t):
        s = len(fire_val)
        while s >0:
            for key in fire_val.values():
                id = key.get('id')
                t.insertRow(t.rowCount())
                t.setItem(t.rowCount()-1,0,QTableWidgetItem(id))
                t.setItem(t.rowCount()-1,1,QTableWidgetItem(id))
            s =-1


    def fire():
        cred  =credentials.Certificate("2.json")
        firebase_admin.initialize_app(cred,{
            'databaseURL':'https://new1-3b819.firebaseio.com/'
        })

        ref = db.reference('/Productos_Bar')
        r1 = ref.get()

        global fire_val
        fire_val = r1
        return fire_val

thread = list()
thread2 = list()
t = threading.Thread(target=Principal.fire)
t2 = threading.Thread(target=Principal.funcion)
thread.append(t)
thread2.append(t2)
t.start()
t2.start()
t.join()
t2.join()

app = QApplication([])
p=Principal()
p.show()
app.exec_()

this is the error:

Exception in thread Thread-2:
    Traceback (most recent call last):
      File "C:\Users\Angel\AppData\Local\Programs\Python\Python36\lib\threading.py", line 916, in _bootstrap_inner
        self.run()
      File "C:\Users\Angel\AppData\Local\Programs\Python\Python36\lib\threading.py", line 864, in run
        self._target(*self._args, **self._kwargs)
    TypeError: funcion() missing 2 required positional arguments: 'self' and 't'

    [Finished in 4.1s]
    
asked by Revsky01 20.07.2018 в 07:52
source

1 answer

1

I do not understand how you point out that it works, because that code has many inconsistencies, such as:

  • where have you defined the variable t that you use as QTableWidget ?,
  • if t and t2 are going to be threads, why do you create them as lists?
  • the fire function could be said to be a static method so it does not require self and the data download is correct, but the funcion method is not, so that code should throw you an error.

Now let's go to the underlying problem:

  • Qt and many other libraries that serve to create GUIs do not support the direct modification of the GUI from another thread, each library offers a methodology to do it indirectly, in the case of Qt offers the signals that are thread -safe , to understand the reason read the next article .
  • On the other hand, I personally avoid using global variables since their debugging is complicated, and even worse when they are used together with threads. Another problem is their abuse that is seen a lot in beginners.

For the resolution of the problem I will assume that for the name of the QTableWidget it is tableWidget .

I will assume that the data that is received has the following structure:

To send the information of the other thread to the GUI I will create the signal messageSignal , and it will be issued when I have the complete data, this signal will connect to a slot that will receive and fill the QTableWidget.

from PyQt5.QtCore import pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import QMainWindow, QApplication, QTableWidgetItem
from PyQt5 import uic

import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

import threading

cred  = credentials.Certificate("2.json")
firebase_admin.initialize_app(cred, { 'databaseURL':'https://new1-3b819.firebaseio.com/'})


class Principal(QMainWindow):
    messageSignal = pyqtSignal(dict)

    def __init__(self):
        QMainWindow.__init__(self)
        uic.loadUi("tabla-p.ui",self)
        self.messageSignal.connect(self.actualizar_data)
        threading.Thread(target=self.obtener_data, args=("Productos_Bar", ), daemon=True).start()

    def obtener_data(self, endpoint):
        ref = db.reference(endpoint)
        fire_val = ref.get()
        self.messageSignal.emit(fire_val)

    @pyqtSlot(dict)
    def actualizar_data(self, message):
        for val in message.values():
            _id = val.get('id')
            count = self.tableWidget.rowCount()
            self.tableWidget.insertRow(count)
            self.tableWidget.setItem(count, 0, QTableWidgetItem(str(_id)))
            self.tableWidget.setItem(count, 1, QTableWidgetItem(str(_id)))


if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)
    p = Principal()
    p.show()
    sys.exit(app.exec_())
    
answered by 20.07.2018 / 14:07
source