WTL: Подсказка в любом месте экрана
От: WinterMute Россия http://yarrr.ru
Дата: 18.08.04 14:15
Оценка:
В своё время меня не устроил стандартный CTooltipCtrl -- мне была нужена подсказка которая бы появлялась и пропадала когда ей скажут. Кроме того, нужно было, что бы подсказка была прозрачна для всех сообщений мыши (я делал т.н. inplace tooltip). Этот простой класс делает всё вышеперечисленное.

Короткое описание:

Маленькое замечание: при создании нужно указать окно хозяин, и это не тоже самое что окно владелец(m_hWndOwner). В качестве хозяина удобнее всего установить ::GetDesktopWindow(), в противном случае возникают малопонятные глюки с позиционированием.

namespace UI2
{
    class Tooltip
        : public CWindowImpl<Tooltip, ATL::CWindow>
    {
    public:
        typedef CWindowImpl<Tooltip, ATL::CWindow> baseClass;
        typedef Tooltip thisClass;

        HWND     m_hWndOwner;

    private:
        TOOLINFO m_ToolInfo;
        bool     m_bActive;

        enum { TIMER_MSG_DELAY_SHOW = 100, TIMER_MSG_DELAY_HIDE = 101, };

        static LPCTSTR GetWndClassName(){ return _T("Zaebis_Tooltip"); }

    public:
        DECLARE_WND_SUPERCLASS(GetWndClassName(), baseClass::GetWndClassName())

        BEGIN_MSG_MAP(thisClass)
            MESSAGE_HANDLER(WM_TIMER, OnTimer)
            MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage)
        END_MSG_MAP()


        Tooltip()
        : baseClass()
        , m_bActive(false)  // подсказка видна
        , m_hWndOwner(0)    // окно, которому будут передаваться мышиные сообщения
        {
        }

        virtual ~Tooltip()
        { }

        bool Create( HWND hWndParent, HWND hWndOwner = NULL )
        {
            HWND hWnd = ::CreateWindowEx(WS_EX_TOPMOST,
                TOOLTIPS_CLASS,
                NULL,
                TTS_NOPREFIX | TTS_ALWAYSTIP,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                hWndParent,
                NULL,
                NULL,
                NULL);

            ATLASSERT(hWnd);

            // initialize toolinfo struct
            memset(&m_ToolInfo, 0, sizeof(m_ToolInfo));
            m_ToolInfo.cbSize = sizeof(m_ToolInfo);
            m_ToolInfo.uFlags = TTF_TRACK | TTF_TRANSPARENT | TTF_SUBCLASS;
            m_ToolInfo.hwnd = hWndParent;

            ::SendMessage(hWnd, TTM_SETMAXTIPWIDTH, 0, SHRT_MAX);
            ::SendMessage(hWnd, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &m_ToolInfo);

            m_hWndOwner = hWndOwner;

            SubclassWindow( hWnd );

            return true;
        }

        void SetBackColor( COLORREF c ){ ::SendMessage(m_hWnd, TTM_SETTIPBKCOLOR, c, 0); }
        void SetTextColor( COLORREF c ){ ::SendMessage(m_hWnd, TTM_SETTIPTEXTCOLOR, c, 0); }
        void SetMargins( const RECT* rectMargins ){ ::SendMessage(m_hWnd, TTM_SETMARGIN, 0, (LPARAM)rectMargins); }
        void SetMaxWidth( int maxWidth ){ ::SendMessage(m_hWnd, TTM_SETMAXTIPWIDTH, 0, (LPARAM)maxWidth); }

        bool IsVisible(){ return m_bActive; };

        CString GetText()
        {
            ::SendMessage( m_hWnd, TTM_GETTEXT, 0, m_ToolInfo );
            return CString( m_ToolInfo.lpszText );
        }

        void SetText( const TCHAR* str )
        {
            delete m_ToolInfo.lpszText;
            if( str )
            {
                m_ToolInfo.lpszText = new TCHAR[ _tcslen(str)+1 ];
                _tcscpy( m_ToolInfo.lpszText, str );
            }
            else m_ToolInfo.lpszText = NULL;

            ::SendMessage( m_hWnd, TTM_UPDATETIPTEXT, 0, (LPARAM)(LPTOOLINFO) &m_ToolInfo );
        }

        void Show( int x, int y )
        {
            m_bActive = true;

            ::SendMessage( m_hWnd, TTM_TRACKPOSITION, 0, (LPARAM)(DWORD) MAKELONG( x, y ) );
            ::SendMessage( m_hWnd, TTM_TRACKACTIVATE, TRUE, (LPARAM)(LPTOOLINFO) &m_ToolInfo );
        }

