Russian Qt Forum

Qt => Общие вопросы => Тема начата: qtkoder777 от Октябрь 22, 2013, 10:15



Название: Как избежать бесконечного рекурсивного вызова слотов?
Отправлено: qtkoder777 от Октябрь 22, 2013, 10:15
Иногда встречается ситуация, когда при смене значения в одном компоненте надо поменять значение в другом, и наоборот, например
Код
C++ (Qt)
connect(spinbox1, SIGNAL(valueChanged(int)), this, SLOT(slotValueChanged1(int)));
connect(spinbox2, SIGNAL(valueChanged(int)), this, SLOT(slotValueChanged2(int)));
void MyClass::slotValueChanged1(int i)
{
    spinbox2->setValue(i);
}
void MyClass::slotValueChanged2(int i)
{
    spinbox1->setValue(i);
}
Если не предпринять дополнительных мер, то слоты будут бесконечно вызывать друг друга.
Очевидны два метода решения
Первый - использовать метод QObject::blockSignals
Код
C++ (Qt)
void MyClass::slotValueChanged1(int i)
{
    this->blockSignals(true);
    spinbox2->setValue(i);
    this->blockSignals(false);}
 
void MyClass::slotValueChanged2(int i)
{
    this->blockSignals(true);
    spinbox1->setValue(i);
    this->blockSignals(false);
}
Считаю, что это плохое решение, т.к. блокируется весь механизм сигнал/слот, а не только те сигналы которые надо.

Другой вариант - ввести переменную, определяющую находимся ли мы уже внутри слота. Он не имеет недостатков первого метода, но имеет свои недостатки: много кода, на каждую пару слотов надо вводить отдельную переменную.
Код
C++ (Qt)
bool in_slot=false;
void MyClass::slotValueChanged1(int i)
{
    if(!in_slot)
    {
        in_slot=true;
        spinbox2->setValue(i);
        in_slot=false;
    }
}
void MyClass::slotValueChanged2(int i)
{
    if(!in_slot)
    {
        in_slot=true;
        spinbox1->setValue(i);
        in_slot=false;
    }
}
Есть ли какое-то стандартное решение для такой ситуации, не имеющее недостатков указанных решений?


Название: Re: Как избежать бесконечного рекурсивного вызова слотов?
Отправлено: mutineer от Октябрь 22, 2013, 10:19
Вообще прямо в документации написано что чтобы избежать рекурсивного вызова слотов надо высылать сигнал об изменении только когда значение действительно изменилось, а не при каждой его записи


Название: Re: Как избежать бесконечного рекурсивного вызова слотов?
Отправлено: qtkoder777 от Октябрь 22, 2013, 10:23
Пример с QSpinBox приведен для простоты.
На самом деле это может быть сложный самописный компонент, для которого не так просто проверить, изменилось в нём что-то или нет.


Название: Re: Как избежать бесконечного рекурсивного вызова слотов?
Отправлено: mutineer от Октябрь 22, 2013, 10:24
Ну это все равно лучше, чем оба приведенных костыля


Название: Re: Как избежать бесконечного рекурсивного вызова слотов?
Отправлено: qtkoder777 от Октябрь 22, 2013, 10:29
Мне кажется, что QSpinBox всегда шлёт сигнал при программной установке значения, даже если оно равно текущему.


Название: Re: Как избежать бесконечного рекурсивного вызова слотов?
Отправлено: mutineer от Октябрь 22, 2013, 10:31
Это странно, в этом случае кутешники нарушают свои же рекомендации


Название: Re: Как избежать бесконечного рекурсивного вызова слотов?
Отправлено: qtkoder777 от Октябрь 22, 2013, 10:35
Может я и ошибаюсь насчёт QSpinBox. В документации написано, что сигнала в этом случае нет.
Но сторонние компоненты могут нарушать эту рекомендацию.
Что можно сделать в таком случае?


Название: Re: Как избежать бесконечного рекурсивного вызова слотов?
Отправлено: mutineer от Октябрь 22, 2013, 10:37
Делать проверку значения перед установкой и если оно такое же, то не ставить