Russian Qt Forum

Qt => Общие вопросы => Тема начата: Гурман от Апрель 29, 2010, 14:42



Название: какой виртуальный метод вызывается после передачи сигнала?
Отправлено: Гурман от Апрель 29, 2010, 14:42
вопрос в заголовке возможно не очень прозрачен, поэтому пояснение:

есть приложение с меню и кнопками на тулбарах, пункты меню посылают сигналы туда, куда подключены

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

после обработки сигналов необходимо выдавать сообщение об ошибке, при этом более чем в половине случаев невозможно выдать это сообщение, поскольку код устанавливается библиотечными функциями

можно в каждый приемник сигнала влепить выдачу сообщений об ошибке после обработки любого сигнала - но это очень не красиво, поскольку слотов для приема сигнала десятки, и при добавлении каждого нового потребуется выдача такого сообщения

каким образом можно получить управление после того, как любой сигнал был обработан его приемником, независимо от того, откуда он был послан? все описанные сигналы и приемники находятся в одной нити приложения, но сигналы посылаются разными объектами


Название: Re: какой виртуальный метод вызывается после передачи сигнала?
Отправлено: kibsoft от Апрель 29, 2010, 15:15
Если я все правильно понял, то можно использовать QSignalMapper. Т.е. все твои виджеты будут посылать сигналы в один слот, оттуда определяя что это за объект вызываем нужную функцию обработки, а затем после возврата из функции выполняем нужные действия(в слоте), т.е. как и надо получаем управление. Незнаю подойдет ли это в вашем случае..
В ассистенте можно почитать: Advanced Signals and Slots Usage
Ну и соответственно описание класса QSignalMapper.


Название: Re: какой виртуальный метод вызывается после передачи сигнала?
Отправлено: spectre71 от Апрель 29, 2010, 15:17
Как вариант, можно переопределить CoreApplication::notify и делать проверки там.

Тупой пример:

Код
C++ (Qt)
class MyApplication : public QApplication{
   Q_OBJECT
 public:
   bool IsError;
 public:
   MyApplication (int& argc, char** argv) : QApplication(argc, argv) {MyGlobalError = false;}
   bool notify ( QObject * receiver, QEvent * event);
};
 
int main(int argc, char *argv[]) {
//...
//...
 MyApplication a(argc, argv);
//...
//...
 return a.exec();
}
 
bool MyApplication::notify ( QObject * receiver, QEvent * event ) {
   bool Res = QApplication::notify(receiver, event);
   if(IsError) {
     IsError= false;
     QMessageBox::information(0, QObject::tr("information"), "Error");
   }
   return Res;
}


Название: Re: какой виртуальный метод вызывается после передачи сигнала?
Отправлено: Igors от Апрель 29, 2010, 15:18
Я бы ставил так

Код
C++ (Qt)
// один из обработчиков
...
if (theErrorHandler.GetError() != errNone)  // ошибка уже случилась, уходим    
return theErrorHandler.GetError();
...
int err = MyLibCal(..);                     // работаем с библиотеками и.т.п.
if (err != errNone)                         // проверяем на ошибку
return theErrorHandler.SetError(err);      // устанавливаем ошибку и уходим
...
 
// ErrorHandler
int ErrorHandler::GetError( void ) const
{
return mErrorCode;
}
 
int ErrorHandler::SetError( int errCode )
{
static QMutex mutex;
QMutexLocker(&mutex);
if (mErrorCode == noErr) {
 mErrorCode = errCode;
 emit ShowError(this);                    // QueuedConnection
}
}
 
ErrorHandler theErrorHandler;             // глобальная переменная
 