        void Show( const RECT* r )
        {
            m_bActive = true;

            m_ToolInfo.rect = *r;

            ::SendMessage( m_hWnd, TTM_TRACKPOSITION, 0, (LPARAM)(DWORD) MAKELONG( r->left, r->top ) );
            ::SendMessage( m_hWnd, TTM_SETMAXTIPWIDTH, 0, (LPARAM)(r->right - r->left) );
            ::SendMessage( m_hWnd, TTM_TRACKACTIVATE, TRUE, (LPARAM)(LPTOOLINFO)&m_ToolInfo );
        }

        void Show( BOOL bShow = TRUE )
        {
            KillTimer( TIMER_MSG_DELAY_SHOW );
            KillTimer( TIMER_MSG_DELAY_HIDE );

            m_bActive = (bShow == TRUE);

            ::SendMessage( m_hWnd, TTM_TRACKACTIVATE, bShow, (LPARAM)(LPTOOLINFO) &m_ToolInfo );
        }

        void Move( int x, int y )
        {
            ::SendMessage( m_hWnd, TTM_TRACKPOSITION, 0, (LPARAM)(DWORD) MAKELONG( x, y ) );
        }

        void DelayShowAtCursor( UINT timeToShow )
        {
            KillTimer( TIMER_MSG_DELAY_SHOW );
            SetTimer( TIMER_MSG_DELAY_SHOW, timeToShow );
        }

        operator HWND() { return m_hWnd; }


        // Message handlers

        LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
        {
            if( TIMER_MSG_DELAY_SHOW == wParam )
            {
                POINT pt; ::GetCursorPos( &pt );
                Show( pt.x, pt.y+20 );
                KillTimer( wParam );
            }
            else if( TIMER_MSG_DELAY_HIDE == wParam )
            {
                Show(FALSE);
                KillTimer( wParam );
            }

            bHandled = FALSE;
            return 0;
        }

        LRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
        {
            // forward message to owner window 
            if( m_hWndOwner )
            {
                POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
                ClientToScreen( &pt ); ::ScreenToClient( m_hWndOwner, &pt );
                lParam = PtToLPARAM(pt);

                ::SendMessage( m_hWndOwner, uMsg, wParam, lParam );
            }

            bHandled = TRUE;
            return 0;
        }
    };

    // ----------------------------------------------------
    
    inline LPARAM PtToLPARAM( POINT pt )
    {
        LPARAM lParam = 0;
        WORD*  pLParam = (WORD*)&lParam;
    
        pLParam[0] = (short)pt.x;
        pLParam[1] = (short)pt.y;
    
        return lParam;
    }
}
Думай, что хочешь, делай, что хочешь, живи, как хочешь -- всё тебе припомню!!
Re: WTL: Подсказка в любом месте экрана
От: _nn_ www.nemerleweb.com
Дата: 18.08.04 16:25
Оценка:
Здравствуйте, WinterMute, Вы писали:

А в чем выражается нужда в виртуальном деструкторе ?

Еще хочу заметить что в WTL принято делать два класса : SomeClassImpl в котором вся функциональность и SomeClass производный от SomeClassImpl, где устанавливается класс окна через DECLARE_WND_SUPERCLASS.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: WTL: Подсказка в любом месте экрана
От: WinterMute Россия http://yarrr.ru
Дата: 18.08.04 16:57
Оценка:
__>А в чем выражается нужда в виртуальном деструкторе ?
Да ни в чём, убрать конечно же.

__>Еще хочу заметить что в WTL принято делать два класса : SomeClassImpl в котором вся функциональность и SomeClass производный от SomeClassImpl, где устанавливается класс окна через DECLARE_WND_SUPERCLASS.


Знаю, но в этом случае с трудом представляю зачем это может понадобиться.
Думай, что хочешь, делай, что хочешь, живи, как хочешь -- всё тебе припомню!!
Re[3]: WTL: Подсказка в любом месте экрана
От: _nn_ www.nemerleweb.com
Дата: 19.08.04 06:38
Оценка:
Здравствуйте, WinterMute, Вы писали:

__>>А в чем выражается нужда в виртуальном деструкторе ?

WM>Да ни в чём, убрать конечно же.


