Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets > [QT] Не получается переопределить minimize


Автор: rainbow86 6.1.2008, 17:58
Никак не получается переопределить minimize. Я хочу что б вместо обычного сворачивания приложение сворачивалось в трэй!
Вот код:
Код

bool MyWindow::eventFilter(QObject *obj, QEvent *event)
{
    if(event->type() == QEvent::WindowStateChange)
    {
        QWindowStateChangeEvent * ce = static_cast<QWindowStateChangeEvent*>(event);
        if ((windowState() & Qt::WindowMinimized) && !(ce->oldState() & Qt::WindowMinimized))
        {
            slotMinimizeToTray();
            return true;
        }
        else
            return false;
    }
    else return QMainWindow::eventFilter(obj, event);
}


Функция slotMinimizeToTray()
Код


void MyWindow::slotMinimizeToTray()
{
    hide();
    tray_icon->show();
}



Несмотря на то что возвращается true после slotMinimizeToTray() все равно вызывается стандартный обработчик???

Автор: nickless 6.1.2008, 19:37
rainbow86, попробуй добавить
Код

event->accept();

Автор: rainbow86 8.1.2008, 10:58
Код

event->accept();


не помогает  smile 

Автор: SABROG 8.1.2008, 13:57
А здесь ты смотрел ? examples\desktop\systray\

Автор: rainbow86 8.1.2008, 14:26
Там нету переопределения minimize!!!

Автор: SABROG 8.1.2008, 20:53
Цитата(rainbow86 @ 8.1.2008,  14:26)
Там нету переопределения minimize!!!

Мне кажется это невозможно. И для чего его переопределять, если делается то что нужно - окно исчезает и в трее появляется иконка ?

Автор: JackYF 8.1.2008, 21:30
rainbow86, что говорит отладчик? до твоего куска кода (фильтра и вызова твоего сворачивания в трей) управление доходит?

Автор: rainbow86 9.1.2008, 12:11
Цитата

Мне кажется это невозможно. И для чего его переопределять, если делается то что нужно - окно исчезает и в трее появляется иконка ?

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

Цитата

rainbow86, что говорит отладчик? до твоего куска кода (фильтра и вызова твоего сворачивания в трей) управление доходит?


Код отрабатывает появляется значок в трее, окно исчезает, но потом срабатывает стандартный обработчики окно появляется в свернутом виде. Причем если его развернуть то видна только рамка, т.е. внутри окно пустое!!!

Автор: JackYF 9.1.2008, 12:25
Цитата(rainbow86 @  9.1.2008,  11:11 Найти цитируемый пост)
Причем если его развернуть то видна только рамка, т.е. внутри окно пустое!!!

хм... похоже на то, что происходит ещё одно событие, кроме WindowStateChange, которое тоже надо отменить. Посмотри в списке событий.
Возможно также, что это баг. Какая у тебя версия QT?

Автор: SABROG 9.1.2008, 12:55
Попробуй вместо hide() пропиши:

Код

qApp->activeWindow->hide();


Или используй WinApi http://www.qtcentre.org/forum/showthread.php?t=23

Автор: JackYF 9.1.2008, 13:11
Цитата(SABROG @  9.1.2008,  11:55 Найти цитируемый пост)
Или используй WinApi

это очень плохой выход. Кроссплатформенность летит к чёрту.

Автор: SABROG 9.1.2008, 13:31
Цитата(JackYF @ 9.1.2008,  13:11)
это очень плохой выход. Кроссплатформенность летит к чёрту.

Ну это на тот случай, если человек сдастся и решит под разными осями делать разную реализацию. Тогда включит в блок свой код и проблема исчезнет:

Код

#if defined(Q_WS_WIN)
        ShowWindow(winId(), SW_HIDE);
#else
        hide();
#endif

Автор: JackYF 9.1.2008, 16:38
Цитата(SABROG @  9.1.2008,  12:31 Найти цитируемый пост)
Тогда включит в блок свой код и проблема исчезнет:

не исчезнет, смотри его последнее сообщение. Проблема в том, что происходит лишнее, а не "не происходит то, что хочу".

