Creating Pyqt5 Buttons in a Loop: All Buttons Trigger the Same Callback

Creating PyQt5 buttons in a loop: all buttons trigger the same callback

I do not understand what type of structure is matrix, but I think it is equivalent to a list of dictionaries.

The problem is that you must pass as an argument to the lambda function assigning it, the clicked signal takes as a parameter a Boolean value that indicates that if the button is checked or not (by default this property is disabled so that this value is false), you must add another parameter.

class App(QMainWindow):
def launch(self, filepath):
subprocess.run(filepath)

def __init__(self):
super(App, self).__init__()

matrix = [{"path": "path1", "setIcon": "icon1", "posx": 0, "posy": 0},
{"path": "path2", "setIcon": "icon2", "posx": 0, "posy": 150},
{"path": "path3", "setIcon": "icon3", "posx": 0, "posy": 300}]

for value in matrix:

filepath = value['path']
icon = value['setIcon']
posx = value['posx']
posy = value['posy']

btn = QToolButton(self)
btn.setIcon(QIcon(icon))
btn.setIconSize(QSize(64, 64))
btn.resize(100, 100)
btn.move(posx, posy)
btn.clicked.connect(lambda checked, arg=filepath: self.launch(arg))

self.initUI()

def initUI(self):
self.setGeometry(150, 150, 1250, 650)
self.setWindowTitle('LinuxLauncher')
self.show()

Blinking buttons in PyQT5

The property does not save the initial state so even if you pair the animation it will not be restored to the initial state. So the solution in this case is to save that state in a variable and create a reset_color() method that restores the color again..

On the other hand the error message: TypeError: unable to convert to Python 'QBrush' object to a C ++ 'QColor' instance indicates that the code self.button_stop.palette().base() returns a QBrush, but it is expected a QColor, and there is no conversion implied, so that implementation must be changed.

As a matter of order I will create a new class that inherits from QPushButton and implement those properties.

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

class BlinkButton(QPushButton):
def __init__(self, *args, **kwargs):
QPushButton.__init__(self, *args, **kwargs)
self.default_color = self.getColor()

def getColor(self):
return self.palette().color(QPalette.Button)

def setColor(self, value):
if value == self.getColor():
return
palette = self.palette()
palette.setColor(self.backgroundRole(), value)
self.setAutoFillBackground(True)
self.setPalette(palette)

def reset_color(self):
self.setColor(self.default_color)

color = pyqtProperty(QColor, getColor, setColor)

class Widget(QWidget):

def __init__(self):
super(Widget, self).__init__()

self.resize(300,200)
layout = QVBoxLayout(self)

self.button_stop = BlinkButton("Stop")
layout.addWidget(self.button_stop)

self.button_start = QPushButton("Start", self)
layout.addWidget(self.button_start)

self.animation = QPropertyAnimation(self.button_stop, "color", self)
self.animation.setDuration(1000)
self.animation.setLoopCount(100)
self.animation.setStartValue(self.button_stop.default_color)
self.animation.setEndValue(self.button_stop.default_color)
self.animation.setKeyValueAt(0.1, QColor(0,255,0))

self.button_start.clicked.connect(self.animation.start)
self.button_stop.clicked.connect(self.stop)

def stop(self):
self.animation.stop()
self.button_stop.reset_color()

if __name__ == "__main__":
app = QApplication([])
w = Widget()
w.show()
app.exec_()

QtCore.QObject.connect in a loop only affects the last instance

I have same problem , you should use functools.partial such as:

for key, val in a_DICT_THAT_YOU_STORED_YOUR_OBJECTS_AND_STRINGS:
obj = partial( findInstance.projectsInstance.myslot,arg1="TWCH",arg2=self,arg3=key,arg4=val.checkState() )
QtCore.QObject.connect(val, QtCore.SIGNAL(_fromUtf8("stateChanged (int)")), obj)

Of course, argX should set to your real name of your argument of your function name.

Using lambda expression to connect slots in pyqt

The QPushButton.clicked signal emits an argument that indicates the state of the button. When you connect to your lambda slot, the optional argument you assign idx to is being overwritten by the state of the button.

Instead, make your connection as

button.clicked.connect(lambda state, x=idx: self.button_pushed(x))

This way the button state is ignored and the correct value is passed to your method.



Related Topics



Leave a reply



Submit