__>>Еще хочу заметить что в WTL принято делать два класса : SomeClassImpl в котором вся функциональность и SomeClass производный от SomeClassImpl, где устанавливается класс окна через DECLARE_WND_SUPERCLASS.


WM>Знаю, но в этом случае с трудом представляю зачем это может понадобиться.

Для того чтобы кто-то смог в дальнейшем расширить функциональность класса.
Так принято в WTL и отходить от этого стиля не стоит.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[4]: WTL: Подсказка в любом месте экрана
От: WinterMute Россия http://yarrr.ru
Дата: 19.08.04 21:24
Оценка:
Здравствуйте, _nn_, Вы писали:

WM>>Знаю, но в этом случае с трудом представляю зачем это может понадобиться.

__>Для того чтобы кто-то смог в дальнейшем расширить функциональность класса.

Да нафиг, и так нормально работает . KISS
Думай, что хочешь, делай, что хочешь, живи, как хочешь -- всё тебе припомню!!
Re: WTL: Подсказка в любом месте экрана
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 20.08.04 06:48
Оценка:
Здравствуйте, WinterMute, Вы писали:

WM>


      ~Tooltip()
      { 
          delete m_ToolInfo.lpszText; // << иначе утекает при уничтожении окна с текстом
          m_ToolInfo.lpszText = NULL;
      }


WM> ...

WM>        CString GetText()
WM>        {
WM>            //::SendMessage( m_hWnd, TTM_GETTEXT, 0, m_ToolInfo ); << очипатка, должно быть
               ::SendMessage( m_hWnd, TTM_GETTEXT, 0, (LPARAM)&m_ToolInfo );
                
WM>            return CString( m_ToolInfo.lpszText );
WM>        }

WM>
Re: WTL: Подсказка в любом месте экрана
От: _nn_ www.nemerleweb.com
Дата: 20.08.04 07:46
Оценка:
Здравствуйте, WinterMute, Вы писали:

::SendMessage(m_hWnd...)
В чем смысл в этм если можно писать просто SendMessage ?

Функцию PtToLPARAM слудует пересмотреть, можно это заменить одной строкой
Вдобавок лучше ее сделать статической функцией класса.

По возможности стоит избегать использования CString в классе или же через условную компиляцию добавлять функции.
А то не все пользуются CString и может вылезти ошибка.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: WTL: Подсказка в любом месте экрана
От: WinterMute Россия http://yarrr.ru
Дата: 20.08.04 08:24
Оценка:
Здравствуйте, _nn_, Вы писали:

__>Здравствуйте, WinterMute, Вы писали:


__>::SendMessage(m_hWnd...)

__>В чем смысл в этм если можно писать просто SendMessage ?

Как то пришлось переносить WTL-ные библиотеки на WinApi, теперь, если не особой разницы, я стараюсь пользоваться API функциями.

__>Функцию PtToLPARAM слудует пересмотреть, можно это заменить одной строкой


Как? Напиши пож, а то я сначала сделал одной строкой, дак она глючила.

__>Вдобавок лучше ее сделать статической функцией класса.


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

__>По возможности стоит избегать использования CString в классе или же через условную компиляцию добавлять функции.

__>А то не все пользуются CString и может вылезти ошибка.

Приму во внимание.
Думай, что хочешь, делай, что хочешь, живи, как хочешь -- всё тебе припомню!!
Re[2]: WTL: Подсказка в любом месте экрана
От: WinterMute Россия http://yarrr.ru
Дата: 20.08.04 08:24
Оценка:
Здравствуйте, Odi$$ey, Вы писали:

OE>Здравствуйте, WinterMute, Вы писали:



OE>
OE>      ~Tooltip()
OE>      { 
OE>          delete m_ToolInfo.lpszText; // << иначе утекает при уничтожении окна с текстом
OE>          m_ToolInfo.lpszText = NULL;
OE>      }
OE>

Вот это большое спасибо. У меня подсказка создавалась статически, поэтому наверное, и не заметил.


WM>> ...



WM>>        CString GetText()
WM>>        {
WM>>            //::SendMessage( m_hWnd, TTM_GETTEXT, 0, m_ToolInfo ); << очипатка, должно быть
OE>               ::SendMessage( m_hWnd, TTM_GETTEXT, 0, (LPARAM)&m_ToolInfo );
                
WM>>            return CString( m_ToolInfo.lpszText );
WM>>        }


