Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

PyQt5 - Scrollbar thinks its QTextEdit thinks is smaller than it is (doesn't resize with window)



  • This post is deleted!


  • @ZeHgS
    This is just a thought. Where are you resetting this scrollbar (well, you are doing this inside setHtml())? Anything outside a resize/show event in Qt widgets is liable to produce an "unreliable" size, as that is only calculated correctly when the widget is shown. That is my understanding/experience.



  • Thank you so much for replying! As far as I can tell everything takes place within resize events.

    Here is a minimum reproducible example:

    Program launcher:

    from PyQt5.QtWidgets import QMainWindow, QApplication, QTextEdit, QWidget, QScrollArea, QVBoxLayout, QHBoxLayout, QSizePolicy
    from PyQt5.QtGui import QMouseEvent, QTextCursor, QIcon
    from PyQt5.QtCore import Qt
    
    import GUIMainWindow
    
    from itertools import chain         # to unnest nested lists
    import re
    
    application = QApplication([])
    
    
    class GUIMainWindow(QMainWindow):
        def __init__(self):
            super().__init__()
    
            # add the description editor
            description_editor = TextEditor()
            description_editor.setAcceptRichText(True)
            description_editor.setTextInteractionFlags(Qt.NoTextInteraction)
            description_editor.setText(
                'Meditation has proven difficult to define as it covers a wide range of dissimilar practices in different traditions. In popular usage, the word "meditation" and the phrase "meditative practice" are often used imprecisely to designate practices found across many cultures.[4][20] These can include almost anything that is claimed to train the attention of mind or to teach calm or compassion.[21] There remains no definition of necessary and sufficient criteria for meditation that has achieved universal or widespread acceptance within the modern scientific community. In 1971, Claudio Naranjo noted that "The word "meditation" has been used to designate a variety of practices that differ enough from one another so that we may find trouble in defining what meditation is."[22]: 6  A 2009 study noted a "persistent lack of consensus in the literature" and a "seeming intractability of defining meditation".[23]: 135 <BR><BR>'
    
                'In modern psychological research, meditation has been defined and characterized in a variety of ways. Many of these emphasize the role of attention[4][1][2][3] and characterize the practice of meditation as attempts to get beyond the reflexive, "discursive thinking"[note 1] or "logic"[note 2] mind[note 3] to achieve a deeper, more devout, or more relaxed state.<BR><BR>'
    
                'Bond et al. (2009) identified criteria for defining a practice as meditation "for use in a comprehensive systematic review of the therapeutic use of meditation", using "a 5-round Delphi study with a panel of 7 experts in meditation research" who were also trained in diverse but empirically highly studied (Eastern-derived or clinical) forms of meditation[note 4]:<BR><BR>'
    
                'three main criteria [...] as essential to any meditation practice: the use of a defined technique, logic relaxation,[note 5] and a self-induced state/mode.<BR><BR>'
    
                'Other criteria deemed important [but not essential] involve a state of psychophysical relaxation, the use of a self-focus skill or anchor, the presence of a state of suspension of logical thought processes, a religious/spiritual/philosophical context, or a state of mental silence.[23]: 135 .<BR><BR>'
    
                '[...] It is plausible that meditation is best thought of as a natural category of techniques best captured by "family resemblances" [...] or by the related "prototype" model of concepts."[23]: 135 [note 6].<BR><BR>'
    
                'Several other definitions of meditation have been used by influential modern reviews of research on meditation across multiple traditions:[note 7].<BR><BR>'
    
                'Walsh & Shapiro (2006): "[M]editation refers to a family of self-regulation practices that focus on training attention and awareness in order to bring mental processes under greater voluntary control and thereby foster general mental well-being and development and/or specific capacities such as calm, clarity, and concentration"[1]: 228–29 .<BR>'
                'Cahn & Polich (2006): "[M]editation is used to describe practices that self-regulate the body and mind, thereby affecting mental events by engaging a specific attentional set.... regulation of attention is the central commonality across the many divergent methods"[2]: 180 .<BR>'
                'Jevning et al. (1992): "We define meditation... as a stylized mental technique... repetitively practiced for the purpose of attaining a subjective experience that is frequently described as very restful, silent, and of heightened alertness, often characterized as blissful"[3]: 415 .<BR>'
                'Goleman (1988): "the need for the meditator to retrain his attention, whether through concentration or mindfulness, is the single invariant ingredient in... every meditation system"[4]: 107 '
                'Separation of technique from tradition.<BR>''Meditation has proven difficult to define as it covers a wide range of dissimilar practices in different traditions. In popular usage, the word "meditation" and the phrase "meditative practice" are often used imprecisely to designate practices found across many cultures.[4][20] These can include almost anything that is claimed to train the attention of mind or to teach calm or compassion.[21] There remains no definition of necessary and sufficient criteria for meditation that has achieved universal or widespread acceptance within the modern scientific community. In 1971, Claudio Naranjo noted that "The word "meditation" has been used to designate a variety of practices that differ enough from one another so that we may find trouble in defining what meditation is."[22]: 6  A 2009 study noted a "persistent lack of consensus in the literature" and a "seeming intractability of defining meditation".[23]: 135 <BR><BR>'
    
                'In modern psychological research, meditation has been defined and characterized in a variety of ways. Many of these emphasize the role of attention[4][1][2][3] and characterize the practice of meditation as attempts to get beyond the reflexive, "discursive thinking"[note 1] or "logic"[note 2] mind[note 3] to achieve a deeper, more devout, or more relaxed state.<BR><BR>'
    
                'Bond et al. (2009) identified criteria for defining a practice as meditation "for use in a comprehensive systematic review of the therapeutic use of meditation", using "a 5-round Delphi study with a panel of 7 experts in meditation research" who were also trained in diverse but empirically highly studied (Eastern-derived or clinical) forms of meditation[note 4]:<BR><BR>'
    
                'three main criteria [...] as essential to any meditation practice: the use of a defined technique, logic relaxation,[note 5] and a self-induced state/mode.<BR><BR>'
    
                'Other criteria deemed important [but not essential] involve a state of psychophysical relaxation, the use of a self-focus skill or anchor, the presence of a state of suspension of logical thought processes, a religious/spiritual/philosophical context, or a state of mental silence.[23]: 135 .<BR><BR>'
    
                '[...] It is plausible that meditation is best thought of as a natural category of techniques best captured by "family resemblances" [...] or by the related "prototype" model of concepts."[23]: 135 [note 6].<BR><BR>'
    
                'Several other definitions of meditation have been used by influential modern reviews of research on meditation across multiple traditions:[note 7].<BR><BR>'
    
                'Walsh & Shapiro (2006): "[M]editation refers to a family of self-regulation practices that focus on training attention and awareness in order to bring mental processes under greater voluntary control and thereby foster general mental well-being and development and/or specific capacities such as calm, clarity, and concentration"[1]: 228–29 .<BR>'
                'Cahn & Polich (2006): "[M]editation is used to describe practices that self-regulate the body and mind, thereby affecting mental events by engaging a specific attentional set.... regulation of attention is the central commonality across the many divergent methods"[2]: 180 .<BR>'
                'Jevning et al. (1992): "We define meditation... as a stylized mental technique... repetitively practiced for the purpose of attaining a subjective experience that is frequently described as very restful, silent, and of heightened alertness, often characterized as blissful"[3]: 415 .<BR>'
                'Goleman (1988): "the need for the meditator to retrain his attention, whether through concentration or mindfulness, is the single invariant ingredient in... every meditation system"[4]: 107 '
                'Separation of technique from tradition.<BR>''Meditation has proven difficult to define as it covers a wide range of dissimilar practices in different traditions. In popular usage, the word "meditation" and the phrase "meditative practice" are often used imprecisely to designate practices found across many cultures.[4][20] These can include almost anything that is claimed to train the attention of mind or to teach calm or compassion.[21] There remains no definition of necessary and sufficient criteria for meditation that has achieved universal or widespread acceptance within the modern scientific community. In 1971, Claudio Naranjo noted that "The word "meditation" has been used to designate a variety of practices that differ enough from one another so that we may find trouble in defining what meditation is."[22]: 6  A 2009 study noted a "persistent lack of consensus in the literature" and a "seeming intractability of defining meditation".[23]: 135 <BR><BR>'
    
                'In modern psychological research, meditation has been defined and characterized in a variety of ways. Many of these emphasize the role of attention[4][1][2][3] and characterize the practice of meditation as attempts to get beyond the reflexive, "discursive thinking"[note 1] or "logic"[note 2] mind[note 3] to achieve a deeper, more devout, or more relaxed state.<BR><BR>'
    
                'Bond et al. (2009) identified criteria for defining a practice as meditation "for use in a comprehensive systematic review of the therapeutic use of meditation", using "a 5-round Delphi study with a panel of 7 experts in meditation research" who were also trained in diverse but empirically highly studied (Eastern-derived or clinical) forms of meditation[note 4]:<BR><BR>'
    
                'three main criteria [...] as essential to any meditation practice: the use of a defined technique, logic relaxation,[note 5] and a self-induced state/mode.<BR><BR>'
    
                'Other criteria deemed important [but not essential] involve a state of psychophysical relaxation, the use of a self-focus skill or anchor, the presence of a state of suspension of logical thought processes, a religious/spiritual/philosophical context, or a state of mental silence.[23]: 135 .<BR><BR>'
    
                '[...] It is plausible that meditation is best thought of as a natural category of techniques best captured by "family resemblances" [...] or by the related "prototype" model of concepts."[23]: 135 [note 6].<BR><BR>'
    
                'Several other definitions of meditation have been used by influential modern reviews of research on meditation across multiple traditions:[note 7].<BR><BR>'
    
                'Walsh & Shapiro (2006): "[M]editation refers to a family of self-regulation practices that focus on training attention and awareness in order to bring mental processes under greater voluntary control and thereby foster general mental well-being and development and/or specific capacities such as calm, clarity, and concentration"[1]: 228–29 .<BR>'
                'Cahn & Polich (2006): "[M]editation is used to describe practices that self-regulate the body and mind, thereby affecting mental events by engaging a specific attentional set.... regulation of attention is the central commonality across the many divergent methods"[2]: 180 .<BR>'
                'Jevning et al. (1992): "We define meditation... as a stylized mental technique... repetitively practiced for the purpose of attaining a subjective experience that is frequently described as very restful, silent, and of heightened alertness, often characterized as blissful"[3]: 415 .<BR>'
                'Goleman (1988): "the need for the meditator to retrain his attention, whether through concentration or mindfulness, is the single invariant ingredient in... every meditation system"[4]: 107 '
                'Separation of technique from tradition.<BR>'
                'Some of the difficulty in precisely defining meditation has been in recognizing the particularities of the many various traditions;[27] and theories and practice can differ within a tradition.[28] Taylor noted that even within a faith such as "Hindu" or "Buddhist", schools and individual teachers may teach distinct types of meditation.[29]: 2  Ornstein noted that "Most techniques of meditation do not exist as solitary practices but are only artificially separable from an entire system of practice and belief."[30]: 143  For instance, while monks meditate as part of their everyday lives, they also engage the codified rules and live together in monasteries in specific cultural settings that go along with their meditative practices.<BR>')
    
            main_window.setCentralWidget(description_editor)
    
    
        def resizeEvent(self, event):
            super().resizeEvent(event)
    
            self.set_up_window()
    
        def launch(self):
            self.set_up_window()
            self.showMaximized()
    
    
    class TextEditor(QTextEdit):
        def __init__(self):
            super(TextEditor, self).__init__()
    
            # make sure this widget is tracking the mouse position at all times
            self.setMouseTracking(True)
            self.last_mouse_position = None
    
        @staticmethod
        def get_selected_word(text_cursor):
            # extract selected word
            text_cursor.select(QTextCursor.WordUnderCursor)
            word_under_cursor = text_cursor.selectedText()
    
            # if the currently selected word is a '.', try to select the previous word
            while word_under_cursor == '.':
                # first move the character back one
                text_cursor.movePosition(QTextCursor.PreviousCharacter)
    
                # try to move to the beginning of the previous word
                successfully_moved_to_previous_word = text_cursor.movePosition(QTextCursor.PreviousWord)
    
                # if unsuccessful, try the next
                if not successfully_moved_to_previous_word:
                    # undo the character move
                    text_cursor.movePosition(QTextCursor.NextCharacter, 1)
    
                    # try to move to the beginning of the next word
                    if text_cursor.movePosition(QTextCursor.NextWord):
                        text_cursor.select(QTextCursor.WordUnderCursor)
                        word_under_cursor = text_cursor.selectedText()
    
                # move the QTextCursor from the '.' to the previous word
                else:
                    text_cursor.select(QTextCursor.WordUnderCursor)
                    word_under_cursor = text_cursor.selectedText()
    
            return word_under_cursor
    
        def get_whole_sentence_containing_selected_word(self, selected_word, text=None):
            if text is None:
                as_text = self.toPlainText()
    
            else:
                as_text = text
    
            # split into sentences
            text_lines = as_text.split('.')
    
            # add back the final stop
            for index, line in enumerate(text_lines[:-1]):
                text_lines[index] = line + '.'
    
            sentences = list(chain(*[s.splitlines() for s in text_lines]))
    
            # get the final selected sentence, if it's found
            selected_sentence = [s for s in sentences if selected_word in s]
    
            if len(selected_sentence) == 0:
                selected_sentence = ''
            else:
                selected_sentence = selected_sentence[0]
    
            return selected_sentence
    
        def get_whole_paragraph_containing_selected_word(self, selected_word):
            as_text = self.toPlainText()
    
            text_paragraphs = as_text.split('\n')
    
            selected_paragraph = [p for p in text_paragraphs if selected_word in p]
    
            return selected_paragraph[0] if len(selected_paragraph) > 0 else ''
    
        def replace_in_html(self, old_string, new_string, case_insensitive=False):
            if not case_insensitive:
                old_html = self.toHtml()
                new_html = old_html.replace(old_string, new_string)
                self.setHtml(new_html)
    
            else:
                old_html = self.toHtml()
                pattern = re.compile(old_string, re.IGNORECASE)
                new_html = pattern.sub(new_string, old_html)
                self.setHtml(new_html)
    
        def setText(self, text: str) -> None:
            extra_newlines_removed = text.replace('<BR><BR><BR>', '<BR><BR>').replace('\n\n', '\n')
    
            super().setText(extra_newlines_removed)
    
        def setHtml(self, text: str) -> None:
            old_value = self.verticalScrollBar().sliderPosition()
            old_value_hor = self.horizontalScrollBar().sliderPosition()
    
            super().setHtml(text)
    
            self.verticalScrollBar().setSliderPosition(old_value)
            self.horizontalScrollBar().setSliderPosition(old_value_hor)
    
        def mouse_inside_editor(self, position):
            self.last_mouse_position = position
            # create a QTextCursor at that position to select text
            text_cursor = self.cursorForPosition(position)
            # get the currently selected word
            word_under_cursor = self.get_selected_word(text_cursor)
    
            # replace substring with placeholder containing as many characters
            selected_word_placeholder = self.replace_selected_text_with_placeholder(text_cursor, 'ª')
    
            selected_fragment = self.get_whole_sentence_containing_selected_word(selected_word_placeholder)
            word_under_cursor = '<span style="background-color: #FFFF00;text-decoration:underline;">' + word_under_cursor + '</span>'
    
            highlighted_text = selected_fragment.replace(selected_word_placeholder, word_under_cursor)
    
            # replace the sentence with the new formatting
            self.replace_in_text(selected_fragment, highlighted_text)
    
        @staticmethod
        def replace_selected_text_with_placeholder(text_cursor, character):
            # remove the selected word to be replaced by the placeholder
            text_cursor.removeSelectedText()
    
            # create a placeholder with as many characters as the original word
            word_placeholder = ''
            for char in range(10):
                word_placeholder += character
            text_cursor.insertText(word_placeholder)
    
            return word_placeholder
    
        def mouseMoveEvent(self, mouse_event: QMouseEvent) -> None:
            if self.underMouse():
                self.mouse_inside_editor(mouse_event.pos())
    
        def replace_in_text(self, text_to_replace, text_to_replace_with):
            # replace newlines with a placeholder so they are kept once the HTML is removed to remove the previous formatting
            self.replace_in_html('<br/>', 'PL_BR', True)
            self.replace_in_html('<br />', 'PL_BR', True)
    
            # replace in the text
            replaced_text = self.toPlainText().replace(text_to_replace, text_to_replace_with)
    
            # remove stray final stops
            replaced_text = replaced_text.replace('..', '.')
            replaced_text = replaced_text.replace('PL_BR. ', 'PL_BR')
    
            # remove excessive empty lines
            replaced_text = replaced_text.replace('PL_BRPL_BRPL_BR', 'PL_BRPL_BR')
    
            while replaced_text.startswith('PL_BR'):
                replaced_text = replaced_text[5:]
    
            # return new lines
            final_html = replaced_text.replace('PL_BR', '<br/>')
    
            self.setHtml(final_html)
    
            # last stray final stops
            self.replace_in_html('">.<br/>', '"><br/>')
    
    
    main_window = GUIMainWindow()
    
    main_window.launch()
    
    application.exec()
    

Log in to reply