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 16 Oct 2023, 17:23 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()
    
    J 1 Reply Last reply 16 Oct 2023, 17:26
    0
    • R Rivridis
      16 Oct 2023, 18:11

      @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

      J Offline
      J Offline
      JonB
      wrote on 16 Oct 2023, 21:35 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 16 Oct 2023, 21:53
      2
      • R Rivridis
        16 Oct 2023, 17:23

        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()
        
        J Offline
        J Offline
        JonB
        wrote on 16 Oct 2023, 17:26 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 16 Oct 2023, 17:35
        0
        • J JonB
          16 Oct 2023, 17:26

          @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 16 Oct 2023, 17:35 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.

          J 1 Reply Last reply 16 Oct 2023, 18:05
          0
          • R Rivridis
            16 Oct 2023, 17:35

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

            J Offline
            J Offline
            JonB
            wrote on 16 Oct 2023, 18:05 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 16 Oct 2023, 18:11
            0
            • J JonB
              16 Oct 2023, 18:05

              @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 16 Oct 2023, 18:11 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 J 2 Replies Last reply 16 Oct 2023, 18:41
              0
              • SGaistS SGaist moved this topic from General and Desktop on 16 Oct 2023, 18:31
              • R Rivridis
                16 Oct 2023, 18:11

                @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 16 Oct 2023, 18:41 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 16 Oct 2023, 20:06
                0
                • SGaistS SGaist
                  16 Oct 2023, 18:41

                  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 16 Oct 2023, 20:06 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
                    16 Oct 2023, 18:11

                    @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

                    J Offline
                    J Offline
                    JonB
                    wrote on 16 Oct 2023, 21:35 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 16 Oct 2023, 21:53
                    2
                    • J JonB
                      16 Oct 2023, 21:35

                      @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 16 Oct 2023, 21:53 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

                      J 1 Reply Last reply 16 Oct 2023, 22:00
                      0
                      • R Rivridis has marked this topic as solved on 16 Oct 2023, 21:53
                      • R Rivridis
                        16 Oct 2023, 21:53

                        @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

                        J Offline
                        J Offline
                        JonB
                        wrote on 16 Oct 2023, 22:00 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

                        1/10

                        16 Oct 2023, 17:23

                        • Login

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