Ага, добавил в последний момент, мне то она была не нужна.
Думай, что хочешь, делай, что хочешь, живи, как хочешь -- всё тебе припомню!!
Re[3]: WTL: Подсказка в любом месте экрана
От: _nn_ www.nemerleweb.com
Дата: 20.08.04 09:14
Оценка:
Здравствуйте, WinterMute, Вы писали:

WM>Здравствуйте, _nn_, Вы писали:


__>>Здравствуйте, WinterMute, Вы писали:


__>>::SendMessage(m_hWnd...)

__>>В чем смысл в этм если можно писать просто SendMessage ?

WM>Как то пришлось переносить WTL-ные библиотеки на WinApi, теперь, если не особой разницы, я стараюсь пользоваться API функциями.

По CString это не заметно
А вообще все же не принято писать ::SendMessage(m_hWnd...)
Это выглядит мазохизмом, мы ведь в WTL пишем все же

__>>Функцию PtToLPARAM слудует пересмотреть, можно это заменить одной строкой


WM>Как? Напиши пож, а то я сначала сделал одной строкой, дак она глючила.

Ну попробую :
Оригинал :
 inline LPARAM PtToLPARAM( POINT pt )
    {
        LPARAM lParam = 0;
        WORD*  pLParam = (WORD*)&lParam;
    
        pLParam[0] = (short)pt.x;
        pLParam[1] = (short)pt.y;
    
        return lParam;
    }

В младщую чать идет координата x, а в старшую часть идет координата y.
inline LPARAM PtToLPARAM(const POINT& pt)
{ return (LPARAM)(pt.x+pt.y<<16); }

Или же можно воспользоваться MAKEWORD
MAKEWORD(pt.x,pt.y)
И все

__>>Вдобавок лучше ее сделать статической функцией класса.


WM>Мне она была нужна и в других классах, поэтому она глобальная.

Понятно.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[4]: WTL: Подсказка в любом месте экрана
От: WinterMute Россия http://yarrr.ru
Дата: 20.08.04 13:18
Оценка:
Здравствуйте, _nn_, Вы писали:

__>Здравствуйте, WinterMute, Вы писали:


WM>>Здравствуйте, _nn_, Вы писали:


__>>>Здравствуйте, WinterMute, Вы писали:


__>>>::SendMessage(m_hWnd...)

__>>>В чем смысл в этм если можно писать просто SendMessage ?

WM>>Как то пришлось переносить WTL-ные библиотеки на WinApi, теперь, если не особой разницы, я стараюсь пользоваться API функциями.

__>По CString это не заметно

Я СString тоже переносил, как-то хитро откусывая хвосты. И в случае чего опроедлить свой "CString" не проблема, там ведь всё что от СString используется это конструирование из константной строки и приведение к константной строке, такое из std::string в два счёта делается. А использовать строки без обёрток это как-то не по мне.

__>А вообще все же не принято писать ::SendMessage(m_hWnd...)

__>Это выглядит мазохизмом, мы ведь в WTL пишем все же

Правильно, я же мазохист .

__>>>Функцию PtToLPARAM слудует пересмотреть, можно это заменить одной строкой


WM>>Как? Напиши пож, а то я сначала сделал одной строкой, дак она глючила.

__>Ну попробую :
__>Оригинал :
__>
__> inline LPARAM PtToLPARAM( POINT pt )
__>    {
__>        LPARAM lParam = 0;
__>        WORD*  pLParam = (WORD*)&lParam;
    
__>        pLParam[0] = (short)pt.x;
__>        pLParam[1] = (short)pt.y;
    
__>        return lParam;
__>    }
__>

__>В младщую чать идет координата x, а в старшую часть идет координата y.
__>
__>inline LPARAM PtToLPARAM(const POINT& pt)
__>{ return (LPARAM)(pt.x+pt.y<<16); }
__>


Это работает только если координаты положительны.

__>Или же можно воспользоваться MAKEWORD

__>MAKEWORD(pt.x,pt.y)
__>И все

Да, похоже на то, только MAKELONG.
Думай, что хочешь, делай, что хочешь, живи, как хочешь -- всё тебе припомню!!
Re[2]: Поправить конструктор
От: WinterMute Россия http://yarrr.ru
Дата: 20.08.04 16:54
Оценка: +1
Здравствуйте, Odi$$ey, Вы писали:

WM>>

OE>
OE>      ~Tooltip()
OE>      { 
OE>          delete m_ToolInfo.lpszText; // << иначе утекает при уничтожении окна с текстом
OE>          m_ToolInfo.lpszText = NULL;
OE>      }
OE>

WM>>


