Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Call for Presentations - Qt World Summit

    Solved How to connect child tableview to parent model?

    Qt for Python
    pyqt5 tableview
    3
    6
    130
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • J
      judethedude last edited by judethedude

      Hey everyone,
      I'm building a PyQt5 application that will have several QWidget windows. Some of these windows will have different tableviews connected to the same source model so the user can view the data in different ways. Here is my minimum example:

      class MainWindow(QMainWindow):
          def __init__(self):
              super().__init__()
              self._ui = Ui_MainWindow()
              self._ui.setupUi(self)
      
              self._patient_search_model_source = models.PatientProfileModel() #QSqlRelationalTableModel
              self._patient_search_proxyModel = QSortFilterProxyModel()
              self._patient_search_proxyModel.setSourceModel(self._patient_search_model_source)
      
          def get_patient_search_proxyModel(self):
              return self._patient_search_proxyModel
      

      And the class for the ApptView (which is a stacked widget in MainWindow)

      class ApptView(QWidget):
          def __init__(self, parent):
              super().__init__(parent)
              self.appt_ui = Ui_appt_form()
              self.appt_ui.setupUi(self)
              self.appt_ui.patient_search_tableView.setModel(MainWindow.get_patient_search_proxyModel)
      

      However I get a compile error for the line self.appt_ui.patient_search_tableView.setModel(MainWindow.get_patient_search_proxyModel)
      "TypeError: setModel(self, QAbstractItemModel): argument 1 has unexpected type 'function'"

      I've tried passing in 'parent': self.appt_ui.patient_search_tableView.setModel(MainWindow.get_patient_search_proxyModel(parent))
      But that gives me the error of "AttributeError: 'MainWindow' object has no attribute '_patient_search_proxyModel'"

      I feel like I must be missing something fundamental here!
      Anyone have any suggestions?
      Thanks for your time, Jude

      EDIT: I should note, I probably could just make a new QSqlRelationalTable model for each seperate QWidget, but I thought that would be bad form.

      jsulm JonB 2 Replies Last reply Reply Quote 0
      • jsulm
        jsulm Lifetime Qt Champion @judethedude last edited by

        @judethedude You could simply pass the model as parameter to ApptView constructor...

        https://forum.qt.io/topic/113070/qt-code-of-conduct

        1 Reply Last reply Reply Quote 3
        • JonB
          JonB @judethedude last edited by JonB

          @judethedude said in How to connect child tableview to parent model?:

          self.appt_ui.patient_search_tableView.setModel(MainWindow.get_patient_search_proxyModel)

          get_patient_search_proxyModel is a function, but you omit the trailing parentheses (()).

          self.appt_ui.patient_search_tableView.setModel(MainWindow.get_patient_search_proxyModel(parent))
          "AttributeError: 'MainWindow' object has no attribute '_patient_search_proxyModel'"

          You must not pass parent from the caller as self. Or something like that, not quite sure, you pass a parent parameter to a method which does accept any parameters (other than the special self).

          In any case, you intend:

          self.appt_ui.patient_search_tableView.setModel(MainWindow.get_patient_search_proxyModel())
          

          Having said that, you are no better off, it won't work. You don't have the MainWindow instance in ApptView, so you can't (easily) access anything in the calling MainWindow anyway. And you should not be trying to do this.

          You could "cast" the parent parameter in ApptView to MainWndow. This should do what you were attemtping:

          self.appt_ui.patient_search_tableView.setModel(parent.get_patient_search_proxyModel())
          

          But it's really messy, you're taking advantage of Python's non-explicit types and you are trying to access the MainWindow instance through parent in ApptView which is not good code design.

          If you must access proxy model in ApptView, pass as parameter to constructor. [Oh, while I have been typing my helpful stuff I see @jsulm has just typed this curtly ;-)]

          class ApptView(QWidget):
              def __init__(self, proxyModel, parent):
                  super().__init__(parent)
                  self._proxy_model = proxyModel
          
          # when you create the `ApptView` in `MainWindow` stacked widget or wherever:
          # (but must come after `self._patient_search_proxyModel = QSortFilterProxyModel()`)
              self._apptView = ApptView(self._patient_search_proxyModel, self)
          
          1 Reply Last reply Reply Quote 3
          • J
            judethedude last edited by judethedude

            @jsulm @JonB Thanks for the solution gentlemen. And thanks for the explanation Jon. If you could expand a bit further, if my goal is multiple tableviews throughout my application, I should pass them as a parameter to each constructor? Instead of creating a new model for each tableview?
            Thanks again.

            EDIT: Also, if you had any recommended reading for program structure for PyQt that would be much appreciated. After your comment I feel I might not have structured my Widgets properly.

            JonB 1 Reply Last reply Reply Quote 0
            • JonB
              JonB @judethedude last edited by JonB

              @judethedude
              Let's separate out what models you have, what views you have and how you access the model(s).

              If you have only one model/data source and you want to view it from multiple places, you only one to create one model instance. Don't duplicate/create extra models if there is a single source of data.

              You can have multiple views onto the same individual model instance, that is no problem. You could have multiple views within, say, the same widget, or one view in each of several widgets, no matter.

              Views belong where they are shown to the user: in code for the widget they are shown in, or in their own modules. Views can know about the models they show (they have to), but models should not know about any views which might be attached to the model. If you choose to, say, put models and views in their own classes/modules, view modules should import the model class, but not vice versa. Don't let your model/data code include any view stuff or even be able to see it, this keeps the segregation clean.

              Now you need to be able to access the model from each view/widget. Some sort of singleton pattern is often good. In MainWindow you already have

              self._patient_search_model_source = models.PatientProfileModel() #QSqlRelationalTableModel
              

              So, depending on how you defined that, is models.... available to your view/widget modules too? Or, see how QSqlDatabase class handles (one or more) database(s) using QSqlDatabase.database() as a static method.

              On a final matter. You actually want the proxy model for your view. You create this via self._patient_search_proxyModel = QSortFilterProxyModel() in MainWindow. Why, why inside MainWindow? The ability to proxy does not seem to be a main window thing --- indeed, your ApptView code shows it is not. Depends on what you do and how you use it, but it might be better placed in the same models..., or similar, you are getting the _patient_search_model_source from? Or, if the sort-filter proxy is only for use in the view, it could just be in ApptView. Unless you want to share the same sorting/filtering across your various views.....

              J 1 Reply Last reply Reply Quote 2
              • J
                judethedude @JonB last edited by

                @JonB ok. I'm picking up what you're laying down. I went through my code and made sure my structure is actually following the patterns I've decided on. To answer your question, I do need access to both the proxy model and source model, but thanks for clarifying the distinction. Thank you for your time!

                1 Reply Last reply Reply Quote 0
                • First post
                  Last post