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. add a search bar that could locate an element in one of the QTreeViews

add a search bar that could locate an element in one of the QTreeViews

Scheduled Pinned Locked Moved Solved Qt for Python
8 Posts 2 Posters 504 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.
  • S Offline
    S Offline
    sof4Rou
    wrote on last edited by
    #1

    I have several tree views in a scroll area. When I search for a word I want that it directs me to this word. So I want a search that automatically scrolls to the item I'm looking for, even if it's further down.

    this is my code :

    from PyQt5.QtWidgets import *
    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    from table_view import *
    from odl_parser import ODLParser
    
    class StartWindow(QDialog):
        def __init__(self, parent=None):
            super().__init__(parent)
            self.setWindowTitle('Open ODL File or Folder')
            self.resize(600, 400) 
    
            main_layout = QHBoxLayout(self)
    
            self.image_label = QLabel(self)
            self.image_label.setPixmap(QPixmap('ACLViewer.jpg').scaled(300, 300, Qt.KeepAspectRatio))
            main_layout.addWidget(self.image_label)
    
            buttons_layout = QVBoxLayout()
    
            self.choose_file_button = QPushButton('Choose File', self)
            self.choose_file_button.clicked.connect(self.choose_file)
            buttons_layout.addWidget(self.choose_file_button)
            
            self.choose_folder_button = QPushButton('Choose Folder', self)
            self.choose_folder_button.clicked.connect(self.choose_folder)
            buttons_layout.addWidget(self.choose_folder_button)
    
            main_layout.addLayout(buttons_layout)
            self.first_tree_configured = False
    
        def choose_file(self):
            file_path, _ = QFileDialog.getOpenFileName(self, "Open ODL File", "", "ODL Files (*.odl)")
            if file_path:
                self.open_table_view(file_path)
    
        def choose_folder(self):
            folder_path = QFileDialog.getExistingDirectory(self, "Open Folder Containing ODL Files")
            if folder_path:
                self.open_folder_view(folder_path)
    
        def open_table_view(self, file_path):
            parser = ODLParser(file_path)
            window = Table(parser)
            window.setWindowTitle('DM Parsing - ' + file_path)
            window.show()
    
        def open_folder_view(self, folder_path):
            folder_window = QDialog(self)
            folder_window.setWindowTitle('ODL Files Tree View')
            folder_window.resize(800, 600)
    
            layout = QVBoxLayout(folder_window)
    
            self.group_combobox = QComboBox()
            self.group_combobox.setStyleSheet(""" border: 1px solid gray;
            border-radius: 3px;
            padding: 1px 18px 1px 3px;
            min-width: 6em; """)
            self.group_combobox.setMaximumWidth(340)
            layout.addWidget(self.group_combobox)
            self.tables = []
    
            self.save_button = QPushButton("Save", folder_window)
            self.save_button.setStyleSheet(""" border: 2px solid #8f8f91;
            border-radius: 6px;
            background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
                                            stop: 0 #f6f7fa, stop: 1 #dadbde);
            min-width: 80px; """)
            #self.save_button.clicked.connect(self.save_acl_changes)
            
            self.reset_button = QPushButton("Reset", folder_window)
            self.reset_button.setStyleSheet(""" border: 2px solid #8f8f91;
            border-radius: 6px;
            background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
                                            stop: 0 #f6f7fa, stop: 1 #dadbde);
            min-width: 80px; """)
            self.reset_button.clicked.connect(self.reset_acl_changes)
    
            buttons_layout = QHBoxLayout()
            buttons_layout.addWidget(self.group_combobox)
            buttons_layout.addWidget(self.save_button)
            buttons_layout.addWidget(self.reset_button)
    
            self.search_bar = QLineEdit()
            self.search_bar.setStyleSheet(""" border: 2px solid gray;
            border-radius: 5px;
            padding: 0 8px;
            background: lightblue;
            selection-background-color: gray; """)
            self.search_bar.setPlaceholderText("Search...")
            layout.addWidget(self.search_bar)
            self.search_bar.textChanged.connect(self.**search_tree**)
    
            layout.addLayout(buttons_layout)
    
            scroll_area = QScrollArea(folder_window)
            scroll_area.setWidgetResizable(True)
    
            scroll_widget = QWidget()
            scroll_layout = QVBoxLayout(scroll_widget)
    
            import os
            processed_files = set() 
            all_groups = set()
            for root, dirs, files in os.walk(folder_path):
                for filename in files:
                    if ('acl' in filename.lower() or 'acls' in filename.lower()) and filename not in processed_files:
                        file_path = os.path.join(root, filename)
                        parser = ODLParser(file_path)
                        file_groups, _ = get_headers_and_rights(parser.data_model)
                        all_groups.update(file_groups)
                        tree_view = self.create_tree_view(parser)
                        scroll_layout.addWidget(tree_view)
                        processed_files.add(filename)
                        
            self.group_combobox.addItems(sorted(all_groups))
            self.group_combobox.setCurrentIndex(0) 
            self.group_combobox.currentTextChanged.connect(self.on_group_combobox_changed)
            QTimer.singleShot(0, lambda: self.on_group_combobox_changed(self.group_combobox.currentText()))
            scroll_area.setWidget(scroll_widget)
            layout.addWidget(scroll_area)
    
            folder_window.exec_()
    
        def reset_acl_changes(self):
            selected_group = self.group_combobox.currentText()
            for table in self.tables:
                table.reset_acl_changes(selected_group)
                table.tree.expandAll()
    
        def **search_tree**(self, text):
            for table in self.tables:
                found_items = table.tree.model().findItems(text, Qt.MatchContains | Qt.MatchRecursive)
                for item in found_items:
                    index = table.tree.model().indexFromItem(item)
                    table.tree.expand(index)
                    table.tree.scrollTo(index)
                    table.tree.setCurrentIndex(index)
        
        def on_group_combobox_changed(self, selected_group):
            for table in self.tables:
                table.update_access_rights(selected_group)
                table.tree.expandAll()
    
        def create_tree_view(self, parser):
            window = Table(parser)
            tree_view = window.tree
            window.is_first_tree = not self.first_tree_configured
            if not self.first_tree_configured:
                self.configure_tree_view(tree_view)
                self.first_tree_configured = True
            else:
                self.configure_tree_view2(tree_view)
                
            tree_view.expandAll()
            height = 0
            for i in range(tree_view.model().rowCount()):
                index = tree_view.model().index(i, 0)
                height += tree_view.rowHeight(index) * self.count_visible_nodes(index)
            height += tree_view.header().height()
            tree_view.setFixedHeight(height)
            self.tables.append(window)
            
            return tree_view
        
        def configure_tree_view(self, tree_view):
            tree_view.setColumnWidth(0, 430) 
            tree_view.setColumnWidth(1, 100) 
            tree_view.header().setStretchLastSection(True)
    
        def configure_tree_view2(self, tree_view):
            self.configure_tree_view(tree_view)
            tree_view.header().hide()
    
    
        def count_visible_nodes(self, index, model=None):
            if not index.isValid():
                return 0
            if model is None:
                model = index.model()
            count = 1 
            if index.model().hasChildren(index):
                for row in range(model.rowCount(index)):
                    child_index = model.index(row, 0, index)
                    count += self.count_visible_nodes(child_index, model)
            return count
    

    I've tried the search_tree function but it didn't direct me to the word I'm looking for.

    Can any one help me ?

    JonBJ 1 Reply Last reply
    0
    • S sof4Rou

      @JonB I have other treeviews above, the word I gave you exists in the last treeview, that's why I want to make a function that shows me the place of the word that I searched

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #7

      @sof4Rou
      I don't understand. If you are talking about scrolling within one treeview which contains a word your code should work and the item is shown in that treeview in your screenshot. If you are talking about needing to scroll the multiple treeviews to get to one containing the word that is a totally different scroll on a different object and I don't know if that is what you mean. If that is the case you need to scroll your desired widget into view in whatever the enclosing scroll area is.

      QScrollArea::ensureWidgetVisible(QWidget *childWidget, int xmargin = 50, int ymargin = 50), is that what you asking about?

      S 1 Reply Last reply
      2
      • S sof4Rou

        I have several tree views in a scroll area. When I search for a word I want that it directs me to this word. So I want a search that automatically scrolls to the item I'm looking for, even if it's further down.

        this is my code :

        from PyQt5.QtWidgets import *
        from PyQt5.QtCore import *
        from PyQt5.QtGui import *
        from table_view import *
        from odl_parser import ODLParser
        
        class StartWindow(QDialog):
            def __init__(self, parent=None):
                super().__init__(parent)
                self.setWindowTitle('Open ODL File or Folder')
                self.resize(600, 400) 
        
                main_layout = QHBoxLayout(self)
        
                self.image_label = QLabel(self)
                self.image_label.setPixmap(QPixmap('ACLViewer.jpg').scaled(300, 300, Qt.KeepAspectRatio))
                main_layout.addWidget(self.image_label)
        
                buttons_layout = QVBoxLayout()
        
                self.choose_file_button = QPushButton('Choose File', self)
                self.choose_file_button.clicked.connect(self.choose_file)
                buttons_layout.addWidget(self.choose_file_button)
                
                self.choose_folder_button = QPushButton('Choose Folder', self)
                self.choose_folder_button.clicked.connect(self.choose_folder)
                buttons_layout.addWidget(self.choose_folder_button)
        
                main_layout.addLayout(buttons_layout)
                self.first_tree_configured = False
        
            def choose_file(self):
                file_path, _ = QFileDialog.getOpenFileName(self, "Open ODL File", "", "ODL Files (*.odl)")
                if file_path:
                    self.open_table_view(file_path)
        
            def choose_folder(self):
                folder_path = QFileDialog.getExistingDirectory(self, "Open Folder Containing ODL Files")
                if folder_path:
                    self.open_folder_view(folder_path)
        
            def open_table_view(self, file_path):
                parser = ODLParser(file_path)
                window = Table(parser)
                window.setWindowTitle('DM Parsing - ' + file_path)
                window.show()
        
            def open_folder_view(self, folder_path):
                folder_window = QDialog(self)
                folder_window.setWindowTitle('ODL Files Tree View')
                folder_window.resize(800, 600)
        
                layout = QVBoxLayout(folder_window)
        
                self.group_combobox = QComboBox()
                self.group_combobox.setStyleSheet(""" border: 1px solid gray;
                border-radius: 3px;
                padding: 1px 18px 1px 3px;
                min-width: 6em; """)
                self.group_combobox.setMaximumWidth(340)
                layout.addWidget(self.group_combobox)
                self.tables = []
        
                self.save_button = QPushButton("Save", folder_window)
                self.save_button.setStyleSheet(""" border: 2px solid #8f8f91;
                border-radius: 6px;
                background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
                                                stop: 0 #f6f7fa, stop: 1 #dadbde);
                min-width: 80px; """)
                #self.save_button.clicked.connect(self.save_acl_changes)
                
                self.reset_button = QPushButton("Reset", folder_window)
                self.reset_button.setStyleSheet(""" border: 2px solid #8f8f91;
                border-radius: 6px;
                background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
                                                stop: 0 #f6f7fa, stop: 1 #dadbde);
                min-width: 80px; """)
                self.reset_button.clicked.connect(self.reset_acl_changes)
        
                buttons_layout = QHBoxLayout()
                buttons_layout.addWidget(self.group_combobox)
                buttons_layout.addWidget(self.save_button)
                buttons_layout.addWidget(self.reset_button)
        
                self.search_bar = QLineEdit()
                self.search_bar.setStyleSheet(""" border: 2px solid gray;
                border-radius: 5px;
                padding: 0 8px;
                background: lightblue;
                selection-background-color: gray; """)
                self.search_bar.setPlaceholderText("Search...")
                layout.addWidget(self.search_bar)
                self.search_bar.textChanged.connect(self.**search_tree**)
        
                layout.addLayout(buttons_layout)
        
                scroll_area = QScrollArea(folder_window)
                scroll_area.setWidgetResizable(True)
        
                scroll_widget = QWidget()
                scroll_layout = QVBoxLayout(scroll_widget)
        
                import os
                processed_files = set() 
                all_groups = set()
                for root, dirs, files in os.walk(folder_path):
                    for filename in files:
                        if ('acl' in filename.lower() or 'acls' in filename.lower()) and filename not in processed_files:
                            file_path = os.path.join(root, filename)
                            parser = ODLParser(file_path)
                            file_groups, _ = get_headers_and_rights(parser.data_model)
                            all_groups.update(file_groups)
                            tree_view = self.create_tree_view(parser)
                            scroll_layout.addWidget(tree_view)
                            processed_files.add(filename)
                            
                self.group_combobox.addItems(sorted(all_groups))
                self.group_combobox.setCurrentIndex(0) 
                self.group_combobox.currentTextChanged.connect(self.on_group_combobox_changed)
                QTimer.singleShot(0, lambda: self.on_group_combobox_changed(self.group_combobox.currentText()))
                scroll_area.setWidget(scroll_widget)
                layout.addWidget(scroll_area)
        
                folder_window.exec_()
        
            def reset_acl_changes(self):
                selected_group = self.group_combobox.currentText()
                for table in self.tables:
                    table.reset_acl_changes(selected_group)
                    table.tree.expandAll()
        
            def **search_tree**(self, text):
                for table in self.tables:
                    found_items = table.tree.model().findItems(text, Qt.MatchContains | Qt.MatchRecursive)
                    for item in found_items:
                        index = table.tree.model().indexFromItem(item)
                        table.tree.expand(index)
                        table.tree.scrollTo(index)
                        table.tree.setCurrentIndex(index)
            
            def on_group_combobox_changed(self, selected_group):
                for table in self.tables:
                    table.update_access_rights(selected_group)
                    table.tree.expandAll()
        
            def create_tree_view(self, parser):
                window = Table(parser)
                tree_view = window.tree
                window.is_first_tree = not self.first_tree_configured
                if not self.first_tree_configured:
                    self.configure_tree_view(tree_view)
                    self.first_tree_configured = True
                else:
                    self.configure_tree_view2(tree_view)
                    
                tree_view.expandAll()
                height = 0
                for i in range(tree_view.model().rowCount()):
                    index = tree_view.model().index(i, 0)
                    height += tree_view.rowHeight(index) * self.count_visible_nodes(index)
                height += tree_view.header().height()
                tree_view.setFixedHeight(height)
                self.tables.append(window)
                
                return tree_view
            
            def configure_tree_view(self, tree_view):
                tree_view.setColumnWidth(0, 430) 
                tree_view.setColumnWidth(1, 100) 
                tree_view.header().setStretchLastSection(True)
        
            def configure_tree_view2(self, tree_view):
                self.configure_tree_view(tree_view)
                tree_view.header().hide()
        
        
            def count_visible_nodes(self, index, model=None):
                if not index.isValid():
                    return 0
                if model is None:
                    model = index.model()
                count = 1 
                if index.model().hasChildren(index):
                    for row in range(model.rowCount(index)):
                        child_index = model.index(row, 0, index)
                        count += self.count_visible_nodes(child_index, model)
                return count
        

        I've tried the search_tree function but it didn't direct me to the word I'm looking for.

        Can any one help me ?

        JonBJ Offline
        JonBJ Offline
        JonB
        wrote on last edited by
        #2

        @sof4Rou said in add a search bar that could locate an element in one of the QTreeViews:

        but it didn't direct me to the word I'm looking for.

        What did it do? Anything? Nothing? Were any matching items found? Did it not scroll to the last occurrence of the string?

        If you don't get an answer I suggest you provide a minimal (i.e. much, much smaller than this), self-contained sample.

        S 2 Replies Last reply
        0
        • JonBJ JonB

          @sof4Rou said in add a search bar that could locate an element in one of the QTreeViews:

          but it didn't direct me to the word I'm looking for.

          What did it do? Anything? Nothing? Were any matching items found? Did it not scroll to the last occurrence of the string?

          If you don't get an answer I suggest you provide a minimal (i.e. much, much smaller than this), self-contained sample.

          S Offline
          S Offline
          sof4Rou
          wrote on last edited by
          #3

          @JonB sorry, I mean when I search for a word using the search bar, it doesn't show me its place in the treeView

          1 Reply Last reply
          0
          • JonBJ JonB

            @sof4Rou said in add a search bar that could locate an element in one of the QTreeViews:

            but it didn't direct me to the word I'm looking for.

            What did it do? Anything? Nothing? Were any matching items found? Did it not scroll to the last occurrence of the string?

            If you don't get an answer I suggest you provide a minimal (i.e. much, much smaller than this), self-contained sample.

            S Offline
            S Offline
            sof4Rou
            wrote on last edited by
            #4

            @JonB 12.PNG
            for example here, when I search for the item "sah" , the scroll area does not go down and show me the word

            JonBJ 1 Reply Last reply
            0
            • S sof4Rou

              @JonB 12.PNG
              for example here, when I search for the item "sah" , the scroll area does not go down and show me the word

              JonBJ Offline
              JonBJ Offline
              JonB
              wrote on last edited by JonB
              #5

              @sof4Rou
              That word is at the top of the treeview, so I don't see there is anything to "scroll to", and your screenshot looks fine, it is showing you the word.

              In any case: get rid of all your code. Create a single QTreeView with a model. The only part of your code you are asking about is

                              table.tree.expand(index)
                              table.tree.scrollTo(index)
                              table.tree.setCurrentIndex(index)
              

              So test that behaviour on increasing row number in index to make sure it scrolls as you want. Then add any "searching" back in.

              S 1 Reply Last reply
              0
              • JonBJ JonB

                @sof4Rou
                That word is at the top of the treeview, so I don't see there is anything to "scroll to", and your screenshot looks fine, it is showing you the word.

                In any case: get rid of all your code. Create a single QTreeView with a model. The only part of your code you are asking about is

                                table.tree.expand(index)
                                table.tree.scrollTo(index)
                                table.tree.setCurrentIndex(index)
                

                So test that behaviour on increasing row number in index to make sure it scrolls as you want. Then add any "searching" back in.

                S Offline
                S Offline
                sof4Rou
                wrote on last edited by
                #6

                @JonB I have other treeviews above, the word I gave you exists in the last treeview, that's why I want to make a function that shows me the place of the word that I searched

                JonBJ 1 Reply Last reply
                0
                • S sof4Rou

                  @JonB I have other treeviews above, the word I gave you exists in the last treeview, that's why I want to make a function that shows me the place of the word that I searched

                  JonBJ Offline
                  JonBJ Offline
                  JonB
                  wrote on last edited by JonB
                  #7

                  @sof4Rou
                  I don't understand. If you are talking about scrolling within one treeview which contains a word your code should work and the item is shown in that treeview in your screenshot. If you are talking about needing to scroll the multiple treeviews to get to one containing the word that is a totally different scroll on a different object and I don't know if that is what you mean. If that is the case you need to scroll your desired widget into view in whatever the enclosing scroll area is.

                  QScrollArea::ensureWidgetVisible(QWidget *childWidget, int xmargin = 50, int ymargin = 50), is that what you asking about?

                  S 1 Reply Last reply
                  2
                  • SGaistS SGaist moved this topic from General and Desktop on
                  • S sof4Rou has marked this topic as solved on
                  • JonBJ JonB

                    @sof4Rou
                    I don't understand. If you are talking about scrolling within one treeview which contains a word your code should work and the item is shown in that treeview in your screenshot. If you are talking about needing to scroll the multiple treeviews to get to one containing the word that is a totally different scroll on a different object and I don't know if that is what you mean. If that is the case you need to scroll your desired widget into view in whatever the enclosing scroll area is.

                    QScrollArea::ensureWidgetVisible(QWidget *childWidget, int xmargin = 50, int ymargin = 50), is that what you asking about?

                    S Offline
                    S Offline
                    sof4Rou
                    wrote on last edited by
                    #8

                    @JonB Yes, your idea is true thank you very much

                    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