Да, нужно еще поправить конструктор, иначе вызов деструктора объекта для которого не был применён метод Create приведёт к неопределённому поведению.

Правильный конструктор:

        Tooltip()
        : baseClass()
        , m_bActive(false)
        , m_hWndOwner(0)
        {
            memset(&m_ToolInfo, 0, sizeof(m_ToolInfo));
        }
Думай, что хочешь, делай, что хочешь, живи, как хочешь -- всё тебе припомню!!
Итого: WTL: Подсказка в любом месте экрана
От: WinterMute Россия http://yarrr.ru
Дата: 20.08.04 16:54
Оценка: 12 (1)
Всем спасибо за сделанные замечания. Вот поправленная версия:

namespace UI2
{
    class Tooltip
        : public CWindowImpl<Tooltip, ATL::CWindow>
    {
    public:
        typedef CWindowImpl<Tooltip, ATL::CWindow> baseClass;
        typedef Tooltip thisClass;

        HWND     m_hWndOwner;

    private:
        TOOLINFO m_ToolInfo;
        bool     m_bActive;
        bool     m_bShowAtCursor;

        enum { TIMER_MSG_DELAY_SHOW = 100, TIMER_MSG_DELAY_HIDE = 101, };

        static LPCTSTR GetWndClassName(){ return _T("Zaebis_Tooltip"); }

    public:
        DECLARE_WND_SUPERCLASS(GetWndClassName(), baseClass::GetWndClassName())

        BEGIN_MSG_MAP(thisClass)
            MESSAGE_HANDLER(WM_TIMER, OnTimer)
            MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage)
        END_MSG_MAP()


        Tooltip()
        : baseClass()
        , m_bActive(false)
        , m_hWndOwner(0)
        {
            memset(&m_ToolInfo, 0, sizeof(m_ToolInfo));
        }

        ~Tooltip()
        { 
            delete m_ToolInfo.lpszText;
            m_ToolInfo.lpszText = NULL;
        }

        bool Create( HWND hWndParent, HWND hWndOwner = NULL )
        {
            HWND hWnd = ::CreateWindowEx(WS_EX_TOPMOST,
                TOOLTIPS_CLASS,
                NULL,
                TTS_NOPREFIX | TTS_ALWAYSTIP,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                hWndParent,
                NULL,
                NULL,
                NULL);

            ATLASSERT(hWnd);

            // initialize toolinfo struct
            memset(&m_ToolInfo, 0, sizeof(m_ToolInfo));
            m_ToolInfo.cbSize = sizeof(m_ToolInfo);
            m_ToolInfo.uFlags = TTF_TRACK | TTF_TRANSPARENT | TTF_SUBCLASS;
            m_ToolInfo.hwnd = hWndParent;

             m_hWndOwner = hWndOwner;

            ::SendMessage( hWnd, TTM_SETMAXTIPWIDTH, 0, SHRT_MAX);
            ::SendMessage( hWnd, TTM_ADDTOOL, 0, (LPARAM)(LPTOOLINFO)&m_ToolInfo);

            SubclassWindow( hWnd );

            return true;
        }

        void SetBackColor( COLORREF c ){ ::SendMessage( m_hWnd, TTM_SETTIPBKCOLOR, c, 0 ); }
        void SetTextColor( COLORREF c ){ ::SendMessage( m_hWnd, TTM_SETTIPTEXTCOLOR, c, 0 ); }
        void SetMargins( const RECT* rectMargins ){ ::SendMessage(m_hWnd, TTM_SETMARGIN, 0, (LPARAM)rectMargins ); }
        void SetMaxWidth( int maxWidth ){ ::SendMessage( m_hWnd, TTM_SETMAXTIPWIDTH, 0, (LPARAM)maxWidth ); }

        bool IsVisible(){ return m_bActive; };

        CString GetText()
        {
            ::SendMessage( m_hWnd, TTM_GETTEXT, 0, (LPARAM)&m_ToolInfo );
            return CString( m_ToolInfo.lpszText );
        }

        void SetText( const TCHAR* str )
        {
            delete m_ToolInfo.lpszText;

            if( str )
            {
                m_ToolInfo.lpszText = new TCHAR[ _tcslen(str)+1 ];
                _tcscpy( m_ToolInfo.lpszText, str );
            }
            else m_ToolInfo.lpszText = NULL;

            ::SendMessage( m_hWnd, TTM_UPDATETIPTEXT, 0, (LPARAM)&m_ToolInfo );
        }

