隐藏小部件后的绘画被剪裁
Painting after hiding a widget get clipped
我正在尝试将 QLineEdit 添加到 QHeaderView 以便我可以从 QSortFilterProxyModel 过滤单词。
起初,header 可能只显示标题和搜索图标。
当用户单击该图标时,QLineEdit 在右侧打开,覆盖搜索按钮,标题移动到 header 的左侧。
随着 editingFinished 信号的发出,QLineEdit 保存当前文本,并且 paintSection 在 header 上绘制标题和 QLineEdit,就像代表所做的那样。
如果 QLineEdit 为空,则搜索结束并且 paintSection 返回到第一个布局,只有带有搜索图标的标题。
然而,在我的代码中,当搜索结束时,paintSection 只刷新被 QLineEdit 覆盖的部分,而没有被它覆盖的部分保持不变,直到某种事件触发重新绘制。
我对Qt的painter系统不是很友好,所以我对这个问题很郁闷。
这是我当前的 HeaderView 代码。不包括负责打开 QLineEdit 的功能。
Header数据只是一个简单的 class,其中包含 Header.
的信息
class HeaderView(QHeaderView):
def __init__(self, orientation=Qt.Horizontal):
super().__init__(orientation)
self.setSectionsMovable(True)
self.setSectionsClickable(True)
self.editIndex = -1
self.headers = []
self.searchImage = QImage('search.png')
h = HeaderData()
self.headers.append(h)
self.line = QLineEdit(self.viewport())
self.line.hide()
self.line.editingFinished.connect(self.editingFinished)
self.line.textChanged.connect(self.textChanged)
def paintSection(self, painter, rect, logicalIndex):
if self.headers[logicalIndex].search is True: # currently searching
# Left half is filled with title
text_rect = QRect(rect.x(), rect.y(), rect.width()//2, rect.height())
painter.drawText(text_rect, Qt.AlignCenter, self.model().headerData(logicalIndex, self.orientation(), Qt.DisplayRole))
# Right half is area for QLineEdit
rel_pos = painter.deviceTransform().map(QPoint(rect.x(), rect.y()))
line_rect = QRect(rect.width() // 2, 0, rect.width() // 2, rect.height())
line_pos = rel_pos + line_rect.topLeft()
device = painter.device()
w = QLineEdit()
w.resize(line_rect.size())
w.setText(self.headers[logicalIndex].line_text)
w.render(device, line_pos, QRegion(0, 0, w.width(), w.height()), QWidget.RenderFlag.DrawChildren)
self.headers[logicalIndex].line_rect = line_rect
else: # not searching
painter.drawText(rect, Qt.AlignCenter, self.model().headerData(logicalIndex, self.orientation(), Qt.DisplayRole))
point = rect.topLeft()
offset = QPoint(rect.width() - rect.height(), rect.height()//4)
icon_size = QSize(rect.height()//2, rect.height()//2))
painter.drawImage(point + offset, self.searchImage.scaled(icon_size)
self.headers[logicalIndex].search_rect = QRect(offset, icon_size)
def openEditor(self, index):
self.editIndex = index
line_rect = self.headers[index].line_rect.translated(self.sectionViewportPosition(index), 0)
self.line.setGeometry(line_rect)
self.line.setText(self.headers[index].line_text)
self.line.setVisible(True)
def textChanged(self, text):
self.headers[self.editIndex].line_text = text
def editingFinished(self):
if self.line.text() == '':
self.headers[self.editIndex].search = False
self.line.hide()
self.headers[self.editIndex].line_text = self.line.text()
self.editIndex = -1
好的,我做了一些事件过滤和其他事情,发现当 editingFinished
被调用时,只有 layoutRequest
事件引发,因为隐藏了编辑器小部件,而这个事件肯定没有'重绘背景。
所以我尝试在editingFinished
函数的末尾添加repaint
或update
,但它们根本没有调用任何事件。当我调用它们时 before 小部件被隐藏,现在它们触发了 paintEvent
,但只触发了我的小部件所在的区域。
在那之后,我在 Qt 中找到了一个插槽 updateSection
用于 Python 文档,它确实有效!我不确定它是否适用于 C++ Qt,因为我在 C++ Qt 文档中找不到相同的插槽。
我还是很好奇为什么我用'repaint'或'update'时header没有更新,但那是另一个问题了。
我正在尝试将 QLineEdit 添加到 QHeaderView 以便我可以从 QSortFilterProxyModel 过滤单词。
起初,header 可能只显示标题和搜索图标。 当用户单击该图标时,QLineEdit 在右侧打开,覆盖搜索按钮,标题移动到 header 的左侧。
随着 editingFinished 信号的发出,QLineEdit 保存当前文本,并且 paintSection 在 header 上绘制标题和 QLineEdit,就像代表所做的那样。 如果 QLineEdit 为空,则搜索结束并且 paintSection 返回到第一个布局,只有带有搜索图标的标题。
然而,在我的代码中,当搜索结束时,paintSection 只刷新被 QLineEdit 覆盖的部分,而没有被它覆盖的部分保持不变,直到某种事件触发重新绘制。
我对Qt的painter系统不是很友好,所以我对这个问题很郁闷。
这是我当前的 HeaderView 代码。不包括负责打开 QLineEdit 的功能。 Header数据只是一个简单的 class,其中包含 Header.
的信息class HeaderView(QHeaderView):
def __init__(self, orientation=Qt.Horizontal):
super().__init__(orientation)
self.setSectionsMovable(True)
self.setSectionsClickable(True)
self.editIndex = -1
self.headers = []
self.searchImage = QImage('search.png')
h = HeaderData()
self.headers.append(h)
self.line = QLineEdit(self.viewport())
self.line.hide()
self.line.editingFinished.connect(self.editingFinished)
self.line.textChanged.connect(self.textChanged)
def paintSection(self, painter, rect, logicalIndex):
if self.headers[logicalIndex].search is True: # currently searching
# Left half is filled with title
text_rect = QRect(rect.x(), rect.y(), rect.width()//2, rect.height())
painter.drawText(text_rect, Qt.AlignCenter, self.model().headerData(logicalIndex, self.orientation(), Qt.DisplayRole))
# Right half is area for QLineEdit
rel_pos = painter.deviceTransform().map(QPoint(rect.x(), rect.y()))
line_rect = QRect(rect.width() // 2, 0, rect.width() // 2, rect.height())
line_pos = rel_pos + line_rect.topLeft()
device = painter.device()
w = QLineEdit()
w.resize(line_rect.size())
w.setText(self.headers[logicalIndex].line_text)
w.render(device, line_pos, QRegion(0, 0, w.width(), w.height()), QWidget.RenderFlag.DrawChildren)
self.headers[logicalIndex].line_rect = line_rect
else: # not searching
painter.drawText(rect, Qt.AlignCenter, self.model().headerData(logicalIndex, self.orientation(), Qt.DisplayRole))
point = rect.topLeft()
offset = QPoint(rect.width() - rect.height(), rect.height()//4)
icon_size = QSize(rect.height()//2, rect.height()//2))
painter.drawImage(point + offset, self.searchImage.scaled(icon_size)
self.headers[logicalIndex].search_rect = QRect(offset, icon_size)
def openEditor(self, index):
self.editIndex = index
line_rect = self.headers[index].line_rect.translated(self.sectionViewportPosition(index), 0)
self.line.setGeometry(line_rect)
self.line.setText(self.headers[index].line_text)
self.line.setVisible(True)
def textChanged(self, text):
self.headers[self.editIndex].line_text = text
def editingFinished(self):
if self.line.text() == '':
self.headers[self.editIndex].search = False
self.line.hide()
self.headers[self.editIndex].line_text = self.line.text()
self.editIndex = -1
好的,我做了一些事件过滤和其他事情,发现当 editingFinished
被调用时,只有 layoutRequest
事件引发,因为隐藏了编辑器小部件,而这个事件肯定没有'重绘背景。
所以我尝试在editingFinished
函数的末尾添加repaint
或update
,但它们根本没有调用任何事件。当我调用它们时 before 小部件被隐藏,现在它们触发了 paintEvent
,但只触发了我的小部件所在的区域。
在那之后,我在 Qt 中找到了一个插槽 updateSection
用于 Python 文档,它确实有效!我不确定它是否适用于 C++ Qt,因为我在 C++ Qt 文档中找不到相同的插槽。
我还是很好奇为什么我用'repaint'或'update'时header没有更新,但那是另一个问题了。