Search code examples
pythonpyqt5qt-designerqtablewidgetqdialog

QDialog:Trouble Loading Data Into QTableWidget From A User Input


I'm attempting to have a QDialog that gives the user the feature to search up data based on their input. The data is connected to a database.

The user types what they want to look for {self.search_name.text()} which is then queried in the database {self.c.execute} and displayed in a QTableWidget {package_list} after clicking search (self.loaddata).

The issue I am having is loading the data into the table. I know the query works because if I predefine what I want to look for in my code the table will populate. I am getting no errors when running the script.

Any ideas on how to fix this or maybe another way of accomplishing the same goal without using a QDialog?

 class SearchPackageByNameDialog(QDialog):
    def __init__(self, *args, **kwargs):

        super(SearchPackageByNameDialog, self).__init__(*args, **kwargs)
        self.setStyleSheet("background-color: rgb(28, 66, 32);\n"
"font: 10pt \"Courier New\";\n"
"")


        loadUi('GUIs/PackageLookupNameDailog.ui',self)

        self.btn_search.clicked.connect(self.loaddata)


        self.loaddata()


    def loaddata(self):

        searchrol = self.search_name.text()

        searchresult = '"'+searchrol+'"'


        self.conn = sqlite3.connect("database.db")
        self.c = self.conn.cursor()
        self.c.execute("CREATE TABLE IF NOT EXISTS Packages(Tracking_Number TEXT PRIMARY KEY,Recipient TEXT,DateIn TEXT,DateOut TEXT)")
        self.c.close()


        self.package_list = QtWidgets.QTableWidget(self)

        self.package_list.setGeometry(QtCore.QRect(10, 110, 600, 300))
        self.package_list.setAlternatingRowColors(True)
        self.package_list.setColumnCount(4)
        self.package_list.setColumnWidth(0,200)
        self.package_list.setColumnWidth(1,200)
        self.package_list.setColumnWidth(2,100)
        self.package_list.setColumnWidth(3,100)
        self.package_list.horizontalHeader().setCascadingSectionResizes(False)
        self.package_list.horizontalHeader().setSortIndicatorShown(False)
        self.package_list.horizontalHeader().setStretchLastSection(True)
        self.package_list.verticalHeader().setVisible(False)
        self.package_list.verticalHeader().setCascadingSectionResizes(False)
        self.package_list.verticalHeader().setStretchLastSection(False)
        self.package_list.setHorizontalHeaderLabels(("Tracking Number", "Recipient", "Date In", "Date Out"))
        self.package_list.setStyleSheet("font: 14pt 'Courier New';background-color: rgb(114, 104, 112);\n"
"alternate-background-color: rgb(124, 136, 126);\n"
"border-color: rgb(160, 141, 131);\n"
"gridline-color: rgb(145, 150, 127);")


        self.connection = sqlite3.connect("database.db")
        query = "SELECT * from Packages WHERE recipient IS "+str(searchresult)
        result = self.connection.execute(query)
        print(query)
        self.package_list.setRowCount(0)
        for row_number, row_data in enumerate(result):
            self.package_list.insertRow(row_number)
            for column_number, data in enumerate(row_data):
                self.package_list.setItem(row_number, column_number,QTableWidgetItem(str(data)))
        self.connection.close()   

Solution

  • The problem is that you're creating a new table each time loaddata is called.

    If the table already exists in the ui you're using, then just use that, but from the look of your code it probably doesn't.

    How to solve it (in the wrong way)

    For the sake of completeness, I'll tell you that you could just add the following line after creating the table:

        self.package_list.show()
    

    This is required because when a widget is added to a parent and that widget is not managed by a layout (more about this later), that widget does not become visible if the parent already is.

    The first time the dialog is created, it creates the table because you called loaddata in the __init__, and then the dialog is shown. In this case, when a parent is shown, each of its children are shown too (even if they were not explicitly shown) unless hide() or setVisible(False) is explicitly called on those widget. After that, any new "free" widget created as child must be explicitly shown with show() or setVisible(True).

    BUT, no.

    This should not be necessary. First of all, because if a table already exists, there's no need to create one.

    The correct solution is to create the table in the __init__, possibly by setting there everything that will certainly not change by the search query: headers settings, alternating row colors, etc.

    Layouts, layouts, layouts

    There are very, very few, rare and specific cases for which is absolutely necessary to use fixed geometries (setGeometry(), move(), resize()) for widgets. The rule of thumb is: if you're using fixed geometries, you're probably doing it wrong.

    These are the main reasons for which it should be avoided:

    • if the user resizes the window to a smaller size, some widgets will become partially or completely invisible: consider what happens for a user that has a smaller screen size than yours;
    • if the window is resized to a bigger size, there will be a lot of unused space (and it will look ugly);
    • what you see on your screen is almost never what others will see in theirs: different default font or DPI will potentially force some widgets to increase their minimum size, with the result that some widgets will overlap with others;

    Layout managers are always the first and right choice, and you can easily create them within Qt Designer. Do consider that this is mandatory even if you want to set a fixed size for your window (see the third point of the list above).