        void Move( int x, int y )
        {
            ::SendMessage( m_hWnd, TTM_TRACKPOSITION, 0, (LPARAM)(DWORD)MAKELONG( x, y ) );
        }

        void Show( int x, int y )
        {
            Move( x, y );
            Show();
        }

        void Show( const RECT* r )
        {
            m_bActive = true;
            m_ToolInfo.rect = *r;

            ::SendMessage( m_hWnd, TTM_TRACKPOSITION, 0, (LPARAM)(DWORD) MAKELONG( r->left, r->top ) );
            ::SendMessage( m_hWnd, TTM_SETMAXTIPWIDTH, 0, (LPARAM)(r->right - r->left) );
            ::SendMessage( m_hWnd, TTM_TRACKACTIVATE, TRUE, (LPARAM)&m_ToolInfo );
        }

        void Show( BOOL bShow = TRUE )
        {
            m_bActive = (bShow == TRUE);
            ::SendMessage( m_hWnd, TTM_TRACKACTIVATE, bShow, (LPARAM)&m_ToolInfo );
        }

        void ShowAtCursor()
        {
            POINT pt; ::GetCursorPos( &pt );
            Show( pt.x, pt.y+20 );
        }

        void ShowAfter( UINT delay, bool bAtCursor = false )
        {
            if( IsWindow() )
            {
                m_bShowAtCursor = bAtCursor;

                KillTimer( TIMER_MSG_DELAY_SHOW );
                SetTimer( TIMER_MSG_DELAY_SHOW, delay );
            }
        }

        void ShowAtCursorAfter( UINT delay )
        {
            ShowAfter( delay, true );
        }

        void HideAfter( UINT delay )
        {
            if( IsWindow() )
            {
                KillTimer( TIMER_MSG_DELAY_HIDE );
                SetTimer( TIMER_MSG_DELAY_HIDE, delay );
            }
        }

        void CancelShowAfter()
        {
            KillTimer( TIMER_MSG_DELAY_SHOW );
        }

        void CancelHideAfter()
        {
            KillTimer( TIMER_MSG_DELAY_HIDE );
        }

        operator HWND() { return m_hWnd; }


        // Message handlers

