WordUnderCursor 无法正常工作(当不在任何单词之上时检测到单词)
WordUnderCursor not working as it should (word being detected when not on top of any words)
为什么检测到一个词在光标下?图像中的红色箭头从光标实际所在的位置开始。不管我把它放在哪里,只要它在window里面,程序就认为一个词被选中了。如果光标在文本下方,则默认为最后一个。如果光标在上面,则默认为第一个。
图片:
我的所有代码:
from PyQt5.QtWidgets import QTextEdit, QMainWindow, QApplication
from PyQt5.QtGui import QMouseEvent, QTextCursor
class Editor(QTextEdit):
def __init__(self):
super(Editor, self).__init__()
# make sure this widget is tracking the mouse position at all times
self.setMouseTracking(True)
def mouseMoveEvent(self, mouse_event: QMouseEvent) -> None:
if self.underMouse():
# create a QTextCursor at that position and select text
text_cursor = self.cursorForPosition(mouse_event.pos())
text_cursor.select(QTextCursor.WordUnderCursor)
word_under_cursor = text_cursor.selectedText()
print(word_under_cursor)
# replace substring with placeholder so that repeat occurrences aren't highlighted as well
selected_word_placeholder = self.replace_selected_text_with_placeholder(text_cursor)
word_under_cursor = '<span style="background-color: #FFFF00;font-weight:bold;">' + word_under_cursor + '</span>'
# replace the sentence with the new formatting
self.setHtml(self.toPlainText().replace(selected_word_placeholder, word_under_cursor))
def replace_in_html(self, old_string, new_string):
old_html = self.toHtml()
new_html = old_html.replace(old_string, new_string)
self.setHtml(new_html)
# use placeholder so that repeat occurrences of the word are not highlighted
def replace_selected_text_with_placeholder(self, text_cursor):
# 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 += '@'
text_cursor.insertText(word_placeholder)
return word_placeholder
def set_up(main_window):
title_editor = Editor()
title_editor.setText('Venda quente original xiaomi redmi airdots 2 tws fones de ouvido sem fio bluetooth fones controle ai gaming headset come')
main_window.setCentralWidget(title_editor)
main_window.show()
application = QApplication([])
window = QMainWindow()
set_up(window)
application.exec()
问题是由于 select()
总是试图 select 某些东西,即使鼠标实际上没有 在 文本块上, 它会得到最接近的单词。
解决方法是检查鼠标是否实际上在文本块的矩形内:
if self.underMouse():
pos = mouse_event.pos()
# create a QTextCursor at that position and select text
text_cursor = self.cursorForPosition(pos)
text_cursor.select(QTextCursor.WordUnderCursor)
start = text_cursor.selectionStart()
end = text_cursor.selectionEnd()
length = end - start
block = text_cursor.block()
blockRect = self.document().documentLayout().blockBoundingRect(block)
# translate by the offset caused by the scroll bar
blockRect.translate(0, -self.verticalScrollBar().value())
if not pos in blockRect:
# clear the selection since the mouse is not over the block
text_cursor.setPosition(text_cursor.position())
elif length:
# ensure that the mouse is actually over a word
startFromBlock = start - block.position()
textLine = block.layout().lineForTextPosition(startFromBlock)
endFromBlock = startFromBlock + length
x, _ = textLine.cursorToX(endFromBlock)
if pos.x() > blockRect.x() + x:
# mouse cursor is not over a word, clear the selection
text_cursor.setPosition(text_cursor.position())
请考虑,正如您对上一个问题的建议,使用 setHtml
突出显示文本 不是 一个好的选择,因为它总是会重置编辑内容;这不仅是性能问题,也是可用性问题(甚至忽略滚动条问题):setHtml
总是重置撤消堆栈,因此用户不能再使用撤消操作。
为什么检测到一个词在光标下?图像中的红色箭头从光标实际所在的位置开始。不管我把它放在哪里,只要它在window里面,程序就认为一个词被选中了。如果光标在文本下方,则默认为最后一个。如果光标在上面,则默认为第一个。
图片:
我的所有代码:
from PyQt5.QtWidgets import QTextEdit, QMainWindow, QApplication
from PyQt5.QtGui import QMouseEvent, QTextCursor
class Editor(QTextEdit):
def __init__(self):
super(Editor, self).__init__()
# make sure this widget is tracking the mouse position at all times
self.setMouseTracking(True)
def mouseMoveEvent(self, mouse_event: QMouseEvent) -> None:
if self.underMouse():
# create a QTextCursor at that position and select text
text_cursor = self.cursorForPosition(mouse_event.pos())
text_cursor.select(QTextCursor.WordUnderCursor)
word_under_cursor = text_cursor.selectedText()
print(word_under_cursor)
# replace substring with placeholder so that repeat occurrences aren't highlighted as well
selected_word_placeholder = self.replace_selected_text_with_placeholder(text_cursor)
word_under_cursor = '<span style="background-color: #FFFF00;font-weight:bold;">' + word_under_cursor + '</span>'
# replace the sentence with the new formatting
self.setHtml(self.toPlainText().replace(selected_word_placeholder, word_under_cursor))
def replace_in_html(self, old_string, new_string):
old_html = self.toHtml()
new_html = old_html.replace(old_string, new_string)
self.setHtml(new_html)
# use placeholder so that repeat occurrences of the word are not highlighted
def replace_selected_text_with_placeholder(self, text_cursor):
# 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 += '@'
text_cursor.insertText(word_placeholder)
return word_placeholder
def set_up(main_window):
title_editor = Editor()
title_editor.setText('Venda quente original xiaomi redmi airdots 2 tws fones de ouvido sem fio bluetooth fones controle ai gaming headset come')
main_window.setCentralWidget(title_editor)
main_window.show()
application = QApplication([])
window = QMainWindow()
set_up(window)
application.exec()
问题是由于 select()
总是试图 select 某些东西,即使鼠标实际上没有 在 文本块上, 它会得到最接近的单词。
解决方法是检查鼠标是否实际上在文本块的矩形内:
if self.underMouse():
pos = mouse_event.pos()
# create a QTextCursor at that position and select text
text_cursor = self.cursorForPosition(pos)
text_cursor.select(QTextCursor.WordUnderCursor)
start = text_cursor.selectionStart()
end = text_cursor.selectionEnd()
length = end - start
block = text_cursor.block()
blockRect = self.document().documentLayout().blockBoundingRect(block)
# translate by the offset caused by the scroll bar
blockRect.translate(0, -self.verticalScrollBar().value())
if not pos in blockRect:
# clear the selection since the mouse is not over the block
text_cursor.setPosition(text_cursor.position())
elif length:
# ensure that the mouse is actually over a word
startFromBlock = start - block.position()
textLine = block.layout().lineForTextPosition(startFromBlock)
endFromBlock = startFromBlock + length
x, _ = textLine.cursorToX(endFromBlock)
if pos.x() > blockRect.x() + x:
# mouse cursor is not over a word, clear the selection
text_cursor.setPosition(text_cursor.position())
请考虑,正如您对上一个问题的建议,使用 setHtml
突出显示文本 不是 一个好的选择,因为它总是会重置编辑内容;这不仅是性能问题,也是可用性问题(甚至忽略滚动条问题):setHtml
总是重置撤消堆栈,因此用户不能再使用撤消操作。