setCursor(QCursor(Qt.ForbiddenCursor)) 不适用于禁用的 QLineEdit

问题描述 投票:0回答:2

我正在尝试将禁止光标设置为动态启用/禁用的行编辑。但它似乎根本不起作用。

from PySide6.QtCore import Qt
from PySide6.QtGui import QCursor

def toggle_line_edit(self, switch_type: SwitchType):
    match switch_type:
        case SwitchType.One:
            self.ui.line_edit.setCursor(QCursor(Qt.ForbiddenCursor))
            self.ui.line_edit.setDisabled(True)
        case SwitchType.Two:
            self.ui.line_edit.setCursor(QCursor(Qt.IBeamCursor))
            self.ui.line_edit.setDisabled(False)

有什么我想念的吗?

python qt pyside pyside6
2个回答
1
投票

这不仅仅是关于 QLineEdit:any 禁用的小部件在禁用时不会显示其自定义光标。

这是有正当理由的,至少从一般的角度来看:禁用的小部件不提供任何用户交互(键盘和鼠标),因此没有必要显示不同的光标让用户相信小部件是,事实上,启用。

请注意,虽然您可以将 QLineEdit 设置为只读,但这不会阻止某种程度的交互:例如,它仍然可以使用鼠标甚至键盘提供文本选择(在单击或使用 到达后)选项卡).

一个可能的替代方案是完全阻止任何交互;可以通过将策略设置为

NoFocus
来清除焦点功能,而鼠标交互需要忽略 all 鼠标事件。为了简单起见,最好使用子类:

class FakeDisabledLineEdit(QLineEdit):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setCursor(Qt.ForbiddenCursor)
        self.setFocusPolicy(Qt.NoFocus)

    def event(self, event):
        if isinstance(event, QMouseEvent):
            return True
        return super().event(event)

注意:您似乎正在使用从 Designer 创建的 UI,因此,为了在您的 UI 中使用这样的子类,您需要升级小部件。考虑对这个主题进行一些研究,从我的这篇文章开始。

唯一的问题可能是小部件仍然显示为已启用,因此可能的(脏)解决方法是在绘画事件中临时设置

WA_Disabled
标志。这将使 Qt believe 小部件被禁用,并让样式相应地绘制其内容:

class FakeDisabledLineEdit(QLineEdit):
    # ... as above

    def paintEvent(self, event):
        enabled = self.isEnabled()
        if enabled:
            self.setAttribute(Qt.WA_Disabled, True)
        super().paintEvent(event)
        if enabled:
            self.setAttribute(Qt.WA_Disabled, False)

根据评论编辑

由于您想显示一个可见的“提示”,该字段实际上可以根据 UI 的其他元素启用,因此还有另一种可能性。

您可以将行编辑设置为只读,并使用

placeholderText
属性来显示该提示;如上所述禁用焦点将阻止任何编辑,直到行编辑变为“启用”。

基本实现可以覆盖

setReadOnly()
并在调用基本实现后执行其中所需的所有操作:

class FakeDisabledLineEdit(QLineEdit):
    def setReadOnly(self, readOnly):
        super().setReadOnly(readOnly)
        if readOnly:
            self.setCursor(Qt.ForbiddenCursor)
            self.setFocusPolicy(Qt.NoFocus)
            self.clear()
            self.setPlaceholderText('Click the checkbox to enable')
        else:
            self.setCursor(Qt.IBeamCursor)
            self.setFocusPolicy(Qt.StrongFocus)
            self.setPlaceholderText('')

只要您do有该字段的占位符文本,即使您想恢复文本,这也可能成为问题。

这需要更全面的方法,但它仍然可行。下面是一个示例,它显示了所需的行为,同时允许“正常”占位符文本 恢复先前设置的文本:

class FakeDisabledLineEdit(QLineEdit):
    _text = ''
    _readOnlyText = ''
    _placeholderText = ''
    def __init__(self, *args, **kwargs):
        if 'readOnlyText' in kwargs:
            self._readOnlyText = kwargs.pop('readOnlyText')
        super().__init__(*args, **kwargs)
        self._text = self.text()
        self._placeholderText = self.placeholderText()
        if self.isReadOnly() and self._readOnlyText:
            self.setReadOnly(True)

    @Property(str)
    def readOnlyText(self):
        return self._readOnlyText

    @readOnlyText.setter
    def readOnlyText(self, text):
        if self._readOnlyText != text:
            self._readOnlyText = text
            if self.isReadOnly():
                super().setPlaceholderText(text or self._placeholderText)

    def setReadOnlyText(self, text):
        self.readOnlyText = text

    def setPlaceholderText(self, text):
        self._placeholderText = text
        if self.isReadOnly():
            text = self._readOnlyText
        super().setPlaceholderText(text)

    def setReadOnly(self, readOnly):
        super().setReadOnly(readOnly)
        if readOnly:
            with QSignalBlocker(self):
                self.setCursor(Qt.ForbiddenCursor)
                self.setFocusPolicy(Qt.NoFocus)
                self._text = self.text()
                self.clear()
            placeholderText = self._readOnlyText
        else:
            self.setCursor(Qt.IBeamCursor)
            self.setFocusPolicy(Qt.StrongFocus)
            self.setText(self._text)
            placeholderText = self._placeholderText
        super().setPlaceholderText(placeholderText)

    def setText(self, text):
        if self._text == text:
            return
        self._text = text
        if self.isReadOnly():
            with QSignalBlocker(self): # avoid textChanged signal emit
                super().setText(self._readOnlyText)
        else:
            super().setText(text)

这是一个显示上述工作原理的测试:

app = QApplication([])
win = QWidget()
placeholderEdit = QLineEdit('Placeholder text if editable', 
    placeholderText='Set placeholder')
readOnlyEdit = QLineEdit('Click the checkbox to enable', 
    placeholderText='Read only text')
check = QCheckBox('Enable field')
field = FakeDisabledLineEdit(
    readOnly=True, placeholderText=placeholderEdit.text(), 
    readOnlyText=readOnlyEdit.text())

layout = QVBoxLayout(win)
layout.addWidget(placeholderEdit)
layout.addWidget(readOnlyEdit)
layout.addWidget(check)
layout.addWidget(QFrame(frameShape=QFrame.HLine))
layout.addWidget(QLabel('Custom field:'))
layout.addWidget(field)

placeholderEdit.textChanged.connect(field.setPlaceholderText)
readOnlyEdit.textChanged.connect(field.setReadOnlyText)
check.toggled.connect(lambda checked: field.setReadOnly(not checked))

win.show()

app.exec()

0
投票

我试用了 QT Designer 并检查了它生成的代码。您似乎无法为禁用的 QLineEdit 设置光标。所以这似乎是解决方案:

self.my_line_edit.setEnabled(True)
self.my_line_edit.setCursor(QCursor(Qt.ForbiddenCursor))
self.my_line_edit.setMouseTracking(True)
self.my_line_edit.setFrame(False)
self.my_line_edit.setReadOnly(True)
© www.soinside.com 2019 - 2024. All rights reserved.