        LRESULT OnTimer( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
        {
            if( TIMER_MSG_DELAY_SHOW == wParam )
            {
                m_bShowAtCursor?ShowAtCursor():Show();
        KillTimer( wParam );
            }
            else if( TIMER_MSG_DELAY_HIDE == wParam )
            {
                Show(FALSE);
                KillTimer( wParam );
            }

            bHandled = FALSE;
            return 0;
        }

        LRESULT OnMouseMessage( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
        {
            // forward message to owner window 
            if( m_hWndOwner )
            {
                POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
                ClientToScreen( &pt ); ::ScreenToClient( m_hWndOwner, &pt );
                ::SendMessage( m_hWndOwner, uMsg, wParam, MAKELONG( pt.x, pt.y ) );
            }

            bHandled = TRUE;
            return 0;
        }
    };
}
Думай, что хочешь, делай, что хочешь, живи, как хочешь -- всё тебе припомню!!
Re: Итого: WTL: Подсказка в любом месте экрана
От: _nn_ www.nemerleweb.com
Дата: 20.08.04 17:42
Оценка:
Здравствуйте, WinterMute, Вы писали:

WM>Всем спасибо за сделанные замечания. Вот поправленная версия:


Еще поправка :
LPCTSTR GetText()
{
  SendMessage(TTM_GETTEXT, 0, (LPARAM)&m_ToolInfo);
  return m_ToolInfo.lpszText;
}


Кроме того что это избавляет от использования CString, это не вызвает лишний конструктор.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: Итого: WTL: Подсказка в любом месте экрана
От: WinterMute Россия http://yarrr.ru
Дата: 20.08.04 21:56
Оценка:
__>Еще поправка :
__>
__>LPCTSTR GetText()
__>{
__>  SendMessage(TTM_GETTEXT, 0, (LPARAM)&m_ToolInfo);
__>  return m_ToolInfo.lpszText;
__>}
__>


__>Кроме того что это избавляет от использования CString, это не вызвает лишний конструктор.


Ты прав, константный указатель на строку лучше.
Думай, что хочешь, делай, что хочешь, живи, как хочешь -- всё тебе припомню!!
Re[5]: WTL: Подсказка в любом месте экрана
От: _nn_ www.nemerleweb.com
Дата: 21.08.04 06:56
Оценка:
Здравствуйте, WinterMute, Вы писали:

WM>Это работает только если координаты положительны.


WM>Да, похоже на то, только MAKELONG.

Конечно

Так устроит ?
MAKELONG((short)pt.x,(short)pt.y)
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[6]: WTL: Подсказка в любом месте экрана
От: WinterMute Россия http://yarrr.ru
Дата: 21.08.04 10:27
Оценка:
__>Так устроит ?
__>
__>MAKELONG((short)pt.x,(short)pt.y)
__>


Устроит. Но приведение к "short" лишнее, в макросе MAKELONG все компоненты усекаются по маске 0xffff.
Думай, что хочешь, делай, что хочешь, живи, как хочешь -- всё тебе припомню!!
Re: Итого: WTL: Подсказка в любом месте экрана
От: Alexey Goncharov Россия  
Дата: 21.08.04 17:03
Оценка: +1
Здравствуйте, WinterMute, Вы писали:

WM>Всем спасибо за сделанные замечания. Вот поправленная версия:


Еще маленькое замечание — раз память выделяется по new [], то и удалять надо по delete [], а не по delete
Re[2]: Итого: WTL: Подсказка в любом месте экрана
От: WinterMute Россия http://yarrr.ru
Дата: 21.08.04 22:12
Оценка: +1
AG>Еще маленькое замечание — раз память выделяется по new [], то и удалять надо по delete [], а не по delete

Да, я тоже недавно заметил .
Думай, что хочешь, делай, что хочешь, живи, как хочешь -- всё тебе припомню!!
Итого2: WTL: Подсказка в любом месте экрана
От: WinterMute Россия http://yarrr.ru
Дата: 25.08.04 15:17
Оценка: 6 (2)
#Имя: FAQ.wtl.tooltip
Еще несколько маленьких доработок:

namespace UI2
{
    class Tooltip
        : public CWindowImpl<Tooltip, ATL::CWindow>
    {
    public:
        typedef CWindowImpl<Tooltip, ATL::CWindow> baseClass;
        typedef Tooltip thisClass;

        HWND     m_hWndOwner;

    private:
        TOOLINFO m_ToolInfo;
        bool     m_bVisible;
        bool     m_bShowAtCursor;

        enum { TIMER_MSG_DELAY_SHOW = 100, TIMER_MSG_DELAY_HIDE = 101, };

        static LPCTSTR GetWndClassName(){ return _T("Zaebis_Tooltip"); }

    public:
        DECLARE_WND_SUPERCLASS(GetWndClassName(), baseClass::GetWndClassName())

        BEGIN_MSG_MAP(thisClass)
            MESSAGE_HANDLER(WM_TIMER, OnTimer)
            MESSAGE_HANDLER(WM_SETCURSOR, OnMouseMessage) // Если хочется что бы над подказкой был такой-же курсор как и над хозяином
            MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage)
        END_MSG_MAP()


        Tooltip()
        : baseClass()
        , m_bVisible(false)
        , m_hWndOwner(0)
        {
            memset(&m_ToolInfo, 0, sizeof(m_ToolInfo));
        }

        ~Tooltip()
        { 
            DestroyWindow();
        }

        bool Create( HWND hWndParent, HWND hWndOwner = NULL )
        {
            DestroyWindow();

            HWND hWnd = ::CreateWindowEx(WS_EX_TOPMOST,
                TOOLTIPS_CLASS,
                NULL,
                TTS_NOPREFIX | TTS_ALWAYSTIP,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                hWndParent,
                NULL,
                NULL,
                NULL);

            ATLASSERT(hWnd);

            // initialize toolinfo struct
            m_ToolInfo.cbSize = sizeof(m_ToolInfo);
            m_ToolInfo.uFlags = TTF_TRACK | TTF_TRANSPARENT | TTF_SUBCLASS;
            m_ToolInfo.hwnd = hWndParent;

             m_hWndOwner = hWndOwner;

            ::SendMessage( hWnd, TTM_SETMAXTIPWIDTH, 0, SHRT_MAX );
            ::SendMessage( hWnd, TTM_ADDTOOL, 0, (LPARAM)(LPTOOLINFO)&m_ToolInfo );

            SubclassWindow( hWnd );

            return true;
        }


        void DestroyWindow()
        {
            if( m_hWnd )baseClass::DestroyWindow();

            delete [] m_ToolInfo.lpszText;
            memset(&m_ToolInfo, 0, sizeof(m_ToolInfo));
        }


