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!

1
  • Sorry about 'matrix' - see the comment under the answer below. Commented Mar 8, 2018 at 23:56

1 Answer 1

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()
Sign up to request clarification or add additional context in comments.

4 Comments

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 to know how to mark an answer as correct, review the tour
For the record I realize you were right - the yaml data is a list of dictionaries, not a dictionary of dictionaries.
how can i pass multiple arguments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.