我正在学习Qt 5.5和QML。
框架很强大,有时候有很多方法可以做一件事。我认为有些可能比其他人更有效率,而且我想知道何时以及为何使用一个而不是另一个。 我想要一个可以解释所做出的选择的答案。当我使用新代码时,如果在C ++端有用,可以使用C ++ 11和C ++ 14语法。
要解决的问题是:
我有一个TextField
链接到一个可以弹出FileDialog
的按钮。我希望TextField
中的文字无效时为red
,否则保持不变(我将其设置为green
因为我不知道如何获取“默认”颜色)。 TextField
的值将在C ++端使用,并在应用程序退出时保持不变。
我使用自定义QValidator
编写了一个版本,QML方面的一些属性,使用onTextChanged:
和onValidatorChanged:
来修改文本的颜色。根据Q ++中的属性(valid
)设置文本颜色,该属性是从C ++端(在验证器中)设置的。要设置属性,C ++必须按名称查找调用者(TextField
名为directoryToSave
),因为我还没有找到将对象本身作为参数传递的方法。
以下是MainForm.ui.qml
中包含的QML代码:
TextField {
property bool valid: false
id: directoryToSave
objectName: 'directoryToSave'
Layout.fillWidth:true
placeholderText: qsTr("Enter a directory path to save to the peer")
validator: directoryToSaveValidator
onTextChanged: if (valid) textColor = 'green'; else textColor = 'red';
onValidatorChanged:
{
directoryToSave.validator.attachedObject = directoryToSave.objectName;
// forces validation
var oldText = text;
text = text+' ';
text = oldText;
}
}
自定义验证码:
class QDirectoryValidator : public QValidator
{
Q_OBJECT
Q_PROPERTY(QVariant attachedObject READ attachedObject WRITE setAttachedObject NOTIFY attachedObjectChanged)
private:
QVariant m_attachedObject;
public:
explicit QDirectoryValidator(QObject* parent = 0);
virtual State validate(QString& input, int& pos) const;
QVariant attachedObject() const;
void setAttachedObject(const QVariant &attachedObject);
signals:
void attachedObjectChanged();
};
与这些定义相关:
QVariant QDirectoryValidator::attachedObject() const
{
return m_attachedObject;
}
void QDirectoryValidator::setAttachedObject(const QVariant &attachedObject)
{
if (attachedObject != m_attachedObject)
{
m_attachedObject = attachedObject;
emit attachedObjectChanged();
}
}
QValidator::State QDirectoryValidator::validate(QString& input, int& pos) const
{
QString attachedObjectName = m_attachedObject.toString();
QObject *rootObject = ((LAACApplication *) qApp)->engine().rootObjects().first();
QObject *qmlObject = rootObject ? rootObject->findChild<QObject*>(attachedObjectName) : 0;
// Either the directory exists, then it is _valid_
// or the directory does not exist (maybe the string is an invalid directory name, or whatever), and then it is _invalid_
QDir dir(input);
bool isAcceptable = (dir.exists());
if (qmlObject) qmlObject->setProperty("valid", isAcceptable);
return isAcceptable ? Acceptable : Intermediate;
}
m_attachedObject
是QVariant
,因为我最初希望引用QML实例而不是其名称。
由于验证器仅关注验证,因此它不包含有关其验证的数据的任何状态
因为我必须得到TextField
的值才能在应用程序中执行某些操作,所以我构建了另一个类以在更改时保存值:MyClass
。我将其视为我的控制器。目前,我将数据直接存储在应用程序对象中,可以将其视为我的模型。这将在未来发生变化。
class MyClass : public QObject
{
Q_OBJECT
public:
MyClass() {}
public slots:
void cppSlot(const QString &string) {
((LAACApplication *) qApp)->setLocalDataDirectory(string);
}
};
控制器MyClass
和验证器QDirectoryValidator
的实例是在应用程序初始化期间使用以下代码创建的:
MyClass * myClass = new MyClass;
QObject::connect(rootObject, SIGNAL(signalDirectoryChanged(QString)),
myClass, SLOT(cppSlot(QString)));
//delete myClass;
QValidator* validator = new QDirectoryValidator();
QVariant variant;
variant.setValue(validator);
rootObject->setProperty("directoryToSaveValidator", variant);
//delete
仅用于发现删除实例时发生的情况。
main.qml
将事物联系在一起:
ApplicationWindow {
id: thisIsTheMainWindow
objectName: "thisIsTheMainWindow"
// ...
property alias directoryToSaveText: mainForm.directoryToSaveText
property var directoryToSaveValidator: null
signal signalDirectoryChanged(string msg)
// ...
FileDialog {
id: fileDialog
title: "Please choose a directory"
folder: shortcuts.home
selectFolder: true
onAccepted: {
var url = fileDialog.fileUrls[0]
mainForm.directoryToSaveText = url.slice(8)
}
onRejected: {
//console.log("Canceled")
}
Component.onCompleted: visible = false
}
onDirectoryToSaveTextChanged: thisIsTheMainWindow.signalDirectoryChanged(directoryToSaveText)
}
最后,MainForm.ui.qml胶水:
Item {
// ...
property alias directoryToSavePlaceholderText: directoryToSave.placeholderText
property alias directoryToSaveText: directoryToSave.text
// ...
}
我不满意:
onValidatorChanged:
中的污垢,以确保使用正确的颜色初始化UI 我可以想到其他5个解决方案:
onTextChanged:
因为我们无法摆脱QML端的信令。大部分内容都在MyClass
Behavior
之外的其他内容实现属性值写入拦截器(请参阅here)signalDirectoryChanged
嗯,正如你所看到的,做事的多种方式令人困惑,所以赞赏了senpai的建议。
完整的源代码here。