Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: Magvaj от Март 10, 2009, 23:52



Название: Всплывающие окна
Отправлено: Magvaj от Март 10, 2009, 23:52
Пошукал по форуму, но так и не нашёл ни одного вразумительного примера всплывающего окна. Необходимо что-то в стиле Amarok, когда он уведомления показывает. Или же как окошки мессенджеров, когда приходят сообщения.

Может кто реализовывал и поделится советом какие виджеты использовать и в какую сторону копать?


Название: Re: Всплывающие окна
Отправлено: Alex Custov от Март 11, 2009, 02:36
Посмотреть в исходниках?

Можно ещё побаловаться с флагами, например Qt::X11BypassWindowManagerHint может подойти.


Название: Re: Всплывающие окна
Отправлено: uriel от Март 11, 2009, 08:50
Приделывал подобное уведомление к QMPDClient, ибо очень не хватало. Достаточно создать виджет без указания родительского, установить ему флаги Qt::ToolTip | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint и правильно разместить относительно того места, где оно должно всплывать. :)


Название: Re: Всплывающие окна
Отправлено: kirill от Март 11, 2009, 09:49
Беда в том, что пока оно всплывает юзверь может утащить окно за заголовок.
Приходится отслеживать это и поддергивать, но отставание все равно приличное получается.


Название: Re: Всплывающие окна
Отправлено: uriel от Март 11, 2009, 11:57
Ну это уже от ситуации зависит. :)
Я делал, чтобы при наведении на иконку в трее оно высплывало, а как только курсор вышел за пределы этой иконки - ловко исчезало. А учитывая, что этот виджет не становится активным, то его даже Alt+F7 не возьмёшь.
Да и флаг Qt::FramelessWindowHint вроде бы говорит как раз о том, что рамки у него быть не должно.


Название: Re: Всплывающие окна
Отправлено: sendevent от Март 11, 2009, 15:41
глянь qutim - похожи на qip'овские, ток посимпотичнее. задумано хорошо, реализовано не особо, но можно взять геометрию слайдинга.


Название: Re: Всплывающие окна
Отправлено: Magvaj от Март 11, 2009, 17:39
Посмотреть в исходниках?

Можно ещё побаловаться с флагами, например Qt::X11BypassWindowManagerHint может подойти.

а в windows оно работать будет?


Название: Re: Всплывающие окна
Отправлено: Magvaj от Март 11, 2009, 17:45
глянь qutim - похожи на qip'овские, ток посимпотичнее. задумано хорошо, реализовано не особо, но можно взять геометрию слайдинга.

покопался в коде и сломал мозг. Не понятно у них всё что и откуда.

Решил реализовывать на основе QFrame с флагом Qt::ToolTip.


Название: Re: Всплывающие окна
Отправлено: sendevent от Март 11, 2009, 19:05
по поводу перекрытия панелью задач - хз :)
выдрал из проекта, на компелябельность не проверял, но, думаю, в общих чертах понятно и за скелет взять можно будет:
systraymessage.h
Код:
#include <QWidget>
#include <QTimer>

#include "ui_systraymessage.h"
class SysTrayMessage : public QWidget
{
    Q_OBJECT
    public:
        SysTrayMessage( int, int, int, unsigned int, int, int, QWidget *parent = 0);
        virtual ~SysTrayMessage();
       
        bool m_bIs1stTrayWindow;
       
        void showTrayMessage();
        void setHtml( const QString & );
        void setColor( const QColor& color );
        void setTitle( const QString & );
       
        inline int getStackPosition() const { return m_iStackPos; }
    protected:
        virtual void construct( int iWidthPx, int iHeightPx, int iTimeS, unsigned int uiScreenCorner,
        int iSlideStyle, int iStackPos );
       
    protected slots:
    void slideVerticallyUp();
    void slideVerticallyDown();
    void slideHorizontallyRight();
    void slideHorizontallyLeft();
public slots:
        void close();
private:
       
        Ui::SysTrayMessageUi ui;
        unsigned int m_uiScreenCorner;
        int m_iSlideStyle;
        int m_iTTLSecs;
        int m_iStackPos;
        int fromX;
        int fromY;
        int m_iWidth, m_iHeigth;
       
        QColor m_color;
       
        QTimer m_timer;
               
        QPoint m_ptPrevPos, m_ptSlideDst;
       
        void slide();
        void calcCoords();
       
    signals:
        void signalClosed();       
};
systraymessage.cpp
Код:
#include "systraymessage.h"

#include <QPalette>
#include <QColor>
#include <QDesktopWidget>

SysTrayMessage::SysTrayMessage( int width, int height, int t,
unsigned int pos, int st, int psInStack, QWidget *parent)
:QWidget(parent)
{
    construct( width, height, t, pos, st, psInStack );
}

