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 implement findChildren() universally ?
QtWS25 Last Chance

How to implement findChildren() universally ?

Scheduled Pinned Locked Moved Solved Qt for Python
9 Posts 3 Posters 1.7k 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.
  • N Offline
    N Offline
    NonNT
    wrote on 6 Sept 2020, 09:39 last edited by
    #1

    Hey!

    MainWindow imports Dialog which imports CustomWidget

    In CustomWidget the MainWindow is the grandparent:

    actions = self.parentWidget().parentWidget().findChildren(QAction)
    

    MainWindow imports CustomWidget

    In CustomWidget the MainWindow is the parent:

    actions = self.parentWidget().findChildren(QAction)
    

    How to implement findChildren() so that it works in both cases?

    Thanks

    J 1 Reply Last reply 6 Sept 2020, 09:54
    0
    • N NonNT
      6 Sept 2020, 09:39

      Hey!

      MainWindow imports Dialog which imports CustomWidget

      In CustomWidget the MainWindow is the grandparent:

      actions = self.parentWidget().parentWidget().findChildren(QAction)
      

      MainWindow imports CustomWidget

      In CustomWidget the MainWindow is the parent:

      actions = self.parentWidget().findChildren(QAction)
      

      How to implement findChildren() so that it works in both cases?

      Thanks

      J Offline
      J Offline
      JonB
      wrote on 6 Sept 2020, 09:54 last edited by
      #2

      @NonNT
      There i something wrong here. Either something is a parent or a grandparent or whatever, but what you import makes no difference either way. Parentage is to do with how widgets are added where, not by what is imported.

      Having said that: there is (almost certainly) something wrong with your logic if from within a child/custom widget you are reaching up to its parent/grandparent and doing something there, like looking for children. Essentially widgets should not need to know anything about their parent; they may look at their own children, but should no be relying on their parent being anything in particular. Urge you to reconsider your approach, before your code turns into a spaghetti-mess!

      1 Reply Last reply
      3
      • N Offline
        N Offline
        NonNT
        wrote on 6 Sept 2020, 12:11 last edited by NonNT 9 Jun 2020, 12:31
        #3

        main.py

        # This Python file uses the following encoding: utf-8
        
        import sys
        from PySide2.QtWidgets import QApplication
        
        from main_window import MainWindow
        
        
        if __name__ == "__main__":
        
            app = QApplication(sys.argv)
            app.setOrganizationName('pyTest')
            app.setApplicationName('Keyboard Shortcuts')
            app.setApplicationDisplayName('Keyboard Shortcuts')
        
            window = MainWindow()
            window.show()
        
            sys.exit(app.exec_())
        

        main_window.py

        # This Python file uses the following encoding: utf-8
        
        import sys
        
        from PySide2.QtCore import Qt
        from PySide2.QtGui import QIcon, QKeySequence
        from PySide2.QtWidgets import QAction, QApplication, QMainWindow, QMenu
        
        from keyboard_shortcuts_dialog import KeyboardShortcutsDialog
        from keyboard_shortcuts_table import KeyboardShortcutsTable
        
        
        class MainWindow(QMainWindow):
        
            def __init__(self):
                QMainWindow.__init__(self)
        
                self.resize(QApplication.desktop().availableGeometry(self).width() / 2, QApplication.desktop().availableGeometry(self).height() / 2);
                self.move((QApplication.desktop().availableGeometry(self).width() - self.width()) / 2, (QApplication.desktop().availableGeometry(self).height() - self.height()) / 2);
        
                actionQuit = QAction('Quit', self)
                actionQuit.setIcon(QIcon.fromTheme('application-exit'))
                actionQuit.setShortcut(QKeySequence.Quit)
                actionQuit.setToolTip('Quit the application')
                actionQuit.triggered.connect(self.close)
        
                actionKeyboardShortcuts = QAction('Keyboard Shortcuts', self)
                actionKeyboardShortcuts.setIcon(QIcon.fromTheme('help-keybord-shortcuts'))
                actionKeyboardShortcuts.triggered.connect(self.onActionKeyboardShortcutsTriggered)
        
                menu = self.menuBar().addMenu('Application')
                menu.addAction(actionKeyboardShortcuts)
                menu.addSeparator()
                menu.addAction(actionQuit)
        
                # Main widget
                self.setCentralWidget(KeyboardShortcutsTable(self))
        
        
            def onActionKeyboardShortcutsTriggered(self):
        
                dialog = KeyboardShortcutsDialog(self)
                dialog.setWindowTitle('Keyboard Shortcuts')
                dialog.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
                dialog.show()
        

        keyboard_shortcuts_dialog.py

        # This Python file uses the following encoding: utf-8
        
        from PySide2.QtWidgets import QApplication, QDialog, QDialogButtonBox, QVBoxLayout
        
        from keyboard_shortcuts_table import KeyboardShortcutsTable
        
        
        class KeyboardShortcutsDialog(QDialog):
        
            def __init__(self, parent=None):
                super(KeyboardShortcutsDialog, self).__init__(parent)
        
                self.resize(QApplication.desktop().availableGeometry(self).width() / 3, QApplication.desktop().availableGeometry(self).height() / 3);
                self.move((QApplication.desktop().availableGeometry(self).width() - self.width()) / 2, (QApplication.desktop().availableGeometry(self).height() - self.height()) / 2);
        
                buttonBox = QDialogButtonBox(QDialogButtonBox.Close)
                buttonBox.rejected.connect(self.close)
        
                # Main layout
                layout = QVBoxLayout()
                layout.addWidget(KeyboardShortcutsTable(self), 1)
                layout.addWidget(buttonBox)
        
                self.setLayout(layout)
        

        keyboard_shortcuts_table.py

        # This Python file uses the following encoding: utf-8
        
        from PySide2.QtCore import Qt
        from PySide2.QtGui import QKeySequence
        from PySide2.QtWidgets import QAction, QMainWindow, QTableWidget, QTableWidgetItem, QVBoxLayout, QWidget
        
        
        class KeyboardShortcutsTable(QWidget):
        
            def __init__(self, parent=None):
                super(KeyboardShortcutsTable, self).__init__(parent)
        
                labels = ['Name', 'Shortcut', 'Description']
        
                shortcutItems = []
        
                # Only works if MainWindow is parent
                actionItems = self.parentWidget().findChildren(QAction)
        
                # Only works if MainWindow is grandparent
                #actionItems = self.parentWidget().parentWidget().findChildren(QAction)
        
                for actionItem in actionItems:
                    if not actionItem.shortcut().isEmpty():
                        shortcutItems.append(actionItem)
        
                tableBox = QTableWidget(len(shortcutItems), len(labels), self)
                tableBox.setHorizontalHeaderLabels(labels);
                tableBox.horizontalHeader().setDefaultAlignment(Qt.AlignLeft)
                tableBox.horizontalHeader().setStretchLastSection(True)
                tableBox.verticalHeader().setVisible(False)
        
                row = 0
                for shortcutItem in shortcutItems:
                    tableBox.setItem(row, 0, QTableWidgetItem(shortcutItem.text()))
                    tableBox.setItem(row, 1, QTableWidgetItem(shortcutItem.shortcut().toString(QKeySequence.NativeText)))
                    tableBox.setItem(row, 2, QTableWidgetItem(shortcutItem.toolTip()))
                    row += 1
        
                # Main layout
                layout = QVBoxLayout()
                layout.addWidget(tableBox, 1)
        
                self.setLayout(layout)
        

        <--->

                # Only works if MainWindow is parent
                actionItems = self.parentWidget().findChildren(QAction)
        
                # Only works if MainWindow is grandparent
                #actionItems = self.parentWidget().parentWidget().findChildren(QAction)
        

        So how can this be done universally?

        1 Reply Last reply
        0
        • S Offline
          S Offline
          SGaist
          Lifetime Qt Champion
          wrote on 6 Sept 2020, 17:50 last edited by
          #4

          Hi,

          Are you trying to implement some sort of action editor ?

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply
          0
          • N Offline
            N Offline
            NonNT
            wrote on 6 Sept 2020, 21:05 last edited by
            #5

            No, it is just a simple text editor. I want to list all available Keyboard Shortcuts in a dialog.
            But I want to write KeyboardShortcutsTable so that I can use it elsewhere.

            keyboard-shortcuts-dialog.png

            1 Reply Last reply
            0
            • N Offline
              N Offline
              NonNT
              wrote on 6 Sept 2020, 21:23 last edited by
              #6

              I have changed it like this:

              class KeyboardShortcutsTable(QWidget):
                  def __init__(self, mainWindowWidget, parent=None):
                      ...
                      actionItems = mainWindowWidget.findChildren(QAction)
                      ...
              
              class KeyboardShortcutsDialog(QDialog):
                  ...
                  layout.addWidget(KeyboardShortcutsTable(self.parentWidget()), 1)
                  ...
              

              It works, but I am not sure if it is the best solution.

              J 1 Reply Last reply 7 Sept 2020, 09:36
              0
              • N NonNT
                6 Sept 2020, 21:23

                I have changed it like this:

                class KeyboardShortcutsTable(QWidget):
                    def __init__(self, mainWindowWidget, parent=None):
                        ...
                        actionItems = mainWindowWidget.findChildren(QAction)
                        ...
                
                class KeyboardShortcutsDialog(QDialog):
                    ...
                    layout.addWidget(KeyboardShortcutsTable(self.parentWidget()), 1)
                    ...
                

                It works, but I am not sure if it is the best solution.

                J Offline
                J Offline
                JonB
                wrote on 7 Sept 2020, 09:36 last edited by
                #7

                @NonNT
                This means that KeyboardShortcutsDialog is tied to showing the QActions of whatever its parent widget is. Which is not bad, but if you're asking me I would remove that dependency.

                You are already passing the desired widget as a parameter to your KeyboardShortcutsTable, which is good. Why not take it a step further, and pass it as a parameter to KeyboardShortcutsDialog, which in turn can pass it on to KeyboardShortcutsTable? Do you require KeyboardShortcutsDialog to only be able to show the shortcuts of its own parent widget, rather than of any widget passed to it?

                class MainWindow(QMainWindow):
                    def onActionKeyboardShortcutsTriggered(self):
                        dialog = KeyboardShortcutsDialog(self, self)
                
                
                class KeyboardShortcutsDialog(QDialog):
                    def __init__(self, actionsWidget, parent=None):
                        ...
                        self.actionsWidget = actionsWidget
                        ...
                        layout.addWidget(KeyboardShortcutsTable(self.actionsWidget), 1)
                        ...
                
                
                class KeyboardShortcutsTable(QWidget):
                    def __init__(self, actionsWidget, parent=None):
                        ...
                        actionItems = actionsWidget.findChildren(QAction)
                        ...
                

                No parenting-dependencies here! I might pass actionsWidget.findChildren(QAction) as the parameter, receiving a list of QActions instead of a QWidget, depending on whether I really need to access the widget rather than just its actions.

                1 Reply Last reply
                0
                • N Offline
                  N Offline
                  NonNT
                  wrote on 8 Sept 2020, 11:25 last edited by
                  #8

                  KeyboardShortcutsTable is tied to the parent widget.
                  I thought that you could call the findChildren(QAction) or something similar in KeyboardShortcutsTable to get the list of actions without passing the MainWindow widget.
                  But it works now. Thanks

                  J 1 Reply Last reply 8 Sept 2020, 12:13
                  0
                  • N NonNT
                    8 Sept 2020, 11:25

                    KeyboardShortcutsTable is tied to the parent widget.
                    I thought that you could call the findChildren(QAction) or something similar in KeyboardShortcutsTable to get the list of actions without passing the MainWindow widget.
                    But it works now. Thanks

                    J Offline
                    J Offline
                    JonB
                    wrote on 8 Sept 2020, 12:13 last edited by
                    #9

                    @NonNT
                    Well you can if you specify the correct parentage. If you are inside KeyboardShortcutsTable you presumably have to go up to its KeyboardShortcutsDialog, and then from there up to the MainWindow.

                    But I think its preferable to pass the MainWindow widget explicitly, then your table is not tied to where it happens to be situated/called from.

                    1 Reply Last reply
                    0

                    7/9

                    7 Sept 2020, 09:36

                    • Login

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