Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. How to connect child tableview to parent model?
QtWS25 Last Chance

How to connect child tableview to parent model?

Scheduled Pinned Locked Moved Solved Qt for Python
pyqt5tableview
6 Posts 3 Posters 673 Views
  • 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 Offline
    J Offline
    judethedude
    wrote on 21 Sept 2022, 12:56 last edited by judethedude
    #1

    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.

    J J 2 Replies Last reply 21 Sept 2022, 13:05
    0
    • J judethedude
      21 Sept 2022, 12:56

      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.

      J Offline
      J Offline
      jsulm
      Lifetime Qt Champion
      wrote on 21 Sept 2022, 13:05 last edited by
      #2

      @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
      3
      • J judethedude
        21 Sept 2022, 12:56

        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.

        J Offline
        J Offline
        JonB
        wrote on 21 Sept 2022, 13:09 last edited by JonB
        #3

        @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
        3
        • J Offline
          J Offline
          judethedude
          wrote on 21 Sept 2022, 13:17 last edited by judethedude
          #4

          @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.

          J 1 Reply Last reply 21 Sept 2022, 13:35
          0
          • J judethedude
            21 Sept 2022, 13:17

            @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.

            J Offline
            J Offline
            JonB
            wrote on 21 Sept 2022, 13:35 last edited by JonB
            #5

            @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 21 Sept 2022, 14:12
            2
            • J JonB
              21 Sept 2022, 13:35

              @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 Offline
              J Offline
              judethedude
              wrote on 21 Sept 2022, 14:12 last edited by
              #6

              @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
              0

              1/6

              21 Sept 2022, 12:56

              • Login

              • Login or register to search.
              1 out of 6
              • First post
                1/6
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • Users
              • Groups
              • Search
              • Get Qt Extensions
              • Unsolved