Yulia
Yulia

Reputation: 31

Bind dynamically made widgets to one signal in PyQt5

I have a frame to which layout I dynamically add lineedits clicking on a toolbutton. I need all of these lineedits to work with my autocompleter on signal textChanged. I can't quite understand how to do it. I saw while researching that lambda may help but I couldnt't do it. I guess it's because I poorly understand how all this works. I used QtDesigner and this tutorial to make GUI. My code is in two files - in the first there are just widgets:

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(799, 424)
        ...
        self.toolbutton_add_score = QtWidgets.QToolButton(self.groupbox_scores)
        self.toolbutton_add_score.setObjectName("toolbutton_add_score")
        self.layout_groupbox_scores.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.toolbutton_add_score)
        self.frame_movies_scores = QtWidgets.QFrame(self.groupbox_scores)
        self.frame_movies_scores.setObjectName("frame_movies_scores")
        self.layout_frame_movies_scores = QtWidgets.QGridLayout(self.frame_movies_scores)
        self.layout_frame_movies_scores.setObjectName("layout_frame_movies_scores")
        self.lineedit_input_movie = QtWidgets.QLineEdit(self.frame_movies_scores)
        self.lineedit_input_movie.setObjectName("lineedit_input_movie")
        self.layout_frame_movies_scores.addWidget(self.lineedit_input_movie, 0, 0)

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Рекомендательная система"))
        ...

In the second one there are my functions:

class MyWin(QtWidgets.QMainWindow):
    def __init__(self, parent = None):
        QtWidgets.QWidget.__init__(self, parent)
        self.ui = Ui_Form()
        self.ui.setupUi(self)
        self.ui.lineedit_input_movie.textChanged.connect(self.autocomplete)
        self.ui.toolbutton_add_score.clicked.connect(self.add_score_field)

    def autocomplete(self):
        cursor.execute("SELECT title FROM movies WHERE title LIKE '%%' || %s || '%%';", (self.ui.lineedit_input_movie.text(),))
        it = cursor.fetchall()
        strings = [item[0] for item in it]
        completer = QtWidgets.QCompleter(strings, self)
        self.ui.lineedit_input_movie.setCompleter(completer)
        self.ui.lineedit_input_movie.show()

    def add_score_field(self):
        self.lineedit_input_movie = QtWidgets.QLineEdit(self.ui.frame_movies_scores)
        self.lineedit_input_movie.setObjectName("lineedit_input_movie")
        self.ui.layout_frame_movies_scores.addWidget(self.lineedit_input_movie, r, 0)

The code here works only for the fiers lineedit in layout. What do I have to do to make it work for all lineedits in the layout?

Upvotes: 1

Views: 230

Answers (1)

MrLeeh
MrLeeh

Reputation: 5589

You need to put your additional fields in a list to keep their references. At the moment you are overwriting your existing field which is not good. Also you need to connect your textChanged signal for each new field.

class MyWin(QtWidgets.QMainWindow):

    def __init__(self, parent = None):

        self.score_fields = []
        # ...


    def add_score_field(self):

        # Create a new Line Edi
        new_lineedit = QtWidgets.QLineEdit(self.ui.frame_movies_scores)
        new_lineedit.setObjectName("lineedit_input_movie")

        # append it to your score_fields list
        self.score_fields.append(new_lineedit)

        # add it to your layout
        self.ui.layout_frame_movies_scores.addWidget(new_lineedit, r, 0)

        # connect your signal
        new_lineedit.textChanged.connect(self.autocomplete)

Upvotes: 1

Related Questions