Название: Re: какой виртуальный метод вызывается после передачи сигнала?
Отправлено: Гурман от Апрель 29, 2010, 15:53
че-то не нравится ни один предложенный вариант  :(

лучше всего, если бы можно было переопределить приложение, а там виртуальный метод что-нибудь вроде AfterSignalProcessed(), который вызывается каждый раз, когда завершился любой обработчик любого сигнала

такого нет?


Название: Re: какой виртуальный метод вызывается после передачи сигнала?
Отправлено: Kolobok от Апрель 29, 2010, 17:17
Тип соединения у тебя DirectConnection. Значит, на следующей строчке после emit слот уже выполнится. Вот и посылай после первого сигнала второй, что сигнал обработан.


Название: Re: какой виртуальный метод вызывается после передачи сигнала?
Отправлено: Гурман от Апрель 29, 2010, 18:56
Тип соединения у тебя DirectConnection. Значит, на следующей строчке после emit слот уже выполнится. Вот и посылай после первого сигнала второй, что сигнал обработан.

откуда посылать? из слота? из функции, делающей emit? слотов несколько десятков, мест для emit еще больше, и на множество слотов сигналы идут из меню приложения, от разных кнопок и прочих виджетов, созданных в QtDesigner


Название: Re: какой виртуальный метод вызывается после передачи сигнала?
Отправлено: kibsoft от Апрель 29, 2010, 19:08
Цитировать
откуда посылать? из слота? из функции, делающей emit? слотов несколько десятков, мест для emit еще больше, и на множество слотов сигналы идут из меню приложения, от разных кнопок и прочих виджетов, созданных в QtDesigner
Kolobok имеет ввиду после каждого сигнала высылай другой сигнал, что тот уже обработан.
Ну и еще остается вариант практически такой же - это в конце слота обработки сигнала вызывать какую-либо функцию или опять же отсылать сигнал, что тот уже обработан.


Название: Re: какой виртуальный метод вызывается после передачи сигнала?
Отправлено: spectre71 от Апрель 29, 2010, 19:27
Тип соединения у тебя DirectConnection. Значит, на следующей строчке после emit слот уже выполнится. Вот и посылай после первого сигнала второй, что сигнал обработан.

Что попало. И как интересно получится продублировать сигналы из внутри методов класовв QT библиотеки. :)


Название: Re: какой виртуальный метод вызывается после передачи сигнала?
Отправлено: Kolobok от Апрель 29, 2010, 19:29
Код:
connect( button, SIGNAL( clicked() ), obj1, SLOT( slot() ) );
connect( button, SIGNAL( clicked() ), obj2, SLOT( slot() ) );

Слоты выполнятся в той последовательности, как они были соединены. В данном примере сначала obj1->slot(), потом obj2->slot().


Название: Re: какой виртуальный метод вызывается после передачи сигнала?
Отправлено: spectre71 от Апрель 29, 2010, 19:29
че-то не нравится ни один предложенный вариант  :(

лучше всего, если бы можно было переопределить приложение, а там виртуальный метод что-нибудь вроде AfterSignalProcessed(), который вызывается каждый раз, когда завершился любой обработчик любого сигнала

такого нет?

1) Чем тебе не нравятся предложенные варианты. Поясни.
2) Уточни что за обработка ошибок, в каких случаях, ...



Название: Re: какой виртуальный метод вызывается после передачи сигнала?
Отправлено: spectre71 от Апрель 29, 2010, 19:37
Код:
connect( button, SIGNAL( clicked() ), obj1, SLOT( slot() ) );
connect( button, SIGNAL( clicked() ), obj2, SLOT( slot() ) );

Слоты выполнятся в той последовательности, как они были соединены. В данном примере сначала obj1->slot(), потом obj2->slot().

1) Возможно и так(не уточнял), но только для однопотокого приложения! :)
2) Очень плохой способ дублировать сединения.




Название: Re: какой виртуальный метод вызывается после передачи сигнала?
Отправлено: Igors от Апрель 29, 2010, 19:45
лучше всего, если бы можно было переопределить приложение, а там виртуальный метод что-нибудь вроде AfterSignalProcessed(), который вызывается каждый раз, когда завершился любой обработчик любого сигнала

такого нет?
А как оно должно "быть" (т.е. разумна ли такая вещь)?  Какие параметры должны подаваться в  AfterSignalProcessed()? Нужен как минимум код/флаг ошибки - а откуда они возьмутся если это личное дело каждого слота-обработчика ?


Название: Re: какой виртуальный метод вызывается после передачи сигнала?
Отправлено: Kolobok от Апрель 29, 2010, 19:51
1) Возможно и так(не уточнял), но только для однопотокого приложения! :)

Цитировать
все описанные сигналы и приемники находятся в одной нити приложения

2) Очень плохой способ дублировать сединения.

А где здесь дублирование? Один сигнал посылается двум разным слотам.


Название: Re: какой виртуальный метод вызывается после передачи сигнала?
Отправлено: spectre71 от Апрель 29, 2010, 19:59
А где здесь дублирование? Один сигнал посылается двум разным слотам.

Сам этот принцип - безсмысленное дублирование соединений. Второе соединение для возможной обработки ошибки.
Элементарно можно промахнуться:
- забыть сделать 2-е соединение, когда известно что в первом сединении слот может сгенерить ошибку;
- забыть добавить 2-е соединение, ко всем 1-м, во всех модулях, когда 1-й слот был изменен так что стал генерить ошибку.
- ...



Название: Re: какой виртуальный метод вызывается после передачи сигнала?
Отправлено: Kolobok от Апрель 29, 2010, 20:30
Сам этот принцип - безсмысленное дублирование соединений. Второе соединение для возможной обработки ошибки.

