免责声明:我是Qt / PyQt5的相对新手,所以欢迎您提供任何建议。
我正在尝试在PyQt5表单上正确实施验证,以向用户提供适当的反馈。
我当前的测试代码是:
from __future__ import annotations
import typing
from PyQt5.QtCore import QTimer, QRegularExpression
from PyQt5.QtGui import QValidator, QRegularExpressionValidator
from PyQt5.QtWidgets import QApplication, QWidget, QLineEdit, QVBoxLayout
class MyValidator(QRegularExpressionValidator):
states = {
QValidator.Invalid: 'invalid',
QValidator.Intermediate: 'intermediate',
QValidator.Acceptable: 'acceptable'
}
def validate(self, text: str, pos: int) -> typing.Tuple[QValidator.State, str, int]:
def set_selector(s):
p = self.parent()
p.setProperty('selector', s)
p.style().unpolish(p)
p.style().polish(p)
p.update()
state, text, pos = super(MyValidator, self).validate(text, pos)
selector = MyValidator.states[state]
if selector == 'invalid':
sel = self.parent().property('selector')
QTimer.singleShot(1000, lambda: set_selector(sel))
set_selector(selector)
return state, text, pos
class Widget(QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.le = QLineEdit()
regexp = QRegularExpression(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}')
self.le.setValidator(MyValidator(regexp, self.le))
self.le.setProperty('selector', 'none')
lay = QVBoxLayout(self)
lay.addWidget(self.le)
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
app.setStyleSheet('''\
*[selector="invalid"] {border-radius: 3px; border: 1px solid red;}
*[selector="intermediate"] {border-radius: 3px; border: 1px solid gold;}
*[selector="acceptable"] {border-radius: 3px; border: 1px solid green;}
''')
w = Widget()
w.show()
sys.exit(app.exec_())
我有以下三个“问题”(严格要求恕我直言):
QLineEdit
被忽略,我被迫重新定义border-color: whatever;
边框。同样,这既丑陋又(更重要的是!)是错误的,因为重新创建的边框与原始边框完全不相同。这似乎是由于Qt并未“默认”使用CSS;请参阅底部的Note2。鉴于上面的问题是:这是实现视觉反馈的正确方法还是还有其他(可能更清洁)的方法?
注意:我理解这个问题有一定数量的基于意见的方面,但是我要求提供统一的“最佳实践”(如果有)。
注2:似乎(欢迎有识之士进行澄清!)Qt默认情况下不使用CSS。这与其他语言/工具包(例如:java / javaFX)不同,在其他语言/工具包中,渲染总是由CSS驱动,并且用户“仅”更新/添加到实际存在的“默认CSS”中。
我的理解(可能是错误的)是边框(或其他任何图形元素)是“默认”“手工绘制”(在c ++中,直接在画布上绘制),而 IFF 用户定义了 relevant CSS元素称为单独的渲染引擎,因此渲染可能会有所不同。
在“边框”的特定情况下,我无法正确定义与“默认”图形相同的CSS边框;如您所见,运行该代码段会在内部默认边框内绘制一个像素;我无法“修复”它。
我对上面的代码感到非常满意,但是任何加深我对QWidget与CSS交互以及相关问题的理解的“答案”都会被接受。
正如@ekhumoro在评论中指出的,我没有使用Dynamic Properties的Qt批准语法。 关于这两个注意事项:
style().polish()
实际上解决了我的垂直边框尺寸问题。style().unpolish()
/ style().polish()
不能 正常工作...部分。对于“静态”边界(Intermediate
和Acceptable
验证程序状态),它实际上可以正常工作,但对于“瞬态”(Invalid
)边界则不能很好地工作。欢迎有识之士。
我已按照@ekhumoro(非常感谢!)的建议将代码段更新为最终版本(可以正常工作)。
对我来说,问题已解决。我将开放该问题以备将来参考。