В Qt, как я могу реализовать виджет, который остается согласованным с переменными в коде
Вопрос
Вот пример SpinBox, который записывает свои изменения в базовые переменные. Основная проблема, с которой я сталкиваюсь, заключается в том, что valueChanged вызывается при создании виджета. Есть ли более элегантный способ сделать это? Я думаю, что это странно, что я подключил виджет к себе, но valueChanged не является виртуальным.
class ValueWriterInt: public QSpinBox {
Q_OBJECT
public:
ValueWriterInt(vector<int*> const& value): myValue(value) {
QObject::connect(this, SIGNAL(valueChanged(int)), this, SLOT(valueChanged(int)));
}
~ValueWriterInt() {}
private slots:
void valueChanged(int new_value) {
for (auto it = myValue.begin(); it != myValue.end(); ++it)
**it = new_value;
}
private:
vector<int*> myValue;
};
Решение
Я не вижу ничего особенно странного в подключении виджета к себе. Наличие единственного метода обнаружения обновлений данных и реагирования на них на самом деле звучит как хорошая вещь, поскольку у вас меньше точек отказа при проверке при отладке. В вашем конкретном случае это вызывает нежелательное поведение, но в целом это хорошее решение.
Теперь, выразив мнение о том, что рефлексивная связь не является по сути своей не элегантной, я собираюсь предложить менее чем "элегантный". решение для предотвращения вызова valueChanged
после построения. Вы можете иметь флаг, чтобы определить, был ли объект только что создан и возвращен рано, чтобы предотвратить запуск кода сразу после создания. В вашем примере:
class ValueWriterInt: public QSpinBox {
Q_OBJECT
public:
ValueWriterInt(vector<int*> const& value): myValue(value), myAfterInit(true) {
QObject::connect(this, SIGNAL(valueChanged(int)), this, SLOT(valueChanged(int)));
}
~ValueWriterInt() {}
private slots:
void valueChanged(int new_value) {
if (myAfterInit) {
myAfterInit = false;
return;
}
for (auto it = myValue.begin(); it != myValue.end(); ++it)
**it = new_value;
}
private:
vector<int*> myValue;
boolean myAfterInit;
};
Это не так уж плохо для решения. По крайней мере, это даст вам желаемое поведение, пока (и если) вы не найдете более элегантный метод.
Другие советы
Так чего же вы здесь добиваетесь? Да, valueChanged не является виртуальным - почему это должно быть, ваши объекты должны напрямую подключать свои собственные слоты к любым сигналам, на которые они хотят реагировать, нет?
Я не вижу другой альтернативы, кроме как использовать соединения SIGNAL-SLOT. Однако я бы изменил название слота, чтобы он не совпадал с именем сигнала.
Интересно, как называется слот, даже если соединение еще не установлено. Я подозреваю, что изменение названия слота решит эту проблему.