Scrollbar 认为它的 QTextEdit 认为比它小(不使用 window 调整大小)
Scrollbar thinks its QTextEdit thinks is smaller than it is (doesn't resize with window)
我遇到了一个奇怪的错误。滚动条认为它的 QTextEdit 比实际小!
我有一个自定义的 QTextEdit。每当我替换 HTML 时,滚动条都会重置为 0。为了克服这个问题,我只是覆盖 setHtml,存储旧值并在替换 HTML 后重置它。
麻烦的是,如果我的 window 大于它的最小尺寸(或者开始,如果没有最小尺寸),QTextEdit 会按预期增长,但是对于滚动条位置值超过某个特定值的情况,此解决方案将停止工作数字,这意味着即使我启动程序最大化或手动调整它的大小,QTextEdit 仍然认为它的大小与最小值相同,因此 window 在其最小尺寸下不会显示的任何内容都会从滚动条中切断.
我尝试将所有容器设置为所有大小策略,唯一“有效”的是最大和固定但 QTextEdit 不再根据需要使用 window 调整大小。直接设置滑块位置也不起作用。
最小可重现示例:
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__()
# set the Window's minimum size according to the width of images in the product gallery plus a constant
self.setMinimumSize(800, 600)
# set up the main window
self.setGeometry(0, 30, 800, 600)
def set_up_window(self):
# the main container is a vertical scroll area, with the image section on top and the info section on the bottom
main_container = QWidget()
main_container.setMouseTracking(True)
main_container_layout = QVBoxLayout()
main_container.setLayout(main_container_layout)
# 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_container_layout.addWidget(description_editor)
main_container.setLayout(main_container_layout)
main_window.setCentralWidget(main_container)
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()
适用于此维度:
仅适用于红色部分。下面的任何内容都被带到相同的位置:
注意:这个回答没有直接回复问题,因为问题的根源与滚动条无关
问题是由于setHtml
总是重置内容造成的。虽然结果可能看起来是瞬时的,但事实并非如此,因为必须根据滚动区域的大小重新布局文档,这最终会更新滚动条。
虽然技术上可以延迟滚动条重新定位,但真正的问题是setHTML
不是正确的提供突出显示的方法,尤其是鼠标悬停:鼠标的每一次单独移动都会导致上面解释的情况,这显然不是一个好的解决方案,性能明智。
同样重要的是要记住,在 Qt 编辑器中设置 HTML 只是解释,因为 HTML 被解析,然后“翻译”成 Qt 文档;您会看到 toHtml()
将 而不是 return 用于 setHtml()
的代码,即使未进行任何更改也是如此。
事实上,改变 Qt 富文本编辑器格式的正确方法是与其较低级别 API 交互,访问 QTextDocument and modifying it using a QTextCharFormat.
请注意,虽然使用 QTextCursor 界面应用正常编辑,但它不会有效用于此目的,因为它被视为“用户操作”并将格式更改添加到撤消堆栈文档。
为了将更改应用到基础文档 而不 更改其内容,有必要通过指定字符边界和实际格式为该布局使用 QTextLayout of the QTextBlock that will contain the highlighted text, then it's possible to create and set a FormatRange .
这种方法的好处是格式更改不会更改实际的文档格式,只会更改文档的显示方式,因此,例如,toHtml()
将永远不会包含突出显示。
这是总结过程:
- 根据鼠标光标位置获取QTextCursor;
- select鼠标下的字;
- 获取 QTextBlock 并确保鼠标实际上位于该块的矩形内(
cursor.WordUnderCursor
总能找到最接近的词,即使它不 恰好 在鼠标);
- 获取 selection 的范围并检查该范围是否与上次调用相比发生了变化;
- 清除之前的排版格式(可以是不同的词,甚至是不同的块);
- 如果有 selection,创建一个 FormatRange,其起始位置基于块光标位置,并具有给定的文本格式;
- 在布局上设置格式;
- 通知文档其内容“脏”,需要重新布局(并重新绘制);
为了在鼠标移动时调用该函数,应设置 mouseTracking
属性,并且必须覆盖 viewportEvent
以正确跟踪鼠标事件。
from PyQt5 import QtCore, QtGui, QtWidgets
from random import randrange, choice
from string import ascii_lowercase as letters
class HighlightTextEdit(QtWidgets.QTextEdit):
highlightPos = -1, -1
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setMouseTracking(True)
self.highlightBlock = self.document().firstBlock()
self.highlightFormat = QtGui.QTextCharFormat()
self.highlightFormat.setBackground(
QtGui.QBrush(QtGui.QColor('#FFFF00')))
self.highlightFormat.setFontUnderline(True)
self.document().contentsChanged.connect(self.highlight)
def highlight(self, pos=None):
if not self.toPlainText() or not self.isVisible():
return
if pos is None:
pos = self.mapFromGlobal(QtGui.QCursor.pos())
cursor = self.cursorForPosition(pos)
cursor.select(cursor.WordUnderCursor)
start = cursor.selectionStart()
end = cursor.selectionEnd()
doc = self.document()
block = doc.findBlock(start)
# check if the mouse is actually inside the rectangle of the block
blockRect = doc.documentLayout().blockBoundingRect(block)
blockLayout = block.layout()
if not pos in blockRect.translated(0, -self.verticalScrollBar().value()):
# mouse is outside of the block, no highlight
start = end = -1
startFromBlock = start - block.position()
length = end - start
if length:
# ensure that the cursor is actually within the boundaries of the word
textLine = blockLayout.lineForTextPosition(startFromBlock)
endFromBlock = startFromBlock + length
x, _ = textLine.cursorToX(endFromBlock)
if pos.x() > blockRect.x() + x:
start = end = -1
length = 0
# if the range is the same as the previous call, we can ignore it
if self.highlightPos == (start, end):
return
# clear the previous highlighting
self.highlightBlock.layout().clearFormats()
self.highlightPos = start, end
if length:
# create a FormatRange for the highlight using the current format
r = QtGui.QTextLayout.FormatRange()
r.start = startFromBlock
r.length = length
r.format = self.highlightFormat
blockLayout.setFormats([r])
# notify that the document must be layed out (and repainted) again
dirtyEnd = max(
self.highlightBlock.position() + self.highlightBlock.length(),
block.position() + block.length()
)
dirtyStart = min(self.highlightBlock.position(), block.position())
doc.markContentsDirty(dirtyStart, dirtyEnd - dirtyStart)
self.highlightBlock = block
def viewportEvent(self, event):
if event.type() == event.Leave:
# disable highlight when leaving, using coordinates outside of the
# viewport to ensure that highlighting is cleared
self.highlight(QtCore.QPoint(-1, -1))
elif event.type() == event.Enter:
self.highlight()
elif event.type() == event.MouseMove:
if not event.buttons():
self.highlight(event.pos())
elif event.type() == event.MouseButtonRelease:
self.highlight(event.pos())
return super().viewportEvent(event)
if __name__ == '__main__':
text = ''
for p in range(randrange(10, 30)):
parag = []
for w in range(randrange(5, 50)):
word = ''
for l in range(randrange(2, 20)):
word += choice(letters)
if not randrange(10):
word += ','
parag.append(word)
text += ' '.join(parag).capitalize().rstrip(',') + '.\n\n'
import sys
app = QtWidgets.QApplication(sys.argv)
test = HighlightTextEdit()
test.setText(text)
test.show()
sys.exit(app.exec_())
我遇到了一个奇怪的错误。滚动条认为它的 QTextEdit 比实际小!
我有一个自定义的 QTextEdit。每当我替换 HTML 时,滚动条都会重置为 0。为了克服这个问题,我只是覆盖 setHtml,存储旧值并在替换 HTML 后重置它。
麻烦的是,如果我的 window 大于它的最小尺寸(或者开始,如果没有最小尺寸),QTextEdit 会按预期增长,但是对于滚动条位置值超过某个特定值的情况,此解决方案将停止工作数字,这意味着即使我启动程序最大化或手动调整它的大小,QTextEdit 仍然认为它的大小与最小值相同,因此 window 在其最小尺寸下不会显示的任何内容都会从滚动条中切断.
我尝试将所有容器设置为所有大小策略,唯一“有效”的是最大和固定但 QTextEdit 不再根据需要使用 window 调整大小。直接设置滑块位置也不起作用。
最小可重现示例:
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__()
# set the Window's minimum size according to the width of images in the product gallery plus a constant
self.setMinimumSize(800, 600)
# set up the main window
self.setGeometry(0, 30, 800, 600)
def set_up_window(self):
# the main container is a vertical scroll area, with the image section on top and the info section on the bottom
main_container = QWidget()
main_container.setMouseTracking(True)
main_container_layout = QVBoxLayout()
main_container.setLayout(main_container_layout)
# 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_container_layout.addWidget(description_editor)
main_container.setLayout(main_container_layout)
main_window.setCentralWidget(main_container)
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()
适用于此维度:
仅适用于红色部分。下面的任何内容都被带到相同的位置:
注意:这个回答没有直接回复问题,因为问题的根源与滚动条无关
问题是由于setHtml
总是重置内容造成的。虽然结果可能看起来是瞬时的,但事实并非如此,因为必须根据滚动区域的大小重新布局文档,这最终会更新滚动条。
虽然技术上可以延迟滚动条重新定位,但真正的问题是setHTML
不是正确的提供突出显示的方法,尤其是鼠标悬停:鼠标的每一次单独移动都会导致上面解释的情况,这显然不是一个好的解决方案,性能明智。
同样重要的是要记住,在 Qt 编辑器中设置 HTML 只是解释,因为 HTML 被解析,然后“翻译”成 Qt 文档;您会看到 toHtml()
将 而不是 return 用于 setHtml()
的代码,即使未进行任何更改也是如此。
事实上,改变 Qt 富文本编辑器格式的正确方法是与其较低级别 API 交互,访问 QTextDocument and modifying it using a QTextCharFormat.
请注意,虽然使用 QTextCursor 界面应用正常编辑,但它不会有效用于此目的,因为它被视为“用户操作”并将格式更改添加到撤消堆栈文档。
为了将更改应用到基础文档 而不 更改其内容,有必要通过指定字符边界和实际格式为该布局使用 QTextLayout of the QTextBlock that will contain the highlighted text, then it's possible to create and set a FormatRange .
这种方法的好处是格式更改不会更改实际的文档格式,只会更改文档的显示方式,因此,例如,toHtml()
将永远不会包含突出显示。
这是总结过程:
- 根据鼠标光标位置获取QTextCursor;
- select鼠标下的字;
- 获取 QTextBlock 并确保鼠标实际上位于该块的矩形内(
cursor.WordUnderCursor
总能找到最接近的词,即使它不 恰好 在鼠标); - 获取 selection 的范围并检查该范围是否与上次调用相比发生了变化;
- 清除之前的排版格式(可以是不同的词,甚至是不同的块);
- 如果有 selection,创建一个 FormatRange,其起始位置基于块光标位置,并具有给定的文本格式;
- 在布局上设置格式;
- 通知文档其内容“脏”,需要重新布局(并重新绘制);
为了在鼠标移动时调用该函数,应设置 mouseTracking
属性,并且必须覆盖 viewportEvent
以正确跟踪鼠标事件。
from PyQt5 import QtCore, QtGui, QtWidgets
from random import randrange, choice
from string import ascii_lowercase as letters
class HighlightTextEdit(QtWidgets.QTextEdit):
highlightPos = -1, -1
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setMouseTracking(True)
self.highlightBlock = self.document().firstBlock()
self.highlightFormat = QtGui.QTextCharFormat()
self.highlightFormat.setBackground(
QtGui.QBrush(QtGui.QColor('#FFFF00')))
self.highlightFormat.setFontUnderline(True)
self.document().contentsChanged.connect(self.highlight)
def highlight(self, pos=None):
if not self.toPlainText() or not self.isVisible():
return
if pos is None:
pos = self.mapFromGlobal(QtGui.QCursor.pos())
cursor = self.cursorForPosition(pos)
cursor.select(cursor.WordUnderCursor)
start = cursor.selectionStart()
end = cursor.selectionEnd()
doc = self.document()
block = doc.findBlock(start)
# check if the mouse is actually inside the rectangle of the block
blockRect = doc.documentLayout().blockBoundingRect(block)
blockLayout = block.layout()
if not pos in blockRect.translated(0, -self.verticalScrollBar().value()):
# mouse is outside of the block, no highlight
start = end = -1
startFromBlock = start - block.position()
length = end - start
if length:
# ensure that the cursor is actually within the boundaries of the word
textLine = blockLayout.lineForTextPosition(startFromBlock)
endFromBlock = startFromBlock + length
x, _ = textLine.cursorToX(endFromBlock)
if pos.x() > blockRect.x() + x:
start = end = -1
length = 0
# if the range is the same as the previous call, we can ignore it
if self.highlightPos == (start, end):
return
# clear the previous highlighting
self.highlightBlock.layout().clearFormats()
self.highlightPos = start, end
if length:
# create a FormatRange for the highlight using the current format
r = QtGui.QTextLayout.FormatRange()
r.start = startFromBlock
r.length = length
r.format = self.highlightFormat
blockLayout.setFormats([r])
# notify that the document must be layed out (and repainted) again
dirtyEnd = max(
self.highlightBlock.position() + self.highlightBlock.length(),
block.position() + block.length()
)
dirtyStart = min(self.highlightBlock.position(), block.position())
doc.markContentsDirty(dirtyStart, dirtyEnd - dirtyStart)
self.highlightBlock = block
def viewportEvent(self, event):
if event.type() == event.Leave:
# disable highlight when leaving, using coordinates outside of the
# viewport to ensure that highlighting is cleared
self.highlight(QtCore.QPoint(-1, -1))
elif event.type() == event.Enter:
self.highlight()
elif event.type() == event.MouseMove:
if not event.buttons():
self.highlight(event.pos())
elif event.type() == event.MouseButtonRelease:
self.highlight(event.pos())
return super().viewportEvent(event)
if __name__ == '__main__':
text = ''
for p in range(randrange(10, 30)):
parag = []
for w in range(randrange(5, 50)):
word = ''
for l in range(randrange(2, 20)):
word += choice(letters)
if not randrange(10):
word += ','
parag.append(word)
text += ' '.join(parag).capitalize().rstrip(',') + '.\n\n'
import sys
app = QtWidgets.QApplication(sys.argv)
test = HighlightTextEdit()
test.setText(text)
test.show()
sys.exit(app.exec_())