我正在尝试将禁止光标设置为动态启用/禁用的行编辑。但它似乎根本不起作用。
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)
有什么我想念的吗?
这不仅仅是关于 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()
我试用了 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)