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. Way to save QTextEdit scroll state?
Forum Updated to NodeBB v4.3 + New Features

Way to save QTextEdit scroll state?

Scheduled Pinned Locked Moved Solved Qt for Python
10 Posts 3 Posters 1.1k 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.
  • R Offline
    R Offline
    Rivridis
    wrote on last edited by
    #1

    Is there any way the scroll state of QTextEdit be saved to a local file or within code itself? I tried taking scrollbar position, but it gets reset while switching between files. I set up a QTextEdit to load a EPUB file's content when a element in QTreeview is doubleclicked. It works once and stops working after a while.
    Or, is there any alternate way to load EPUB files that will make it easier?

    from PySide6.QtWidgets import QApplication, QDialog, QVBoxLayout,QMessageBox,QLineEdit,QPushButton,QMainWindow,QSplashScreen,QFileDialog,QTreeView,QFileSystemModel,QTextBrowser,QTextEdit
    from PySide6.QtGui import QPixmap,QTextCharFormat,QFont,QTextCursor,QColor
    from PySide6.QtCore import Qt
    from PySide6.QtUiTools import QUiLoader
    import sys
    from ebooklib import epub
    from bs4 import BeautifulSoup
    import qdarktheme
    import hashlib
    import time
    scroll_positions = {}
    qss = """
            QScrollBar::sub-page:horizontal {
            background: rgba(255, 255, 255, 0)
        }
    
        QScrollBar::add-page:horizontal {
            background: rgba(255, 255, 255, 0)
        }
        QScrollBar::sub-page:vertical {
            background: rgba(255, 255, 255, 0)
        }
    
        QScrollBar::add-page:vertical {
            background: rgba(255, 255, 255, 0)
        }
        QScrollBar::handle
        {
            background : rgba(138,124,171,1);
            min-height: 40px;
        }
        QScrollBar::handle:vertical
        {
            background : rgba(138,124,171,1);
            min-height: 40px;
        }
        QScrollBar::handle::pressed
        {
        background : rgba(138,124,171,1); 
        }
        QScrollBar::handle::hover
        {
        background : rgba(138,124,171,1);
        }
        QScrollBar::add-line,
        QScrollBar::sub-line {
            width: 0;
            subcontrol-position: right;
            subcontrol-origin: margin;
        }
    
    
        """
    
    def show_splash_screen():
        splash_pix = QPixmap('assets\splash.jpg')
        splash_pix = splash_pix.scaled(550, 450, Qt.KeepAspectRatio,Qt.SmoothTransformation)
        splash = QSplashScreen(splash_pix, Qt.WindowStaysOnTopHint)
        splash.setMask(splash_pix.mask())
        splash.show()
    
        return splash
    
    def main():
        app = QApplication(sys.argv)
        qdarktheme.setup_theme(additional_qss=qss,custom_colors={
            "[dark]": {
                "primary": "#D0BCFF",
                "border": "#00000000",
                "treeSectionHeader.background":"#8a7cab"
            }
        })
    
        # Create and show splash screen
        splash = show_splash_screen()
        main_window = Main()
        splash.close()
    
        main_window.children()[1].show()
    
        sys.exit(app.exec())
    
    class Main(QMainWindow):
        def __init__(self):
            super().__init__()
            self.current_file_hash = None
            loader = QUiLoader()
            ui_file = "assets/main.ui" 
            ui = loader.load(ui_file, self)
    
            self.directory = ui.findChild(QPushButton,"direct")
            self.directory.clicked.connect(self.dirpop)
    
            self.tree = ui.findChild(QTreeView,"tree") 
    
            self.model = QFileSystemModel()
            self.model.setRootPath("/")
            self.tree.setModel(self.model)
            self.tree.setRootIndex(self.model.index("/"))
    
            self.tree.doubleClicked.connect(self.choose)
    
            self.text = ui.findChild(QTextEdit,'text')
            self.text.setReadOnly(True)
            self.scroll_bar = self.text.verticalScrollBar()
    
    
        def dirpop(self):
            options = QFileDialog.Options()
            directory = QFileDialog.getExistingDirectory(self, "Select Directory", "", options=options)
    
            if directory:
                self.tree.setRootIndex(self.model.index(directory))
        
        def generate_file_hash(self, content):
            sha256 = hashlib.sha256()
            sha256.update(content.encode('utf-8'))
            return sha256.hexdigest()
        
        def choose(self, index):
            file_path = self.model.filePath(index)
            if ".epub" in file_path:
                # Save the current scroll position
                if self.current_file_hash:
                    scroll_positions[self.current_file_hash] = self.text.verticalScrollBar().value()
    
                book = epub.read_epub(file_path)
                content = ""
                for item in book.items:
                    if isinstance(item, epub.EpubHtml):
                        content += item.content.decode('utf-8')
                styled_content = f"""
                <html>
                    <head>
                        <style>
                            body 
                            {{
                                color: rgb(255, 255, 255);
                                font-size: 16px;
                                background-color: rgba(26, 26, 29, 1);
                            }}
                        </style>
                    </head>
                    <body>
                        {content}
                    </body>
                </html>
                """
                self.text.setHtml(styled_content)
    
                # Generate a unique hash for the current file
                self.current_file_hash = self.generate_file_hash(content)
    
                # Restore the scroll position if available
                if self.current_file_hash in scroll_positions:
                    self.text.verticalScrollBar().setValue(scroll_positions[self.current_file_hash])
                print(scroll_positions)
            else:
                QMessageBox.information(self, "Invalid filetype","Please choose another file")
    
    if __name__ == "__main__":
        main()
    
    JonBJ 1 Reply Last reply
    0
    • R Rivridis

      @JonB The hash function is not the issue, as I checked the printed dictionary value. And for the files that does not work, the position gets shifted to around 1000 everytime

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

      @Rivridis said in Way to save QTextEdit scroll state?:

      And for the files that does not work, the position gets shifted to around 1000 everytime

      If it were me, I would try moving the

      self.text.verticalScrollBar().setValue(scroll_positions[self.current_file_hash])
      

      into a single shot QTimer with 0 or small delay after you have done the self.text.setHtml(styled_content).

      R 1 Reply Last reply
      2
      • R Rivridis

        Is there any way the scroll state of QTextEdit be saved to a local file or within code itself? I tried taking scrollbar position, but it gets reset while switching between files. I set up a QTextEdit to load a EPUB file's content when a element in QTreeview is doubleclicked. It works once and stops working after a while.
        Or, is there any alternate way to load EPUB files that will make it easier?

        from PySide6.QtWidgets import QApplication, QDialog, QVBoxLayout,QMessageBox,QLineEdit,QPushButton,QMainWindow,QSplashScreen,QFileDialog,QTreeView,QFileSystemModel,QTextBrowser,QTextEdit
        from PySide6.QtGui import QPixmap,QTextCharFormat,QFont,QTextCursor,QColor
        from PySide6.QtCore import Qt
        from PySide6.QtUiTools import QUiLoader
        import sys
        from ebooklib import epub
        from bs4 import BeautifulSoup
        import qdarktheme
        import hashlib
        import time
        scroll_positions = {}
        qss = """
                QScrollBar::sub-page:horizontal {
                background: rgba(255, 255, 255, 0)
            }
        
            QScrollBar::add-page:horizontal {
                background: rgba(255, 255, 255, 0)
            }
            QScrollBar::sub-page:vertical {
                background: rgba(255, 255, 255, 0)
            }
        
            QScrollBar::add-page:vertical {
                background: rgba(255, 255, 255, 0)
            }
            QScrollBar::handle
            {
                background : rgba(138,124,171,1);
                min-height: 40px;
            }
            QScrollBar::handle:vertical
            {
                background : rgba(138,124,171,1);
                min-height: 40px;
            }
            QScrollBar::handle::pressed
            {
            background : rgba(138,124,171,1); 
            }
            QScrollBar::handle::hover
            {
            background : rgba(138,124,171,1);
            }
            QScrollBar::add-line,
            QScrollBar::sub-line {
                width: 0;
                subcontrol-position: right;
                subcontrol-origin: margin;
            }
        
        
            """
        
        def show_splash_screen():
            splash_pix = QPixmap('assets\splash.jpg')
            splash_pix = splash_pix.scaled(550, 450, Qt.KeepAspectRatio,Qt.SmoothTransformation)
            splash = QSplashScreen(splash_pix, Qt.WindowStaysOnTopHint)
            splash.setMask(splash_pix.mask())
            splash.show()
        
            return splash
        
        def main():
            app = QApplication(sys.argv)
            qdarktheme.setup_theme(additional_qss=qss,custom_colors={
                "[dark]": {
                    "primary": "#D0BCFF",
                    "border": "#00000000",
                    "treeSectionHeader.background":"#8a7cab"
                }
            })
        
            # Create and show splash screen
            splash = show_splash_screen()
            main_window = Main()
            splash.close()
        
            main_window.children()[1].show()
        
            sys.exit(app.exec())
        
        class Main(QMainWindow):
            def __init__(self):
                super().__init__()
                self.current_file_hash = None
                loader = QUiLoader()
                ui_file = "assets/main.ui" 
                ui = loader.load(ui_file, self)
        
                self.directory = ui.findChild(QPushButton,"direct")
                self.directory.clicked.connect(self.dirpop)
        
                self.tree = ui.findChild(QTreeView,"tree") 
        
                self.model = QFileSystemModel()
                self.model.setRootPath("/")
                self.tree.setModel(self.model)
                self.tree.setRootIndex(self.model.index("/"))
        
                self.tree.doubleClicked.connect(self.choose)
        
                self.text = ui.findChild(QTextEdit,'text')
                self.text.setReadOnly(True)
                self.scroll_bar = self.text.verticalScrollBar()
        
        
            def dirpop(self):
                options = QFileDialog.Options()
                directory = QFileDialog.getExistingDirectory(self, "Select Directory", "", options=options)
        
                if directory:
                    self.tree.setRootIndex(self.model.index(directory))
            
            def generate_file_hash(self, content):
                sha256 = hashlib.sha256()
                sha256.update(content.encode('utf-8'))
                return sha256.hexdigest()
            
            def choose(self, index):
                file_path = self.model.filePath(index)
                if ".epub" in file_path:
                    # Save the current scroll position
                    if self.current_file_hash:
                        scroll_positions[self.current_file_hash] = self.text.verticalScrollBar().value()
        
                    book = epub.read_epub(file_path)
                    content = ""
                    for item in book.items:
                        if isinstance(item, epub.EpubHtml):
                            content += item.content.decode('utf-8')
                    styled_content = f"""
                    <html>
                        <head>
                            <style>
                                body 
                                {{
                                    color: rgb(255, 255, 255);
                                    font-size: 16px;
                                    background-color: rgba(26, 26, 29, 1);
                                }}
                            </style>
                        </head>
                        <body>
                            {content}
                        </body>
                    </html>
                    """
                    self.text.setHtml(styled_content)
        
                    # Generate a unique hash for the current file
                    self.current_file_hash = self.generate_file_hash(content)
        
                    # Restore the scroll position if available
                    if self.current_file_hash in scroll_positions:
                        self.text.verticalScrollBar().setValue(scroll_positions[self.current_file_hash])
                    print(scroll_positions)
                else:
                    QMessageBox.information(self, "Invalid filetype","Please choose another file")
        
        if __name__ == "__main__":
            main()
        
        JonBJ Offline
        JonBJ Offline
        JonB
        wrote on last edited by
        #2

        @Rivridis said in Way to save QTextEdit scroll state?:

        I tried taking scrollbar position, but it gets reset while switching between files.

        Aren't you supposed to restore it after loading the file then?

        R 1 Reply Last reply
        0
        • JonBJ JonB

          @Rivridis said in Way to save QTextEdit scroll state?:

          I tried taking scrollbar position, but it gets reset while switching between files.

          Aren't you supposed to restore it after loading the file then?

          R Offline
          R Offline
          Rivridis
          wrote on last edited by
          #3

          @JonB That's what I did, as seen from the code, the thing is, it works for one fixed file and does not work for the others.

          JonBJ 1 Reply Last reply
          0
          • R Rivridis

            @JonB That's what I did, as seen from the code, the thing is, it works for one fixed file and does not work for the others.

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

            @Rivridis
            Then I would guess you might have some issue in your "hash lookup" of each file? Use a debugger or more print() statements. For all the files where "it does not work", what is the saved scroll position, what are you restoring and where does to fail to work?

            R 1 Reply Last reply
            0
            • JonBJ JonB

              @Rivridis
              Then I would guess you might have some issue in your "hash lookup" of each file? Use a debugger or more print() statements. For all the files where "it does not work", what is the saved scroll position, what are you restoring and where does to fail to work?

              R Offline
              R Offline
              Rivridis
              wrote on last edited by
              #5

              @JonB The hash function is not the issue, as I checked the printed dictionary value. And for the files that does not work, the position gets shifted to around 1000 everytime

              SGaistS JonBJ 2 Replies Last reply
              0
              • SGaistS SGaist moved this topic from General and Desktop on
              • R Rivridis

                @JonB The hash function is not the issue, as I checked the printed dictionary value. And for the files that does not work, the position gets shifted to around 1000 everytime

                SGaistS Offline
                SGaistS Offline
                SGaist
                Lifetime Qt Champion
                wrote on last edited by
                #6

                Did you try to update the position in reaction to textChanged rather than directly after setting the new content ?

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

                R 1 Reply Last reply
                0
                • SGaistS SGaist

                  Did you try to update the position in reaction to textChanged rather than directly after setting the new content ?

                  R Offline
                  R Offline
                  Rivridis
                  wrote on last edited by
                  #7

                  @SGaist Yup, tried that, its not working either. I have now switched to textcursor methods but now the problem is of setting the textcursor to bottom of QTextEdit viewport.

                  1 Reply Last reply
                  0
                  • R Rivridis

                    @JonB The hash function is not the issue, as I checked the printed dictionary value. And for the files that does not work, the position gets shifted to around 1000 everytime

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

                    @Rivridis said in Way to save QTextEdit scroll state?:

                    And for the files that does not work, the position gets shifted to around 1000 everytime

                    If it were me, I would try moving the

                    self.text.verticalScrollBar().setValue(scroll_positions[self.current_file_hash])
                    

                    into a single shot QTimer with 0 or small delay after you have done the self.text.setHtml(styled_content).

                    R 1 Reply Last reply
                    2
                    • JonBJ JonB

                      @Rivridis said in Way to save QTextEdit scroll state?:

                      And for the files that does not work, the position gets shifted to around 1000 everytime

                      If it were me, I would try moving the

                      self.text.verticalScrollBar().setValue(scroll_positions[self.current_file_hash])
                      

                      into a single shot QTimer with 0 or small delay after you have done the self.text.setHtml(styled_content).

                      R Offline
                      R Offline
                      Rivridis
                      wrote on last edited by Rivridis
                      #9

                      @JonB Damn it works, thanks a lot. I had been trying to solve this for a day straight :/ Just needed 100 as time delay, small values did not work

                      JonBJ 1 Reply Last reply
                      0
                      • R Rivridis has marked this topic as solved on
                      • R Rivridis

                        @JonB Damn it works, thanks a lot. I had been trying to solve this for a day straight :/ Just needed 100 as time delay, small values did not work

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

                        @Rivridis
                        Anything "visual" like scroll position, size, cursor position, focus you need to leave it to draw itself once after e.g. setHtml(), because they get reset or need recalculating.

                        1 Reply Last reply
                        2

                        • Login

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