/*virtual*/ void SysTrayMessage::construct( int iWidthPx, int iHeightPx, int iTimeS,
    unsigned int uiScreenCorner, int iSlideStyle, int iStackPos )
{
    ui.setupUi(this);
   
    fromX = 0;
fromY = 0;

    m_iWidth = iWidthPx;
m_iHeigth = iHeightPx;
resize( QSize( m_iWidth, m_iHeigth ) );

    m_uiScreenCorner uiScreenCorner;
    m_iSlideStyle = iSlideStyle;
    m_iTTLSecs = iTimeS;
    m_iStackPos = iStackPos;
    m_bIs1stTrayWindow = true;
m_ptPrevPos = QPoint( 0, 0 );
m_timer.setInterval( m_iTTLSecs*1000 );
   
connect( &m_timer, SIGNAL( timeout() ), this, SLOT( close() ) );

#if defined(Q_OS_MAC)
setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
#else
setWindowFlags( Qt::CustomizeWindowHint|Qt::WindowStaysOnTopHint|Qt::ToolTip );
#endif
}
       
SysTrayMessage::~SysTrayMessage()
{   
}

void SysTrayMessage::showTrayMessage()
{
    show();
    calcCoords();
    m_timer.start();
    slide();
}

void SysTrayMessage::calcCoords()
{
    QDesktopWidget desktopSize;
QRect geometry = desktopSize.availableGeometry();

resize( m_iWidth, m_iHeigth );
switch(m_uiScreenCorner)
{
case ScreenCornerPosition::TopLeft:
m_ptSlideDst = QPoint( geometry.left(), geometry.top() + (m_iStackPos - 1) * m_iHeigth );
break;
case ScreenCornerPosition::TopRight:
m_ptSlideDst = QPoint( geometry.right() - m_iWidth, geometry.top() + (m_iStackPos - 1) * m_iHeigth );
break;
case ScreenCornerPosition::BottomLeft:
m_ptSlideDst = QPoint( geometry.left(), geometry.bottom() - m_iStackPos * m_iHeigth );
break;
default:
m_ptSlideDst = QPoint( geometry.right() - m_iWidth, geometry.bottom() - m_iStackPos * m_iHeigth );
}
}

void SysTrayMessage::close()
{
    //-- custom process...
    ...
    QWidget::close();
    emit signalClosed();
}


void SysTrayMessage::slide()
{   
    switch (m_iSlideStyle)
    {
    case 1:
        if( m_uiScreenCorner == ScreenCornerPosition::TopLeft
        || m_uiScreenCorner == ScreenCornerPosition::TopRight )
        {
            fromX = m_ptSlideDst.x();
            fromY = m_ptSlideDst.y()-height();
            move( fromX, fromY );
            show();
            slideVerticallyDown();
        }
        else if( m_uiScreenCorner == ScreenCornerPosition::BottomLeft
        || m_uiScreenCorner == ScreenCornerPosition::BottomRight)
        {
            fromX = m_ptSlideDst.x();
            fromY = m_ptSlideDst.y() + height();
            move( fromX, fromY );
           
            show();
            slideVerticallyUp();
        }
        break;
    case 0:
        if( m_uiScreenCorner == ScreenCornerPosition::TopLeft
        || m_uiScreenCorner == ScreenCornerPosition::BottomLeft )
        {
            fromX = m_ptSlideDst.x() - width();
            fromY = m_ptSlideDst.y();
            move( fromX, fromY );
           
            show();
            slideHorizontallyRight();
        }
        else if( m_uiScreenCorner == ScreenCornerPosition::TopRight
        || m_uiScreenCorner == ScreenCornerPosition::BottomRight
        )
        {
            fromX = m_ptSlideDst.x() + width();
            fromY = m_ptSlideDst.y();
            move( fromX, fromY );
            show();
            slideHorizontallyLeft();
        }
        break;
    default:
        move( m_ptSlideDst );
        show();
    }
}

void SysTrayMessage::slideVerticallyUp()
{
fromY -= 5;

if (fromY >= m_ptSlideDst.y())
    {
        move(m_ptSlideDst.x(), fromY);
        QTimer::singleShot(10, this, SLOT(slideVerticallyUp()));
    }
}

void SysTrayMessage::slideVerticallyDown()
{
fromY += 5;
if (fromY <= m_ptSlideDst.y())
{
move(m_ptSlideDst.x(), fromY);
QTimer::singleShot(10, this, SLOT(slideVerticallyDown()));
}
}

void SysTrayMessage::slideHorizontallyRight()
{
fromX += 5;
if (fromX <= m_ptSlideDst.x())
{
move(fromX, m_ptSlideDst.y());
QTimer::singleShot(10, this, SLOT(slideHorizontallyRight()));
}
}

void SysTrayMessage::slideHorizontallyLeft()
{
fromX -= 5;
if (fromX >= m_ptSlideDst.x())
{
move(fromX, m_ptSlideDst.y());
QTimer::singleShot(10, this, SLOT(slideHorizontallyLeft()));
}
}

void SysTrayMessage::setHtml( const QString& html )
{
    ui.textDisplay->setHtml( html );
}

void SysTrayMessage::setColor( const QColor& color )
{
    m_color = color;
    this->setStyleSheet( QString( "background-color: rgb(%1, %2, %3);" )
        .arg( m_color.red() ).arg( m_color.green() ).arg( m_color.blue() ) );
}

