Чтобы достичь той же функциональности, что и в моем приложении WPF, здесь я создал Q_INVOKABLE
с именем isNewPlotValid
и вызываю его всякий раз, когда изменяется содержимое моих полей:
ColumnLayout{
LineField{
label: "Name"
text: addContext.newPlot.name
onTextChanged: {
addContext.newPlot.name = text
button.isEnabled = addContext.isNewPlotValid()
}
}
AreaField{
label: "Address"
Layout.fillHeight: true
text: addContext.newPlot.description
onTextChanged: {
addContext.newPlot.description = text
button.isEnabled = addContext.isNewPlotValid()
}
}
PathButton{
id: button
pathData: C.addIcon
onClicked: addContext.addNewPlot()
}
}
It делает то, что я хотел, НО я должен иметь button.isEnabled = addContext.isNewPlotValid()
в каждом поле! Есть ли какой-либо ярлык?
EDIT
В папке Model
моего проекта у меня есть только файлы заголовков, которые определяют структуру данных (Q_PROPERTY) следующим образом:
class Plot : public QObject{
Q_OBJECT
Property(int, id)
Property(QString, name)
Property(QString, description)
};
ничего больше для любого типа Model
, кроме enum
, а макрос Property
создает все необходимые Q-наполнители для Model
следующим образом:
#define Property(QType, name) \
Q_PROPERTY(QType name READ name WRITE set##name NOTIFY name##Changed) \
public: \
QType& name() {return m_##name;} \
void set##name(QType value){if(m_##name != value){m_##name = value; emit name##Changed();}} \
Q_SIGNAL void name##Changed(); \
private: \
QType m_##name;
All мои ViewModels
находятся в отдельной папке под названием ViewModel
. У меня есть одна ViewModel с именем AddVM
, и это Property
типа Plot*
:
class AddVM : public QObject
{
...
Property(Plot*, newPlot)
...
};
Теперь это будет уведомлять пользовательский интерфейс только при изменении указателя. Итак, мне нужно создать еще один slot
, который делает это:
void AddVM::onPlotChanged()
{
emit newPlotChanged();
}
и соединить сигналы nameChanged и descriptionChanged newPlot
с этим слотом onPlotChanged
? Я пробовал соединить оба способа таким образом:
QObject::connect(m_newPlot, &AddVM::m_newPlot->nameChanged, this, &AddVM::onPlotChanged);
QObject::connect(m_newPlot, &AddVM::m_newPlot->descriptionChanged, this, &AddVM::onPlotChanged);
НО второй аргумент, &AddVM::m_newPlot->nameChanged
и &AddVM::m_newPlot->descriptionChanged
, в обеих строках говорит:
не может создать non -константный указатель на функцию-член.
EDIT
Таким образом, решение состоит в том, чтобы иметь их в AddVM
:
class AddVM : public QObject
{
Property(Plot*, newPlot)
Property(bool, isNewPlotValid)
private:
bool hasMatch(QString& text);
void hookupSignalAndSlots();
private slots:
void onPlotChanged();
};
они в cpp
:
bool AddVM::hasMatch(QString &text)
{
foreach(auto x, mvm->plots())
if(x->name() == text) return true;
return false;
}
void AddVM::hookupSignalAndSlots()
{
QObject::connect(m_newPlot, &Plot::nameChanged, this, &AddVM::onPlotChanged);
QObject::connect(m_newPlot, &Plot::descriptionChanged, this, &AddVM::onPlotChanged);
}
void AddVM::onPlotChanged()
{
if(!newPlot()->name().isEmpty() && !newPlot()->description().isEmpty() && !hasMatch(newPlot()->name()))
setisNewPlotValid(true);
else setisNewPlotValid(false);
}
, а эти в qml
:
ColumnLayout{
LineField{
label: "Name"
text: addContext.newPlot.name
onTextChanged: addContext.newPlot.name = text
}
AreaField{
label: "Address"
Layout.fillHeight: true
text: addContext.newPlot.description
onTextChanged: addContext.newPlot.description = text
}
PathButton{
pathData: C.addIcon
toolTip: "insert into database"
onClicked: addContext.addNewPlot()
isEnabled: addContext.isNewPlotValid
}
}
работают должным образом.