Russian Qt Forum

Qt => Общие вопросы => Тема начата: Igors от Сентябрь 07, 2009, 11:56



Название: "Общий" ввод
Отправлено: Igors от Сентябрь 07, 2009, 11:56
Добрый день

Имею много немодальных диалогов но очень простых. Для подавляющего большинства control'ов реакция однотипна:

- записать обновленное значение в данные
- перезапустить расчет который выводит результаты в другом окне

Мне не хочется иметь десятки членов класса и возиться с каждым из них. А хочется иметь один большой switch, например

Код:
bool MyDialog::GetEditVal( int theItemID, double & val )
{
    QLineEdit * edit = qobject_cast <QLineEdit *> ID2Widget(theItemID);
    if (!edit) return false;
    val = edit->text().toDouble();
    return true;
}

void MyDialog::InterfaceChanged( int theItemID )
{
    switch (theItemID) {
      case ID_VELOCITY:
        GetEditVal(theItemID, theData.velocity);
        break; 

      case ID_ACCEL:
        GetEditVal(theItemID, theData.accel);
        break; 
      .....
      .....
    }
}
Получить/присвоить ID - без проблем. Но как мне получить общий сигнал InterfaceChanged без забот с каждым конкретным control'ом?

Спасибо


Название: Re: "Общий" ввод
Отправлено: BRE от Сентябрь 07, 2009, 13:35
Можно сделать класс наследник от QDialog, перекрыть в нем виртуальную функцию:
void QObject::childEvent ( QChildEvent * event )   [virtual protected]

При каждом добавлении/удалении контроллов в этой функции можно делать connect/disconnect нужного сигнала с нужным слотом.


Название: Re: "Общий" ввод
Отправлено: Igors от Сентябрь 07, 2009, 13:51
Можно сделать класс наследник от QDialog, перекрыть в нем виртуальную функцию:
void QObject::childEvent ( QChildEvent * event )   [virtual protected]

При каждом добавлении/удалении контроллов в этой функции можно делать connect/disconnect нужного сигнала с нужным слотом.

Мне не нужно добавлять/удалять control'ы на ходу. Не нужен в данном случае и сигнал/слот - control'ы для этого слишком примитивны :). Хочу просто получить управление когда "произошел ввод от такой-то widget" - а дальше я разберусь


Название: Re: "Общий" ввод
Отправлено: BRE от Сентябрь 07, 2009, 14:09
Мне не нужно добавлять/удалять control'ы на ходу. Не нужен в данном случае и сигнал/слот - control'ы для этого слишком примитивны :).
Хочу просто получить управление когда "произошел ввод от такой-то widget" - а дальше я разберусь
При изменении данных в виджете посылается сигнал. Тебе нужно сигналы от контроллов соединить с одним слотом (InterfaceChanged). Тогда при изменении данных в любом контролле, будет вызван твой слот, где и будет происходить обработка.
Обработка события childEvent позволит тебе автоматически связать сигналы нужных контроллов с твои слотом. Событие это будет происходить при конструировании твоих диалогов.


Название: Re: "Общий" ввод
Отправлено: SASA от Сентябрь 07, 2009, 14:33
QSignalMapper


Название: Re: "Общий" ввод
Отправлено: Igors от Сентябрь 07, 2009, 14:36
Обработка события childEvent позволит тебе автоматически связать сигналы нужных контроллов с твои слотом. Событие это будет происходить при конструировании твоих диалогов.
Меня и "не-автоматически" вполне устроит, children всегда под рукой
При изменении данных в виджете посылается сигнал. Тебе нужно сигналы от контроллов соединить с одним слотом (InterfaceChanged). Тогда при изменении данных в любом контролле, будет вызван твой слот, где и будет происходить обработка.
Да коряво выходит. Понятно что в слоте-приемнике могу получить widget через sender(). Но аргументы для посылаемых сигналов разные: valueChanged( double ), valueChanged( int ) и.т.п. Как мне нацелить их все на 1 slot? (желательно без возни с qobject_cast)