void SysTrayMessage::setTitle( const QString &title )
{
    ui.label->setText( title );
    ui.label->setToolTip( title );
}

использование:
Код:
SysTrayMessage* SysTrayMessageFactory::createMessage( const QString& title, const QString& msg, bool delOnClose )
{
    if ( !m_b1stMsgShown )
{
m_b1stMsgShown = true;
m_iMsgCellInStack = 1;
}

SysTrayMessage *trayMessageWindow = new SysTrayMessage( m_iMsgWidth,
m_iMsgHeight, m_iMsgTTLSecs, m_uiMsgScrCorner,
m_iMsgStyle, m_iMsgCellInStack );

trayMessageWindow->m_bIs1stTrayWindow = m_b1stMsgShown;
trayMessageWindow->setColor( m_color );
trayMessageWindow->setTitle( title );
    trayMessageWindow->setHtml( msg );
   
    if( delOnClose )
        trayMessageWindow->setAttribute( Qt::WA_DeleteOnClose );

connect( trayMessageWindow, SIGNAL( signalClosed() ),
this, SLOT( slotUpdateSysTrayMessagesList() ) );

if ( ( ++m_iMsgCellInStack ) > 5)
        m_iMsgCellInStack = 5;

trayMessagesList.append( trayMessageWindow );

return trayMessageWindow;
}

void SysTrayMessageFactory::slotUpdateSysTrayMessagesList()
{
    SysTrayMessage *tempWindow = qobject_cast<SysTrayMessage*>( sender() );

if( tempWindow )
{
    if( !trayMessagesList.count() )
    {//-- smth wrong :-[
        disconnect( tempWindow, SIGNAL( signalClosed() ),
            this, SLOT( slotUpdateSysTrayMessagesList() ) );
       
        tempWindow->close();
        return;
    }
    else
    {
        if ( tempWindow->m_bIs1stTrayWindow )
        m_b1stMsgShown = false;
       
        int index = trayMessagesList.indexOf( tempWindow );
        if( index >= 0 )
        {
            trayMessagesList.takeAt( index );
            qDebug( "SysTrayMessageFactory::slotUpdateSysTrayMessagesList: msg removed!" );
            m_iMsgCellInStack--;
        }
    }
    qDebug( "SysTrayMessageFactory::slotUpdateSysTrayMessagesList: msges amount: %d", trayMessagesList.count() );
}
}

SysTrayMessageFactory и юай приводить лень, будут вопросы - постараюсь ответить=)


Название: Re: Всплывающие окна
Отправлено: Magvaj от Март 15, 2009, 12:12
sendevent, благодарю за код... в принципе- то что я хотел, только ввиду срочности и напора со стороны начальства пришлось ночами в темпе марша реализовывать самому.

Удалось выяснить факт: виджет не перекрывается панелью задач только в случае если он будет отображаться в виде окна на панельке. В остальных случаях он всегда перекрывает её.

Реализовал класс для виджета ToolTip и управляющий для нормальной анимации и перепозиционирования виджетов в случае удаления некоторых. Так же есть реакции на различные действия со стороны устройств ввода. Класс прекрасно пашет под Win и Lin. Компилится без требований спецефичных классов. Если кому потребуется- пишите в личку- скину код ;-) (сюда выложить не могу по понятным причинам)


Название: Re: Всплывающие окна
Отправлено: kirill от Март 15, 2009, 18:34
Ну это уже от ситуации зависит. :)
Я делал, чтобы при наведении на иконку в трее оно высплывало, а как только курсор вышел за пределы этой иконки - ловко исчезало. А учитывая, что этот виджет не становится активным, то его даже Alt+F7 не возьмёшь.
Да и флаг Qt::FramelessWindowHint вроде бы говорит как раз о том, что рамки у него быть не должно.

Я не про рамку у подсказки, а у того окна к которому оно привязано.
Если показывать в трее, то понятно что этой проблемы нет.
А если привязывать к онку, которое можно елозить, то отставание.


Название: Re: Всплывающие окна
Отправлено: AlekseyK от Сентябрь 23, 2009, 19:18
Я делал, чтобы при наведении на иконку в трее оно высплывало, а как только курсор вышел за пределы этой иконки - ловко исчезало.
А можно поподробнее, пожалуйста как это сделать?

Я переопределил mouseMoveEvent(QMouseEvent *event) в моём всплывающем виджете, но что-то он на движения мыши вообще никак не реагирует (смотрю через отладчик), не говоря о том уже, чтобы спрятаться:

Код
C++ (Qt)
void MyWidget::mouseMoveEvent(QMouseEvent *event)
{
   QWidget::mouseMoveEvent(event);
   if(event->type() == QEvent::Leave)
       hide();
}

Нужно как-то по другому делать?


Название: Re: Всплывающие окна
Отправлено: uriel от Октябрь 07, 2009, 17:59
Извиняюсь, вопрос увидел только сейчас. Видимо, не помешает взять в привычку проверять ответы на свои сообщения при каждом посещении. :)
Оно всё ещё актуально?