3

I should mention that I've read these but I'm still unable to achieve my goal:

[Using a dictionary in a for loop to create buttons doesn't work

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

My goal is to make a linux 'launcher' application. Button creation, placement, etc. is working like a charm but there's one problem - all buttons trigger the same callback - the last one to be connected in the button creation loop.

Here's a basic version of the script to illustrate what I'm trying to do:

class App(QMainWindow):

    def launch(self, filepath):
        subprocess.run(filepath)


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

        for btn in matrix:

            filepath = matrix[btn]['path']
            icon = matrix[btn]['setIcon']
            posx = matrix[btn]['posx']
            posy = matrix[btn]['posy']

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

        self.initUI()


    def initUI(self):

        self.setGeometry(150, 150, 1250, 650)
        self.setWindowTitle('LinuxLauncher')

        self.show()


    if __name__ == '__main__':

        app = QApplication(sys.argv)
        ex = App()
        sys.exit(app.exec_())

I know there's an answer but I've been at it for hours - I'd appreciate it someone could help me out of this jam - Thanks!

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
tscv11
  • 55
  • 1
  • 7

1 Answers1

9

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()
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Thank you for your answer - it works! Sorry I didn't explain 'matrix' - it's a dictionary of dictionaries read from a yaml file and specifies which icons, where to place the buttons, etc. Excellent job, sir! I will accept your answer just as soon as I can figure out how (this is my first question ever). – tscv11 Mar 08 '18 at 23:54
  • @tscv11 to know how to mark an answer as correct, review the [tour] – eyllanesc Mar 08 '18 at 23:56
  • For the record I realize you were right - the yaml data is a list of dictionaries, not a dictionary of dictionaries. – tscv11 Mar 09 '18 at 00:12
  • how can i pass multiple arguments – Sadique Khan Aug 28 '22 at 07:11