0

I'm new to python. I designed a GUI in QtDesigner and translated the code to use it with python. Since if I change something in the GUI it will overwrite my code I want to use a separate file for the functions.

The code should run after the main window is shown but I get an error

Ui_MainWindow' object has no attribute 'fillContactList'

I would really appreciate if anyone would help me.

import sys
import psycopg2
from PySide6 import (QtCore, QtWidgets, QtGui)
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
     QMetaObject, QObject, QPoint, QRect,
     QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
    QFont, QFontDatabase, QGradient, QIcon,
    QImage, QKeySequence, QLinearGradient, QPainter,
    QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QApplication, QLabel, QMainWindow, QMenuBar,
    QSizePolicy, QStatusBar, QTabWidget, QWidget)

from mainwindow import Ui_MainWindow

class mainwindow(QMainWindow, Ui_MainWindow):

   def __init__(self):
       super(mainwindow, self).__init__()
       self.setWindowTitle("Skills In Motion")

   def fillContactList(self):
           conn = psycopg2.connect(database="CRM", user="********", password="*****", host="localhost", port=5432)
           cur = conn.cursor()
           dataset = cur.execute("SELECT cust_name, cust_pk FROM customer")
           results = cur.fetchall()
           
           rowPosition = 0
           for customers in results:
               self.contactsTable.insertRow(rowPosition)
               self.contactsTable.setItem(rowPosition,0,QtWidgets.QTableWidgetItem(customers[0]))
               self.contactsTable.setItem(rowPosition,1,QtWidgets.QTableWidgetItem(str(customers[1])))
               self.contactsTable.hideColumn(1)
               rowPosition = rowPosition+1
           self.contactsTable.itemSelectionChanged.connect(self.onSelectionContact)
           self.contactsTable.selectRow(0)

   if __name__ == "__main__":
       import sys
       app = QtWidgets.QApplication(sys.argv)
       MainWindow = QtWidgets.QMainWindow()
       ui = Ui_MainWindow()
       ui.setupUi(MainWindow)
       ui.fillContactList()
       MainWindow.show()
       sys.exit(app.exec())```
Irene
  • 49
  • 8
  • You're not using the `mainwindow` class you created. Remove the lines after the `app = ...` up to the last one, and replace them with `mainWindow = mainwindow()` `mainWindow.fillContactList()` and `mainWindow.show()`. Also, you should change the class to `MainWindow` (and change the above accordingly), as classes (as constants) should always have capitalized name. – musicamante Oct 20 '21 at 21:13

1 Answers1

0

First, You should rename mainwindow class to MainWindow. MainWindow need to be subclassed from QMainWindow only.

After creating Ui_MainWindow object, use its setupUi method to build your MainWindow object. All the widgets reference that you created in designer will be available as attributes of Ui_MainWindow object.

So, store it in main window as self.ui = Ui_MainWindow(). Build main window as self.ui.setupUi(self). Reference any widgets like self.ui.contactsTable

You need to create object of your MainWindow class, not QMainWindow

Try like this:

import sys
from PySide6.QtWidgets import QMainWindow, QApplication
from mainwindow import Ui_MainWindow


class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()
        self.setWindowTitle("Skills In Motion")
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.fillContactList()

    def fillContactList(self):
        # Reference Table like this
        # self.ui.contactsTable
        pass


if __name__ == '__main__':
    app = QApplication(sys.argv)
    mainWindow = MainWindow()
    mainWindow.show()
    sys.exit(app.exec_())
Rad
  • 113
  • 9
  • "MainWindow need to be subclassed from QMainWindow only". That's inaccurate. The multiple inheritance allows to use `self.setupUi(self)` and use the base instance also for direct reference of the UI, so you can directly use `self.someWidget` instead of `self.ui.someObject`: since the generated form class is a very simple python object, it won't create any naming conflict (as soon as you don't use "*wrong*" names for widgets which could potentially overwrite existing class functions, but if you choose names wisely, that would never happen). – musicamante Oct 21 '21 at 00:27
  • @musicamante Yes, I agree with you. I was actually giving explanation to the example i've given. Personally, I like this approach as it keeps the namespace separate. I should have mentioned it in the answer. Thanks for pointing that out – Rad Oct 21 '21 at 04:00
  • separating namespaces is not wrong per se, on the contrary, but we should also never forget practicality against strict (and rightful) programming patterns: good practices are not always *proper* practices. Having an `ui` object can provide better encapsulation, but has actually little benefit in coding: as long as the instance is a Qt widget, it makes sense that all of its child widgets are direct attributes of it; if we were to be more strict about hierarchy we should also have a hierarchy in names, but we know that it would have more drawbacks than benefits, especially -> – musicamante Oct 21 '21 at 04:15
  • -> considering that Qt objects can be reparented programmatically; since there's little benefit in having a granchild widget like `self.topFrame.leftGroup.topLeftButton`, the consequence is that also having `self.ui.topLeftButton` is not much better than directly being able to have a more readable and direct reference like `self.topLeftButton`. Also, since the base class is itself a widget (so, it's an UI related object), having a separate ui object won't make a lot of sense anyway. – musicamante Oct 21 '21 at 04:19