我正在尝试开发一个使用Qt的应用。我想让应用程序同时使用PySide
和PyQt4
。除了我的自定义QtGui.QValidator
类之外,我没有遇到任何重大的兼容性问题:
import sys
import os
import re
variant = 'PyQt4'
#variant = 'PySide'
print 'Python {}, {}'.format(sys.version, sys.platform)
# Using PyQt4:
if variant == 'PySide':
import PySide
from PySide import QtGui, QtCore
print 'PySide {}, Qt {}'.format(PySide.__version__, PySide.QtCore.__version__)
# Using PySide:
if variant == 'PyQt4':
from PyQt4 import QtGui, QtCore
from PyQt4.Qt import PYQT_VERSION_STR
print 'PyQt4 {}, Qt {}'.format(PYQT_VERSION_STR, QtCore.QT_VERSION_STR)
class ExpressionValidator(QtGui.QValidator):
def __init__(self, parent=None,):
QtGui.QValidator.__init__(self, parent)
self.states = {'invalid': QtGui.QValidator.Invalid,
'intermediate': QtGui.QValidator.Intermediate,
'acceptable': QtGui.QValidator.Acceptable,
}
self.regX_expression = re.compile('([0-9.eEpiPI+-/*\(\))\^]*)')
def returnState(self, state, text, pos):
if state == 'acceptable':
color = '#00cc00' # green
elif state == 'intermediate':
color = '#fff79a' # yellow
else:
color = '#f6989d' # red
self.parent().setStyleSheet('QLineEdit {{ background-color: {} }}'.format(color))
if variant == 'PySide':
return self.states[state]
else:
return (self.states[state], pos)
def validate(self, textInput, pos):
# Check text, return state
matches = self.regX_expression.findall(textInput)
if matches and len(matches[0]) == len(textInput):
if len(textInput) >0 and str(textInput)[-1] in '+-/*^':
self.parent().setToolTip('Expression Needs Finished.')
return self.returnState('intermediate', textInput, pos)
else:
return self.returnState('acceptable', textInput, pos)
else:
return self.returnState('invalid', textInput, pos)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
app.setStyle('GTK')
mainWindow = QtGui.QMainWindow()
lineEdit = QtGui.QLineEdit()
lineEdit.setValidator(ExpressionValidator(lineEdit))
mainWindow.setCentralWidget(lineEdit)
mainWindow.show()
app.exec_()
app.deleteLater()
sys.exit()
我需要在returnState
函数中放置健壮的代码。我是否只需要在多个系统上测试它并继续构建我的if
语句?
到目前为止,这些调用都有效:
Python 2.7.6,Windows 7,PyQt4 4.10.4,Qt 4.8.6:
return (self.states[state], pos)
Python 2.7.6,Windows 7,PySide 1.2.1,Qt 4.8.6:
return self.states[state]
return (self.states[state], text, pos)
Python 2.7.8,OpenSuse(linux2),PyQt4 4.10.4,Qt 4.8.5:
return (self.states[state], pos)
Python 2.7,OpenSuse(linux2),PyQt4 4.8.3,Qt 4.7.1:
return (self.states[state], pos)
Python 2.7.8,OpenSuse(linux2),PySide 1.2.1,Qt 4.8.5:
return self.states[state]
return (self.states[state], text, pos)
如何为正确的呼叫解析help(QtGui.QValidator.validate)
并基于此动态创建回复呼叫呢?
答案 0 :(得分:2)
<强>更新强>:
正如Onlyjus在评论中指出的那样,确切的行为因使用which PyQt api而异。
使用v1 api,input
参数将是QString
,这意味着它可以就地修改(这就是C ++ api的工作方式)。但是对于v2 api,input
参数是一个不可变的python字符串,因此必须返回它。所以实际的签名是:
# v1 api (default for Python 2)
QValidator.validate(QString, int) -> (QValidator.State, int)
# v2 api (default for Python 3)
QValidator.validate(str, int) -> (QValidator.State, str, int)
这些(和许多其他)差异记录在PyQt4文档的PyQt4 and Python v3部分。
PySide的行为虽然有点奇怪,但至少是可以预测的。它将允许返回所有任意长度的元组,只要前三个值的类型与C ++签名相符。所以这些都可行:
return (QValidator.State,)
return (QValidator.State, "string")
return (QValidator.State, "string", 10)
return (QValidator.State, "string", 10, "foo", 60, "blah")
但是这种灵活性在当前情况下都没有帮助,因为在使用v1 api时,PyQt4无法匹配任何这些变体。
看起来唯一真正的解决方案是切换到v2 api(至少为QString
)。
但是,如果你不能这样做,那么最好的妥协就是使用与你正在做的非常相似的东西:
if variant == 'PyQt4':
# if necessary, modify text in place here
# rather than returning it
return (self.states[state], pos)
else:
return (self.states[state], text, pos)
这应该适用于PySide,PyQt4以及PyQt5(如果你曾选择为它提供支持)。