1

I need to change the color of QPushButton, but an error occurred: "AttributeError: type object 'ProyectoTFM' has no attribute 'ui'". I don't know hoy to acced to a ui variable from my thread. This is my code:

import sys
import OpenOPC
import time
import threading

from proyectoQt import *


def actualizarDatosOPC():
    while 1:
        time.sleep(5)
        if(itemsOPC[15])[1]!=0:
            #Error on next line
            ProyectoTFM.ui.AP08Button.setStyleSheet("background-color: red")
    return


class ProyectoTFM(QtGui.QMainWindow):
    def __init__(self,parent=None):
        QtGui.QMainWindow.__init__(self,parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.startTheThread()
        print('Init')

    def startTheThread(self):
        threadQt = threading.Thread(target = actualizarDatosOPC)
        threadQt.start()


def clienteOPC():
    opc=OpenOPC.client()
    opc.connect('Kepware.KEPServerEX.V6')

    global itemsOPC

    while 1:
        itemsOPC = opc.read(opc.list('PLC.PLC.TAGS'))
        time.sleep(5)
    return

threads = list()
threadOPC = threading.Thread(target=clienteOPC)
threads.append(threadOPC)
threadOPC.start()
time.sleep(5)


if __name__== "__main__":
    app=QtGui.QApplication(sys.argv)
    myapp = ProyectoTFM()
    myapp.show()
    sys.exit(app.exec_())
    threadOPC.__delete()

Sorry for my English and thanks.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Daniel Garcia
  • 85
  • 1
  • 1
  • 4

3 Answers3

0

A few things:

  1. You never actually pass the UI to the function actualizarDatosOPC so it doesn't know it exists.
  2. Is there any reason you can't use PyQt's built in threading tools? If you are going to use PyQt it might make sense to buy into the whole framework.

    def startTheThread(self):
        self.threadQt = QThread()
        d = actualizarDatosOPC(self)
        d.moveToThread(self.threadQt) 
        self.threadQt.start()
    
    def actualizarDatosOPC(widget):
        .... widget.AP08Button.setStyleSheet("background-color: red")
    

If you do choose to go this route, I'd take a look at this thread which has a good example: How to use QThread correctly in pyqt with moveToThread()?

Additionally, while the way you initialize your Window works, this is the more standard way to do it:

class ProyectoTFM(QMainWindow, Ui_MainWindow):
    def __init__(self, parent):
        # General Init Stuff
        super(Login, self).__init__(parent)
        self.setupUi(self)

After that, whenever you want to refer to something in the UI all you need to do is refer to self._____. For example, if you have a button named buttonA, self.buttonA would be the appropriate reference.

Edit: As mentioned in another answer, the proper way to actually change the button color would be to emit a trigger that to the main thread which could then respond by changing the button color.

Community
  • 1
  • 1
aoh
  • 1,090
  • 2
  • 13
  • 25
0

Even if you got this to work, you can't modify the UI from a thread directly.

The Compiler
  • 11,126
  • 4
  • 40
  • 54
0

It is not correct to modify the view from a different thread to the main one, a way to solve the problem without using QThread is to create a signal that connects to some slot that changes the color of the button. To be able to emit the signal from the new thread we must pass the object to him through the parameter args.

def actualizarDatosOPC(obj):
    while 1:
        time.sleep(5)
        if(itemsOPC[15])[1]!=0:
            #Error on next line
            obj.sendChangeColor.emit()
    return


class ProyectoTFM(QtGui.QMainWindow):
    sendChangeColor = QtCore.pyqtSignal()
    def __init__(self,parent=None):
        QtGui.QMainWindow.__init__(self,parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.startTheThread()
        print('Init')
        self.sendChangeColor.connect(lambda: self.ui.AP08Button.setStyleSheet("background-color: red"))

    def startTheThread(self):
        threadQt = threading.Thread(target = actualizarDatosOPC, args=(self,))
        threadQt.start()
eyllanesc
  • 235,170
  • 19
  • 170
  • 241