隐藏小部件后绘画被剪掉

最后发布: 2020-07-09


问题

我试图在QHeaderView中添加一个QLineEdit,这样我就可以从QSortFilterProxyModel中过滤单词。

当用户点击图标时,QLineEdit在右侧打开,覆盖了搜索按钮,标题移动到标题的左侧。

当editingFinished信号发出时,QLineEdit保存当前的文本,而paintSection则像委托人一样,将标题和QLineEdit画在页眉上,如果QLineEdit为空,则搜索结束,而paintSection只是回到第一个布局,只有标题和搜索图标。

然而,在我的代码中,当搜索结束时,paintSection只刷新被QLineEdit覆盖的部分,而没有被覆盖的部分保持不变,直到某种事件触发重新绘制。

Behavior

我对Qt的paintter系统不是很熟悉,所以我对这个问题非常沮丧。

这是我目前为HeaderView编写的代码。HeaderData只是一个简单的类,里面有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
python pyqt qpainter qheaderview
回答

好吧,我做了一些事件过滤之类的东西,发现当 editingFinished 谓,只 layoutRequest 事件引发的,因为隐藏了编辑器小部件,这个事件当然没有重新绘制背景。

所以我尝试添加 repaintupdate 到了 editingFinished 函数,但它们根本没有调用任何事件。当我调用它们 之前 小部件被隐藏,现在他们触发了 paintEvent但只有我的小部件放置的区域。

之后,我找到了一个插槽 updateSection 在Qt的Python文档中,它确实有效!我不知道它在C++ Qt上是否有效,因为我在C++ Qt文档中找不到相同的插槽。我不知道在C++ Qt上是否能用,因为我在C++ Qt文档中找不到同样的槽点。

我还是很好奇为什么当我使用 "重绘 "或 "更新 "时,头没有更新,但这是另一个问题。