        void SetBackColor( COLORREF c ){ ::SendMessage( m_hWnd, TTM_SETTIPBKCOLOR, c, 0 ); }
        void SetTextColor( COLORREF c ){ ::SendMessage( m_hWnd, TTM_SETTIPTEXTCOLOR, c, 0 ); }
        void SetMargins( const RECT* rectMargins ){ ::SendMessage(m_hWnd, TTM_SETMARGIN, 0, (LPARAM)rectMargins); }
        void SetMaxWidth( int maxWidth ){ ::SendMessage( m_hWnd, TTM_SETMAXTIPWIDTH, 0, (LPARAM)maxWidth ); }

        bool IsVisible(){ return m_bVisible; };

        const TCHAR* GetText()
        {
            ::SendMessage( m_hWnd, TTM_GETTEXT, 0, (LPARAM)&m_ToolInfo );
            return m_ToolInfo.lpszText;
        }

        void SetText( const TCHAR* text )
        {
            delete [] m_ToolInfo.lpszText;

            if( text )
            {
                m_ToolInfo.lpszText = new TCHAR[ _tcslen(text)+1 ];
                _tcscpy( m_ToolInfo.lpszText, text );
            }
            else m_ToolInfo.lpszText = NULL;

            ::SendMessage( m_hWnd, TTM_UPDATETIPTEXT, 0, (LPARAM)&m_ToolInfo );
        }

        void Move( int x, int y )
        {
            ::SendMessage( m_hWnd, TTM_TRACKPOSITION, 0, (LPARAM)(DWORD)MAKELONG( x, y ) );
        }

        void Show( int x, int y )
        {
            Move( x, y );
            Show();
        }

        void Show( const RECT* r )
        {
            m_bVisible = true;
            m_ToolInfo.rect = *r;

            ::SendMessage( m_hWnd, TTM_TRACKPOSITION, 0, (LPARAM)(DWORD) MAKELONG( r->left, r->top ) );
            ::SendMessage( m_hWnd, TTM_SETMAXTIPWIDTH, 0, (LPARAM)(r->right - r->left) );
            ::SendMessage( m_hWnd, TTM_TRACKACTIVATE, TRUE, (LPARAM)&m_ToolInfo );
        }

        void Show( BOOL bShow = TRUE )
        {
            m_bVisible = (bShow == TRUE);
            ::SendMessage( m_hWnd, TTM_TRACKACTIVATE, bShow, (LPARAM)&m_ToolInfo );
        }

        void ShowAtCursor()
        {
            POINT pt; ::GetCursorPos( &pt );
            Show( pt.x, pt.y+20 );
        }

        void ShowAfter( UINT delay, bool bAtCursor = false )
        {
            if( IsWindow() )
            {
                m_bShowAtCursor = bAtCursor;

                KillTimer( TIMER_MSG_DELAY_SHOW );
                SetTimer( TIMER_MSG_DELAY_SHOW, delay );
            }
        }

        void ShowAtCursorAfter( UINT delay )
        {
            ShowAfter( delay, true );
        }

        void HideAfter( UINT delay )
        {
            if( IsWindow() )
            {
                KillTimer( TIMER_MSG_DELAY_HIDE );
                SetTimer( TIMER_MSG_DELAY_HIDE, delay );
            }
        }

        void CancelShowAfter()
        {
            KillTimer( TIMER_MSG_DELAY_SHOW );
        }

        void CancelHideAfter()
        {
            KillTimer( TIMER_MSG_DELAY_HIDE );
        }

        operator HWND() { return m_hWnd; }


        // Message handlers

        LRESULT OnTimer( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
        {
            if( TIMER_MSG_DELAY_SHOW == wParam )
            {
                m_bShowAtCursor?ShowAtCursor():Show();
                KillTimer( wParam );
            }
            else if( TIMER_MSG_DELAY_HIDE == wParam )
            {
                Show(FALSE);
                KillTimer( wParam );
            }

            bHandled = FALSE;
            return 0;
        }

        LRESULT OnMouseMessage( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
        {
            LRESULT ret = 0;

            // forward message to owner window 
            if( m_hWndOwner )
            {
                POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
                ClientToScreen( &pt ); ::ScreenToClient( m_hWndOwner, &pt );
                ret = ::SendMessage( m_hWndOwner, uMsg, wParam, MAKELONG( pt.x, pt.y ) );
            }

            //bHandled = TRUE;
            bHandled = FALSE;
            return ret;
        }
    };
}
... << RSDN@Home 1.1.4 @@subversion >>
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.