Автор: SABROG 9.1.2008, 16:50
Исчезнет если использовать 2 реализации перехвата сообщений, одна - WinApi, другая - стандартный метод Qt.

Автор: JackYF 9.1.2008, 19:02
Цитата(SABROG @  9.1.2008,  15:50 Найти цитируемый пост)
2 реализации перехвата сообщений, одна - WinApi, другая - стандартный метод Qt.

это как вообще?..

Автор: rainbow86 9.1.2008, 21:29
Нашел сначала рабочий пример по ссылке http://www.qtcentre.org/forum/showthread.php?t=23 
с помощью переопределения функции

Код

bool minimize::winEvent(MSG *message, long *result)
{
    switch(message->message)
    {
        case WM_SIZE:
        {
            if ( message->wParam == SIZE_MINIMIZED )
            {
                ShowWindow(winId(), SW_HIDE);
                return true;
            }
        }
        break;
    }
    
    return QWidget::winEvent(message, result);
}


Но так как это не кроссплатформенно решил поискать еще и наткнулся на том же сайте вот на такое решение проблемы предложенное самими тролями:

Код


void minimize::changeEvent(QEvent * e )
{
    if (e->type() == QEvent::WindowStateChange) 
    {
        if (isMinimized() == true)
        {
            QTimer::singleShot(0, this, SLOT(hide()));
            e->ignore();
            return;
        }
    }

    QMainWindow::changeEvent( e );
} 


Вот ссылка кому интересно на обсуждение
http://www.qtcentre.org/forum/f-newbie-4/t-problem-hiding-main-window-on-minimize-8826.html

И кроссплатформенно и работает  smile 

Автор: JackYF 9.1.2008, 21:42
Что ж, отличный опыт ).

Добавлено через 5 минут и 23 секунды
только у меня ссылка на обсуждение не открывается?

Автор: SABROG 9.1.2008, 22:12
Грубо говоря, здесь создается еще один, временный поток - thread. Который обеспечивает сокрытие окна вне обработчика событий, т.к. скорее всего, сам метод hide() является генератором события и блокируется.

Код

            QTimer::singleShot(0, this, SLOT(hide()));


Я бы не назвал изящным решением - создание дополнительного потока для таких целей, хоть это и выглядит красиво, но похоже выбор не велик.

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

Код

emit hide_me_please();


А внутри слота под этот сигнал впиши hide(). По идее сигнал hide_me_please должен будет вызываться сразу же после выхода из процедуры обработчика эвентов.

Автор: bsa 9.1.2008, 22:22
SABROG, это не выглядит красиво. Это лишний раз заставляет задуматься, а зачем тут такое безобразие. Поэтому придется еще писать комментарий, который будет объяснять, почему сделано так, а не иначе...

Автор: SABROG 10.1.2008, 20:14
Я ошибся QTimer::singleShot не создает нить, в исходниках Qt на нулевой таймер спец. оптимизация стоит, к тому же программа состоит из двух нитей обычно и в одной из них успешно работают таймеры, пока в другой идет блокирующая функция. Поэтому все что делает singleShot это вызывает PostEvent, который добавляется в очередь сообщений и обрабатывается уже после выхода из фильтра эвентов на следующем цикле.

Автор: SABROG 11.1.2008, 11:20
Я все-таки нашел нормальный способ это сделать, спасибо Владимиру Пузанову из ньюс группы.

Код

connect(this, SIGNAL(signalPlaceToTray()),this, SLOT(slotPlaceToTray()), Qt::QueuedConnection);


Т.е. добавилась фишка Qt::QueuedConnection. Проверил, это работает.

Соответственно в эвенте:

Код

void MinimizeTray::changeEvent(QEvent *event)
{
    if (event->type() == QEvent::WindowStateChange) 
    {
        if (isMinimized())
        {
            event->ignore();
            emit signalPlaceToTray();
            return;
        }
    }
QMainWindow::changeEvent(event);
}


Код

void MinimizeTray::slotPlaceToTray()
{
    tray->show();
    hide();
}


Т.е. я создал свой сигнал и свой слот, законнектил их к друг другу. А флаг позволил сделать отложенную передачу сигнала по возврату в main loop.

 smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)