Russian Qt Forum
Ноябрь 27, 2024, 13:51 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: непонятки с таймером, не всегда запускается, см. сообщение  (Прочитано 10218 раз)
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« : Июнь 04, 2010, 14:59 »

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

Код:
void MainWindow::slWaitCursor()
{
QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
cursorchanged = true;
}

void MainWindow::slNull()
{
slMessage("null\n"); // отладочная печать
}

void MainWindow::redrawScene()
{
QTimer timer; // = new QTimer;
cursorchanged = false;
connect( &timer, SIGNAL(timeout()), this, SLOT(slWaitCursor()) );
timer.start( 500 );
//a->processEvents();
large_object->Redraw();
connect( &timer, SIGNAL(timeout()), this, SLOT(slNull()) );
timer.stop();
if( cursorchanged )
QApplication::restoreOverrideCursor();
}

cursorchanged всадил на всякий случай, поскольку не написано, что restoreOverrideCursor() ничего не делает, если курсор не перегружался

шаманство с реконнектом слотов сделал, поскольку timer->singleShot стреляет всегда, независимо от способа и времени исчезновения или остановки таймера - то есть, если сделать stop до истечения времени, сигнал тоже будет послан

но... не работает, почему-то таймер не запускается, поскольку явно видно, что никогда не вызывается slNull() и не меняется курсор, вообще никогда

но! стоит убрать строку timer.stop(); - таймер начинает удивительным образом работать, сигнал в slNull сыпется каждые 500 мсек  Шокированный

large_object->Redraw(); не содержит ни таймеров, ни параллельных нитей, ничего, кроме много-много рисования на QGraphicsScene (причем именно держит свой код обработки объекта, который там выполняется), либо наоборот, мало-мало (тогда курсор менять не надо), но гарантированно - даже когда рисуется все пару секунд, никакие сигналы от таймера не идут, смотрел в отладчике - перед вторым connect в таких случаях явное зависание, но контрольная точка внутри slWaitCursor() не срабатывает (если убрать timer.stop(); то срабатывает)

думал, может очередь сообщений где-то блокируется, но вызов a->processEvents(); (a это есессно указатель на QApplication) не помогает

тупик... можно подумать и сделать часы как-то иначе, но вроде тут все должно работать
« Последнее редактирование: Июнь 04, 2010, 15:06 от Гурман » Записан

2^7-1 == 127, задумайтесь...
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #1 : Июнь 04, 2010, 15:44 »

методом тыка выяснил, что

- таймер таки запускается, после отрисовки он остается активен, и останавливается соответствующим stop()
- независимо от заданного времени таймера, он не срабатывает по истечении заданного времени, поскольку stop() выполняется и после 2х секунд рисования, то, что таймер работает, показывает проверка isActive() НО! при этом таймером не генерится сигнал, и слот slNull() не вызывается, пробовал с разными типами соединений - не имеет значения
- при этом сигнал почему-то генерится, если убрать остановку таймера... Непонимающий - при длительной перерисовке курсор мигает

я баг нашел?
« Последнее редактирование: Июнь 04, 2010, 15:46 от Гурман » Записан

2^7-1 == 127, задумайтесь...
BRE
Гость
« Ответ #2 : Июнь 04, 2010, 15:54 »

Код
C++ (Qt)
       large_object->Redraw();
 
       
В методе Redraw я думаю есть большой цикл, в котором и рисуются все необходимые объекты. Добавь в него processEvents, для того что-бы цикл обработки событий крутился.
И думаю сигналы заработают.  Подмигивающий
« Последнее редактирование: Июнь 04, 2010, 16:05 от BRE » Записан
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #3 : Июнь 05, 2010, 00:06 »

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

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

и если затык в том, что сигнал от таймера во время Redraw не приходит, то тогда почему он не приходит и после окончания Redraw?...
« Последнее редактирование: Июнь 06, 2010, 00:42 от Гурман » Записан

2^7-1 == 127, задумайтесь...
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #4 : Июнь 07, 2010, 08:58 »

хех... попробовал добавить вызов processEvents() внутрь Redraw(), причем не на каждый элемент, а только перед некими "крупными" действиями, результат удручающий... оно то заработало, но отрисовка замедлилась в несколько раз, и что самое ужасное, стало видно, как сцена рисуется, чего собственно и следовало ожидать Злой

то есть, надо вычленить, и разрешить только событие таймера, чтобы processEvents() разрешало прохождение только его событий, либо хотя бы запретить прохождение событий при рисовании - а такой возможности нет...  Грустный есть только два флага QEventLoop::ExcludeUserInputEvents и QEventLoop::ExcludeSocketNotifiers, оба не подходят

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

« Последнее редактирование: Июнь 07, 2010, 09:04 от Гурман » Записан

2^7-1 == 127, задумайтесь...
BRE
Гость
« Ответ #5 : Июнь 07, 2010, 09:03 »

IMHO, лучше отказаться от сигналов и в цикле отрисовки метода Redraw проверять сколько времени крутиться цикл и если время больше заданного менять курсор на "занато", а в конце метода восстанавливать его.
Посмотри на:
void QTime::start ()
int QTime::elapsed () const
Записан
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #6 : Июнь 07, 2010, 09:08 »

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

и вообще... какой же это "таймер", если события его не проходят, когда приложение занято???  Злой я ожидал бы, чтобы таймер работал в параллельной нити, чтобы его сигналы гарантированно доставлялись через блокирующее соединение - придется наверно такое самому написать
« Последнее редактирование: Июнь 07, 2010, 09:15 от Гурман » Записан