Это не дублирование. Первый сигнал посылается для обработки данных. Второй - для проверки результата.

Элементарно можно промахнуться:
- забыть сделать 2-е соединение, когда известно что в первом сединении слот может сгенерить ошибку;
- забыть добавить 2-е соединение, ко всем 1-м, во всех модулях, когда 1-й слот был изменен так что стал генерить ошибку.
[/quote]

Если так рассуждать, то можно и первый коннект забыть. Или забыть парочку объектов создать. Или ту самую библиотеку подключить.:)


Название: Re: какой виртуальный метод вызывается после передачи сигнала?
Отправлено: spectre71 от Апрель 29, 2010, 21:01
Сам этот принцип - безсмысленное дублирование соединений. Второе соединение для возможной обработки ошибки.

Это не дублирование. Первый сигнал посылается для обработки данных. Второй - для проверки результата.

Элементарно можно промахнуться:
- забыть сделать 2-е соединение, когда известно что в первом сединении слот может сгенерить ошибку;
- забыть добавить 2-е соединение, ко всем 1-м, во всех модулях, когда 1-й слот был изменен так что стал генерить ошибку.

Если так рассуждать, то можно и первый коннект забыть. Или забыть парочку объектов создать. Или ту самую библиотеку подключить.:)

По поводу забыть первый коннект и подобное - оно безопасно, поскольку быстро поймаем ошибку. А вот парный - когда еще вылезет проблема.

Все зависит от опыта, в том числе применяемые нами модели.


Название: Re: какой виртуальный метод вызывается после передачи сигнала?
Отправлено: SASA от Апрель 30, 2010, 09:51
Я б вообще изменил способ генерации ошибок.
Вместо присваивания чего-либо в глобальную переменную надо вызывать функцию (испускать сигнал). Т.е. каждый объект должен знать как сообщить об ошибке.
Большой плюс этого подхода в том, что можно легко добавить информацию об ошибке. У меня эта функция имеет 4 параметра - что произошло, где, подробная инфа, критичность.


Название: Re: какой виртуальный метод вызывается после передачи сигнала?
Отправлено: Гурман от Апрель 30, 2010, 13:00
Цитировать
1) Чем тебе не нравятся предложенные варианты. Поясни.

тем, что в них приходится над штатными средствами Qt морочить еще надстройку, и не забывать ее использовать

Цитировать
2) Уточни что за обработка ошибок, в каких случаях, ...

библиотека написана на С, там просто устанавливается код ошибки, и даже не всегда возвращается false, то есть, надо после вызова функции проверять глобальную переменную на 0, надстройка над этой библиотекой написана на С++, и с Qt никак не связана, дополнительные функции просто также устанавливают код ошибки в этой же переменной - поэтому самое последнее предложение высылать сигнал не проходит в принципе

слоты - это простые короткие переходники, которые получают сигналы и вызывают функции библиотеки или надстройки над ней

среднее предложение, высылать сигнал сразу после высылки основного тоже не годится, потому как подавляющее большинство сигналов высылаются виджетами, созданными в QtDesigner, и кроме этого, сигналов гораздо больше, чем слотов - поэтому более кошерно сделать простое макро типа

Код:
#define returnSlot {GloballErrorMessage();return;}

где глобальная функция GloballErrorMessage() проверяет наличие кода ошибки, если он есть, выдает сообщение, и сбрасывает код в 0 - и использовать в конце каждого слота этот макрос вместо return - единственный минус тут - не забыть, что надо писать не return - хотя это конечно тоже хак...

но тут другой момент... вроде бы получается перевести все слоты в один объект, наследующий QMainWindow, а там вроде есть подходящий обработчик


Название: Re: какой виртуальный метод вызывается после передачи сигнала?
Отправлено: ритт от Май 01, 2010, 19:16
я бы написал удобный thin-wrapper для этой либы и не замусоривал бы код приложения сторонними вызовами...


Название: Re: какой виртуальный метод вызывается после передачи сигнала?
Отправлено: Igors от Май 02, 2010, 12:47
Вряд ли Вы отделаетесь макросом, обычно надо сохранить "контекст ошибки" чтобы потом заняться ее печатью (а может и восстановлением). Напр у меня ф-ция SetError принимает 4 параметра

- класс ошибки
- код ошибки
- N (контекстно-зависимое, напр размер блока памяти который не удалось распределить)
- ID файла при обработке которого произошла ошибка (или 0)

После каждого вызова в котором может случиться ошибка, ее надо проверить и, если, случилось, записать контекст и выйти. После завершения всех активных расчетов (возможно в неск. нитках) придет время обработать ошибку.