Python 移动光标时,QTextEdit中的drawRect()无法正常工作
我的QTextEdit的paintEvent中有一个简单的代码,它在当前选定的QTextBlock下绘制一个灰色框:Python 移动光标时,QTextEdit中的drawRect()无法正常工作,python,pyqt,pyqt5,qtextedit,Python,Pyqt,Pyqt5,Qtextedit,我的QTextEdit的paintEvent中有一个简单的代码,它在当前选定的QTextBlock下绘制一个灰色框: def paintEvent(self, ev): painter = QPainter() painter.begin(self.viewport()) currentPos = self.textCursor().position() block = self.document().findBlock(currentPos) rect
def paintEvent(self, ev):
painter = QPainter()
painter.begin(self.viewport())
currentPos = self.textCursor().position()
block = self.document().findBlock(currentPos)
rect = self.document().documentLayout().blockBoundingRect(block)
margin = self.document().documentMargin()
rect.setTopLeft(QPoint(int(rect.topLeft().x()-margin), int(rect.topLeft().y()-margin)))
rect.setBottomRight(QPoint(int(rect.bottomRight().x()+margin), int(rect.bottomRight().y())))
painter.fillRect(rect, QBrush(QColor(10, 10, 10,20)))
if self._last_selected_block and (self._last_selected_block != block):
lastrect = self.document().documentLayout().blockBoundingRect(self._last_selected_block) #clean up artifacts
painter.eraseRect(lastrect)
painter.fillRect(self.contentsRect(), QBrush(QColor(123, 111, 145, 80))) #background color
painter.end()
self._last_selected_block = block
super().paintEvent(ev)
(注意,“清理工件”线会删除在先前选定的QTextBlock区域中绘制的任何内容,因为如果在最后一个块中绘制了文本,则会在最后一个块下保留一条细灰线。这可能是相关的。)
其效果是:
但是,当通过单击另一行移动光标时,会发生以下情况:
下一个矩形仅在光标移动到的字符周围部分绘制,而上一个矩形不会被擦除。橡皮擦Rect()似乎无法删除此工件。当继续键入或换行时,一切都会恢复正常(当通过换行更改行时,不会出现此问题)。我已经确认,当光标移动时会调用paintEvent(),并且要绘制的矩形的宽度不会改变。这里发生了什么?出于优化的原因,Qt只尝试重新绘制小部件中实际需要更新的部分 在QTextEdit的情况下,这意味着只有“插入符号”在移动之前(通过编辑,使用箭头键或鼠标)和现在所在的部分将被更新,而忽略所有其他内容 在您的情况下,这显然是一个问题,因为它只会更新小部件的一小部分,从而不会重新绘制先前高亮显示的块,以显示您的自定义背景 解决方案是跟踪当前光标位置,并在块更改后立即正确更新上一个块和新块。这是通过使用a调用
update()
,通过合并当前块边界rect和上一个块边界rect(如果有)创建;这将安排一次更新,只重新绘制该区域内的内容(这是QTextEdit通常所做的,但我们将其扩展到整个块区域和上一个区域)
请注意,我已经完全更改了paintEvent的实现,因为它基本上是不必要的,原因如下:
- 文件的边距不应用于块李>
- 背景画不考虑滚动区域背景(稍后对此更详细);<李>
- 无需“擦除”上一个块矩形:我们的
调用包括该区域,由于它不是当前块,因此背景将被(重新)绘制在那里李>update()
- 绘制事件中不应更新当前块李>
Base
调色板角色。结果是,你的背景色不是你所相信的,而是由底色(通常是接近白色)和背景组成。为了确保背景正是您想要的颜色,您必须使用该
Base
角色的颜色更新小部件上的调色板,该颜色也应该是不透明的颜色(否则将使用窗口
颜色角色合成)
请提供一份
class TextEdit(QtWidgets.QTextEdit):
_last_selected_block = None
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
palette = self.palette()
palette.setColor(palette.Base, QtGui.QColor(203, 200, 210))
self.setPalette(palette)
self.cursorPositionChanged.connect(self.trackCursorPosition)
def trackCursorPosition(self):
block = self.textCursor().block()
currentRect = self.document().documentLayout().blockBoundingRect(block)
updateRegion = QtGui.QRegion(currentRect.toRect())
if self._last_selected_block and self._last_selected_block != block:
oldRect = self.document().documentLayout().blockBoundingRect(
self._last_selected_block)
updateRegion |= QtGui.QRegion(oldRect.toRect())
self._last_selected_block = block
self.viewport().update(updateRegion)
def paintEvent(self, ev):
painter = QtGui.QPainter(self.viewport())
block = self.textCursor().block()
rect = self.document().documentLayout().blockBoundingRect(block)
painter.fillRect(rect, QtGui.QColor(10, 10, 10,20))
super().paintEvent(ev)