2^7-1 == 127, задумайтесь...
BRE
Гость
« Ответ #7 : Июнь 07, 2010, 09:26 »

хотя это как-то "по-DOS-овски" Улыбающийся в единичном случае схляет, но хотелось некий регулярный способ получить, чтобы можно было потом просто вызывать одну функцию во всех похожих случаях
Одну функцию.... Ты же на C++ пишешь, так и думать нужно по другому.
Набросаю псевдокод, думаю идея будет понятна.
Код
C++ (Qt)
class CursorWaiter
{
public:
CursorWaiter( int timeout = 500 );
 
void process();
};
 
// Использование
void MyClass::Redraw()
{
CursorWaiter cw( 200 );
 
foreach(...)
{
// Считаем
// Рисуем
 
// Проверяем сколько времени прошло, если больше timeout, то меняем его на "Занято"
cw.prosess();
}
 
// При выходе из функции Redraw объект cw разрушиться, в деструкторе восстановить курсор.
}
 

и вообще... какой же это "таймер", если события его не проходят, когда приложение занято???  Злой я ожидал бы, чтобы таймер работал в параллельной нити, чтобы его сигналы гарантированно доставлялись через блокирующее соединение - придется наверно такое самому написать
Ты не ожидай, а посмотри как работают таймеры и все будет понятно.  Подмигивающий
Записан
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #8 : Июнь 07, 2010, 09:34 »

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

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

одним только таймером для этого не обойдешься, сделать придется чуть больше
Записан

2^7-1 == 127, задумайтесь...
ieroglif
Гость
« Ответ #9 : Июнь 07, 2010, 10:01 »

что происходит:
в основном потоке начинает работать "долгая функция" (в нашем случае это отрисовка).
поток её долго и усердно решает. времени на выполнение других задач остаётся поменьше - таймеры (работающие только в основном потоке) начинают зависать, гуй (работающий только в основном потоке) начинает тормозить, прогресс бары перестают корректно работать.. ужас в общем Улыбающийся
решение правильное (имхо, конечно):
решение происходит из понимания, что ООП не ООП, а выполнение комманд у нас ПОСЛЕДОВАТЕЛЬНОЕ. и пока одна комманда у нас не отработает - остальные в лучшем случае прижимаются к стенке и протискиваются как могут, а в других случаях так они вообще блокируются.
вывод простой - всё что "грузит" основной поток - выводить в отдельный. пусть там работает, сигнальчики отправляет какие хочет. а мы из основного потока, как только стартанём его себе singleShoot(на сколько нужно) запустим. ну и будем вести некий стек типа первый-вошёл=первый-вышел "текуще загружаемых потоков" по которому на каждый singleShoot SLOT метод будет брать элемент из стека, проверять - работает ли тред, и если да, то вешать значок песочных часиков. по окончанию работы тред тоже производит ряд действий каких-то там.. ну и т.д.
Записан
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #10 : Июнь 07, 2010, 10:43 »

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

но в моем случае, поскольку пока Redraw не выполнится, гуй и не должен полноценно работать, ибо не с чем

а вот таймеры, и все, что к гую не относится, по идее должно...
« Последнее редактирование: Июнь 07, 2010, 10:45 от Гурман » Записан

2^7-1 == 127, задумайтесь...
ieroglif
Гость
« Ответ #11 : Июнь 07, 2010, 11:25 »

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

но в моем случае, поскольку пока Redraw не выполнится, гуй и не должен полноценно работать, ибо не с чем

поверь, даже самому будет гораздо приятнее, если вместо подвисания гуя (хоть с ним работать и не надо ПОКА ЧТО) у тебя заблокируются элементы которые трогать пока-что не надо и на экране будет написано "Рисуем..." Улыбающийся а сделать это - 15 минут Подмигивающий

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

а вот таймеры, и все, что к гую не относится, по идее должно...

всё, что грузит основной поток в ущерб чему-либо (пользовательское удобство - тоже не маловажный момент.) - оно должно быть отделено в отдельный поток,.. разумеется не в ущерб основному приложению, но у тебя, мне кажется, не тот случай Подмигивающий
Записан
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #12 : Июнь 07, 2010, 12:03 »

Цитировать
поверь, даже самому будет гораздо приятнее, если вместо подвисания гуя (хоть с ним работать и не надо ПОКА ЧТО) у тебя заблокируются элементы которые трогать пока-что не надо и на экране будет написано "Рисуем..." Улыбающийся а сделать это - 15 минут

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

а вместо надписи "Рисуем" вполне устраивают песочные часы
Записан

2^7-1 == 127, задумайтесь...
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #13 : Июнь 07, 2010, 12:58 »

а вот таймеры, и все, что к гую не относится, по идее должно...
Не должно. События таймера имеют низший приоритет в OC и могут быть получены когда нет др. действий. Надо использовать вторичный цикл событий (см. пост BRE). При этом приходится повозиться чтобы он не тормозил выполнение - это нормальные, стандартные хлопоты.

Отделаться песочными часами вряд ли удастся, насколько я помню human interface

- задержка (вычисления, перерисовка и.т.п)  более полсекунды - app должно показать курсором
- задержка 2 и более секунд - app должно выставить индикатор
Записан
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #14 : Июнь 07, 2010, 15:13 »

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

2^7-1 == 127, задумайтесь...
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.185 секунд. Запросов: 23.