Название: Re: "Общий" ввод
Отправлено: BRE от Сентябрь 07, 2009, 14:45
Да коряво выходит. Понятно что в слоте-приемнике могу получить widget через sender(). Но аргументы для посылаемых сигналов разные: valueChanged( double ), valueChanged( int ) и.т.п. Как мне нацелить их все на 1 slot? (желательно без возни с qobject_cast)
Код
C++ (Qt)
connect( w1, SIGNAL( valueChanged( int ) ), SLOT( changed() ) );
connect( w2, SIGNAL( valueChanged( double ) ), SLOT( changed() ) );
 
А в changed() по sender() получаешь свой ID, а по ID ты и так тип знаешь.

SASA напомнил про QSignalMapper. С ним, думаю, будет попроще.


Название: Re: "Общий" ввод
Отправлено: Igors от Сентябрь 07, 2009, 19:25
Код
C++ (Qt)
connect( w1, SIGNAL( valueChanged( int ) ), SLOT( changed() ) );
connect( w2, SIGNAL( valueChanged( double ) ), SLOT( changed() ) );
 
Не понял. В букваре написано мутно
Цитировать
The signals and slots mechanism is type safe: The signature of a signal must match the signature of the receiving slot. (In fact a slot may have a shorter signature than the signal it receives because it can ignore extra arguments.) Since the signatures are compatible, the compiler can help us detect type mismatches.
Так должны они по типам аргументов точно совпадать? Или приемник может иметь меньшее число параметров?  Или как?

SASA напомнил про QSignalMapper. С ним, думаю, будет попроще.
Я пока вижу здесь он не лепится но при случае пригодиться очень даже может, спасибо. Тогда мне может лучше иметь приемником не parent widget а member ee, порожденный от QAction?


Название: Re: "Общий" ввод
Отправлено: BRE от Сентябрь 07, 2009, 19:57
Так должны они по типам аргументов точно совпадать? Или приемник может иметь меньшее число параметров?  Или как?
Самое простое попробовать самому.  ;)



Название: Re: "Общий" ввод
Отправлено: Igors от Сентябрь 07, 2009, 20:23
Самое простое попробовать самому.  ;)
Да я много чего могу сам попробовать :) Но хотелось бы услышать авторитетное мнение "лучших собаководов" :) 


Название: Re: "Общий" ввод
Отправлено: SABROG от Сентябрь 09, 2009, 11:38
Самое простое попробовать самому.  ;)
Да я много чего могу сам попробовать :) Но хотелось бы услышать авторитетное мнение "лучших собаководов" :) 

К варианту, который предложил BRE нужен комментарий. Ты сможешь узнать, что значение изменилось. Но не по пришедшим в метод параметрам, т.к. параметров не будет:

Код
C++ (Qt)
void MainWindow::changed()
{
}

, а только через sender(). Но тут возникнет другая проблема. К какому из контролов приводить указатель QObject? QSpinBox или QDoubleSpinBox? В принципе это можно узнать через sender()->metaObject()->className(). Или можно воспользовать общим базовым классом QAbstractSpinBox и использовать QVariant'ное свойство value() и преобразовывать в то, чем удобнее пользоваться:

Код
C++ (Qt)
void MainWindow::changed()
{
   QAbstractSpinBox *sb = qobject_cast<QAbstractSpinBox *>(sender());
   qDebug() << sender()->metaObject()->className() << sb->property("value");
}
 


Название: Re: "Общий" ввод
Отправлено: Igors от Сентябрь 09, 2009, 12:08
, а только через sender(). Но тут возникнет другая проблема. К какому из контролов приводить указатель QObject? QSpinBox или QDoubleSpinBox?
Как минимум я могу тупо приводить "к известному мне типу", т.е. я просто знаю что "под этим ID у меня  QDoubleSpinBox, а под этим - QLineEdit" и.т.д  Ошибки легко отловить (qobject_cast вернет NULL). Может это и не идеально, но все же лучше чем иметь массу видимых объектов и слотов.


Название: Re: "Общий" ввод
Отправлено: SABROG от Сентябрь 09, 2009, 12:43
С моей точки зрения это плохой тон программирования. Потом интерфейс программы будет тяжело модифицировать, т.к. при каждом удалении, добавлении придется вспоминать в каких местах кода нужно сделать изменения. Лучше сделать 10 слотов под каждый тип данных, чем один, но с возможным будущим геморроем.