В Qt, как я могу реализовать виджет, который остается согласованным с переменными в коде

StackOverflow https://stackoverflow.com/questions/818981

  •  03-07-2019
  •  | 
  •  

Вопрос

Вот пример 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. Однако я бы изменил название слота, чтобы он не совпадал с именем сигнала.

Интересно, как называется слот, даже если соединение еще не установлено. Я подозреваю, что изменение названия слота решит эту проблему.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top