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 ?
Forum Updated to NodeBB v4.3 + New Features

How to implement findChildren() universally ?

Scheduled Pinned Locked Moved Solved Qt for Python
9 Posts 3 Posters 1.8k Views 1 Watching
  • 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 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

    JonBJ 1 Reply Last reply
    0
    • N NonNT

      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

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on 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 last edited by NonNT
        #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
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on 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 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 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.

              JonBJ 1 Reply Last reply
              0
              • N NonNT

                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.

                JonBJ Offline
                JonBJ Offline
                JonB
                wrote on 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 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

                  JonBJ 1 Reply Last reply
                  0
                  • N NonNT

                    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

                    JonBJ Offline
                    JonBJ Offline
                    JonB
                    wrote on 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

                    • Login

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