Поиск:

Ответ в темуСоздание новой темы Создание опроса
> [Qt] замирает обработка событий при перетаскивании, processEvents очень долго выполняется. 
:(
    Опции темы
iigor
Дата 23.1.2010, 13:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 12
Регистрация: 7.9.2007

Репутация: нет
Всего: нет



Добрый день, всем!

Наткнулся на такую особенность. При перетаскивании окошка(или изменении размеров) возврат управления processEvents происходит после завершения перетаскивания.

В коде ниже можно наблюдать, как в консоле останавливается вывод циферок, когда окошко перетаскиваешь.

Код

#include <qapplication>
#include <qcoreapplication>
#include <qlabel>
#include <qtgui>
#include <qeventloop>

class MyDlg : public QMainWindow
{
    public:
    MyDlg()
    {
        this->resize(500,200);
        this->setWindowTitle("CRASH TEST");
    };
};


int main(int argc, char *argv[])
{
    QApplication app(argc, argv );
    MyDlg *mywnd = new MyDlg ();

    mywnd->show();

    int i=0;
    
    printf("it %d\n",i);
    for (i=0;i<100000000; i++) 
    {
        app.processEvents(QEventLoop::AllEvents);
        printf("it %d\n",i);
    }
    
    delete mywnd;
    return 0;

}




При этом ничего подобного не происходит, скажем, в консоле (cmd) или плеере lightalloy.   
PM MAIL   Вверх
SABROG
Дата 23.1.2010, 14:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


Профиль
Группа: Завсегдатай
Сообщений: 2481
Регистрация: 18.9.2006

Репутация: 81
Всего: 91



По-моему это стандартное поведение всех программ. Если передвигать окно, просто кликнуть на бордюр окна для изменения размера и держать мышку зажатой или открыть системное меню заголовка - все события останавливаются: таймеры, анимация, сообщения из сокетов и т.п. Другое дело, если это не стандартное окно, как у winamp или lightalloy - окно со шкуркой. Эти окна не рисуют пунктирный прямоугольник при перетаскивании, они двигаются вслед за мышкой, т.к. обрабатывают своё перемещение сами, а не полагаются на ОС. Поэтому в таких программах цикл событий как работал так и работает. Поэкспериментируй с флагом Qt::FramelessWindowHint, из-за отсутствия заголовка в подобных окнах тебе придется реализовывать перемещение и изменение размеров окна самому, что и сделано в программах типа LA.


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
iigor
Дата 23.1.2010, 15:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 12
Регистрация: 7.9.2007

Репутация: нет
Всего: нет



Нее. тут другое.

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

Есть спец. опция 

Цитата

void QEventLoop::processEvents ( ProcessEventsFlags flags, int maxTime )

Process pending events that match flags for a maximum of maxTime milliseconds, or until there are no more events to process, whichever is shorter. This function is especially useful if you have a long running operation and want to show its progress without allowing user input, i.e. by using the ExcludeUserInputEvents flag.

Notes:

This function does not process events continuously; it returns after all available events are processed.
Specifying the WaitForMoreEvents flag makes no sense and will be ignored.


Но она не работает как ожидается. Опять же, при перетаскивании, выхода из неё не будет пока кнопку не отпустишь (==не закончится поток сообщений)
PM MAIL   Вверх
SABROG
Дата 23.1.2010, 16:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


Профиль
Группа: Завсегдатай
Сообщений: 2481
Регистрация: 18.9.2006

Репутация: 81
Всего: 91



Тут всего одного события хватает, чтобы processEvents() не вернулся - вызвать системное меню на заголовке окна и не закрывать его. События выполняются последовательно, если какой-то метод реагирует на событие и долго не возвращает управления, то остальные события будут ждать. Аналогично и обработчики таймера будут стоять, это всего лишь события.


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
iigor
Дата 23.1.2010, 16:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 12
Регистрация: 7.9.2007

Репутация: нет
Всего: нет



crashtest.cpp
Код

#include <qapplication>
#include <qcoreapplication>
#include <qlabel>
#include <qtgui>
#include <qeventloop>
#include <qtimer>
#include "crashtest.h"



MyDlg::MyDlg()
{
    this->resize(500,200);
    this->setWindowTitle("CRASH TEST");
    
    this->i = 0;
    
    this->qtimer = new QTimer();
    
    this->qtimer->setInterval(0);

    this->connect(this->qtimer, SIGNAL(timeout()), this, SLOT(timeout()));
    this->qtimer->start();
}


MyDlg::~MyDlg()
{
    delete this->qtimer;
};

void MyDlg::timeout()
{
    printf("itS %d\n",this->i);
    this->i ++;
    
};



crashtest.h
Код

#include <qapplication>
#include <qcoreapplication>
#include <qlabel>
#include <qtgui>
#include <qeventloop>
#include <qtimer>
#include "crashtest.h"



MyDlg::MyDlg()
{
    this->resize(500,200);
    this->setWindowTitle("CRASH TEST");
    
    this->i = 0;
    
    this->qtimer = new QTimer();
    
    this->qtimer->setInterval(100);

    this->connect(this->qtimer, SIGNAL(timeout()), this, SLOT(timeout()));
    this->qtimer->start();
}


MyDlg::~MyDlg()
{
    delete this->qtimer;
};

void MyDlg::timeout()
{
    printf("itS %d\n",this->i);
    this->i ++;
    
};


main.cpp
Код

#include <qapplication>
#include <qcoreapplication>
#include <qlabel>
#include <qtgui>
#include <qeventloop>
#include <qtimer>
#include "crashtest.h"



int main(int argc, char *argv[])
{
    QApplication app(argc, argv );
    MyDlg *mywnd = new MyDlg ();


    mywnd->show();

    int i=0;
    
    printf("it %d\n",i);
    //app.exec();
    for (i=0;i<100000000; i++) 
    {
        app.processEvents(QEventLoop::AllEvents,10);
        printf("it %d\n",i);
    }

    
    delete mywnd;
    return 0;

}




данное приложение выводит в консоль сообщения вида "it 123" из main и "itS 456" благодаря таймеру.
Если же нажать на системное меню - тогда сообщения "it 123" не появляются, но сообщения "itS 456"  по прежнему выводятся, т.е. сообщения от таймера обрабатываются => цикл обработки не остановился. Или вы не про это?


PM MAIL   Вверх
SABROG
Дата 23.1.2010, 19:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


Профиль
Группа: Завсегдатай
Сообщений: 2481
Регистрация: 18.9.2006

Репутация: 81
Всего: 91



Тогда я не понимаю какие еще эвенты могут быть в очереди при открытом системном меню, что невозможно вернуться из processEvents().


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
iigor
Дата 23.1.2010, 19:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 12
Регистрация: 7.9.2007

Репутация: нет
Всего: нет



там QT что-то мутит smile
Он запоминает некоторые состояния. И ждёт некоторых событий. (Я не очень силён в winapi, так что глубоко не понимаю этот код.)

см. около  if (!haveMessage)

Код

bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
{
    Q_D(QEventDispatcherWin32);

    if (!d->internalHwnd)
        createInternalHwnd();

    d->interrupt = false;
    emit awake();

    bool canWait;
    bool retVal = false;
    bool seenWM_QT_SENDPOSTEDEVENTS = false;
    bool needWM_QT_SENDPOSTEDEVENTS = false;
    do {
        DWORD waitRet = 0;
        HANDLE pHandles[MAXIMUM_WAIT_OBJECTS - 1];
        QVarLengthArray<MSG> processedTimers;
        while (!d->interrupt) {
            DWORD nCount = d->winEventNotifierList.count();
            Q_ASSERT(nCount < MAXIMUM_WAIT_OBJECTS - 1);

            MSG msg;
            bool haveMessage;

            if (!(flags & QEventLoop::ExcludeUserInputEvents) && !d->queuedUserInputEvents.isEmpty()) {
                // process queued user input events
                haveMessage = true;
                msg = d->queuedUserInputEvents.takeFirst();
            } else if(!(flags & QEventLoop::ExcludeSocketNotifiers) && !d->queuedSocketEvents.isEmpty()) {
                // process queued socket events
                haveMessage = true;
                msg = d->queuedSocketEvents.takeFirst();
            } else {
                haveMessage = PeekMessage(&msg, 0, 0, 0, PM_REMOVE);
                if (haveMessage && (flags & QEventLoop::ExcludeUserInputEvents)
                    && ((msg.message >= WM_KEYFIRST
                         && msg.message <= WM_KEYLAST)
                        || (msg.message >= WM_MOUSEFIRST
                            && msg.message <= WM_MOUSELAST)
                        || msg.message == WM_MOUSEWHEEL
                        || msg.message == WM_MOUSEHWHEEL
                        || msg.message == WM_CLOSE)) {
                    // queue user input events for later processing
                    haveMessage = false;
                    d->queuedUserInputEvents.append(msg);
                }
                if (haveMessage && (flags & QEventLoop::ExcludeSocketNotifiers)
                    && (msg.message == WM_QT_SOCKETNOTIFIER && msg.hwnd == d->internalHwnd)) {
                    // queue socket events for later processing
                    haveMessage = false;
                    d->queuedSocketEvents.append(msg);
                }
            }

            if (!haveMessage) {
                // no message - check for signalled objects
                for (int i=0; i<(int)nCount; i++)
                    pHandles[i] = d->winEventNotifierList.at(i)->handle();
                waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, 0, QS_ALLINPUT, MWMO_ALERTABLE);
                if ((haveMessage = (waitRet == WAIT_OBJECT_0 + nCount))) {
                    // a new message has arrived, process it
                    continue;
                }
            }
            if (haveMessage) {
#ifdef Q_OS_WINCE
                // WinCE doesn't support hooks at all, so we have to call this by hand :(
                (void) qt_GetMessageHook(0, PM_REMOVE, (LPARAM) &msg);
#endif

                if (d->internalHwnd == msg.hwnd && msg.message == WM_QT_SENDPOSTEDEVENTS) {
                    if (seenWM_QT_SENDPOSTEDEVENTS) {
                        needWM_QT_SENDPOSTEDEVENTS = true;
                        continue;
                    }
                    seenWM_QT_SENDPOSTEDEVENTS = true;
                } else if (msg.message == WM_TIMER) {
                    // avoid live-lock by keeping track of the timers we've already sent
                    bool found = false;
                    for (int i = 0; !found && i < processedTimers.count(); ++i) {
                        const MSG processed = processedTimers.constData()[i];
                        found = (processed.wParam == msg.wParam && processed.hwnd == msg.hwnd && processed.lParam == msg.lParam);
                    }
                    if (found)
                        continue;
                    processedTimers.append(msg);
                } else if (msg.message == WM_QUIT) {
                    if (QCoreApplication::instance())
                        QCoreApplication::instance()->quit();
                    return false;
                }

                if (!filterEvent(&msg)) {
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }
            } else if (waitRet >= WAIT_OBJECT_0 && waitRet < WAIT_OBJECT_0 + nCount) {
                d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0));
            } else {
                // nothing todo so break
                break;
            }
            retVal = true;
        }

        // still nothing - wait for message or signalled objects
        canWait = (!retVal
                   && !d->interrupt
                   && (flags & QEventLoop::WaitForMoreEvents));
        if (canWait) {
            DWORD nCount = d->winEventNotifierList.count();
            Q_ASSERT(nCount < MAXIMUM_WAIT_OBJECTS - 1);
            for (int i=0; i<(int)nCount; i++)
                pHandles[i] = d->winEventNotifierList.at(i)->handle();

            emit aboutToBlock();
            waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE);
            emit awake();
            if (waitRet >= WAIT_OBJECT_0 && waitRet < WAIT_OBJECT_0 + nCount) {
                d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0));
                retVal = true;
            }
        }
    } while (canWait);

    if (!seenWM_QT_SENDPOSTEDEVENTS && (flags & QEventLoop::EventLoopExec) == 0) {
        // when called "manually", always send posted events
        QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData);
    }

    if (needWM_QT_SENDPOSTEDEVENTS)
        PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0);

    return retVal;
}

PM MAIL   Вверх
iigor
Дата 24.1.2010, 20:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 12
Регистрация: 7.9.2007

Репутация: нет
Всего: нет



Как мне объяснили, тот "баг", который я думал в qt, оказался в DispatchMessage().   т.е. внутри неё запускается некий дополнительный цикл и qt умеет с ним работать, поэтому нормально отрабатываются сообщения таймера.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Кроссплатформенное программирование, QT/Gtk+/wxWidgets"
JackYF
Любитель
  • В заголовке темы в квадратных скобках обозначьте используемую вами библиотеку, например: [QT],[GTK],[wx].
  • Если вопрос актуален только для некоторой версии библиотеки, либо, если вы пользуетесь не самой последней версией, укажите это. Например: [QT4], [GTK2].
  • Все начинающие изучать Qt - не забудьте зайти сюда.
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • В вопросе укажите полную версию версию библиотеки, а также все дополнительные используемые программные пакеты.
  • Не забывайте пользоваться кнопкой "Код".
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к тематике этого раздела. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, Любитель.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets | Следующая тема »


 




[ Время генерации скрипта: 0.0994 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.