Изменения в специализированном интерфейсе QValidator и QML
Я изучаю Qt 5.5 и QML.
Каркас является мощным, и иногда есть много способов сделать одну вещь. Я думаю, что некоторые, вероятно, более эффективны, чем другие, иЯ хотел бы понять, когда и почему использовать один, а не другой.
Я хотел бы получить ответ, который может объяснить сделанный выбор. Поскольку я работаю с новым кодом, можно использовать синтаксис C ++ 11 и C ++ 14, если он полезен на стороне C ++.
Чтобы решить проблему это:
у меня естьTextField
связан с кнопкой, которая может выдвинутьFileDialog
, Я хочу текст вTextField
бытьred
когда он недействителен, и остался без изменений в противном случае (я установил егоgreen
потому что я не знаю, как получить цвет по умолчанию). ЗначениеTextField
должен использоваться на стороне C ++ и сохраняется при выходе из приложения.
Я закодировал версию, используя кастомQValidator
некоторые свойства на стороне QML, использованиеonTextChanged:
а такжеonValidatorChanged:
изменить цвет текста. Цвет текста устанавливается в соответствии со свойством (valid
) в QML, который устанавливается со стороны C ++ (в валидаторе). Чтобы установить свойство, C ++ должен найти по имени вызывающегоTextField
названныйdirectoryToSave
) потому что я еще не нашел способ передать сам объект в качестве аргумента.
Вот код QML, содержащийся вMainForm.ui.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:
чтобы быть уверенным, чтобы инициализировать интерфейс с правильным цветомпоиск по имени дерева, чтобы найти абонента (выглядит неэффективно; может не быть)спагетти-подобное кодирование среди нескольких экземпляров C ++ и частей QMLЯ могу думать о 5 других решениях:
избавиться от пользовательского валидатора и сохранить толькоonTextChanged:
потому что мы не можем избавиться от сигнализации со стороны QML. Большинство вещей сделано вMyClass
исправление Qt для реализациизначение свойства записывает перехватчик для чего-то еще, чемBehavior
(увидетьВот)регистрация типа C ++ для присоединения к объекту QML. (увидетьВот)зарегистрировать тип и использовать его как контроллер и структуру данных (в виде бобов) для последующей передачи на модель (см.Вот)используя сигналы вручную, как я уже делаю сsignalDirectoryChanged
Ну, как вы видите, плеторические способы делать вещи сбивают с толку, поэтому совет сэмпай ценится.
Полный исходный код доступенВот.