WxTaskBarIcon

From WxWiki

Jump to: navigation, search

[edit] wxTaskBarIcon with Balloon Tooltips

Windows Only - Only Microsoft Windows 2000, XP and later operating systems support balloon tooltips.

This class extends wxTaskBarIcon to offer balloon tooltips. Use the following patch:

QDongTaskIcon
Index: build/msw/config.gcc
===================================================================
RCS file: /pack/cvsroots/wxwindows/wxWindows/build/msw/config.gcc,v
retrieving revision 1.18
diff -u -r1.18 config.gcc
--- build/msw/config.gcc        2005/07/28 12:42:09     1.18
+++ build/msw/config.gcc        2005/08/01 06:01:02
 
@@ -17,10 +17,10 @@
 CXX = g++
 
 # Standard flags for CC
-CFLAGS =
+CFLAGS = -D_WIN32_IE=0x0600
 
 # Standard flags for C++
-CXXFLAGS =
+CXXFLAGS = -D_WIN32_IE=0x0600
 
 # Standard preprocessor flags (common for CC and CXX)
 CPPFLAGS =
 
 
Index: include/wx/msw/taskbar.h
===================================================================
RCS file: /pack/cvsroots/wxwindows/wxWindows/include/wx/msw/taskbar.h,v
retrieving revision 1.24
diff -u -r1.24 taskbar.h
--- include/wx/msw/taskbar.h    2004/09/07 06:00:52 1.24
+++ include/wx/msw/taskbar.h    2005/08/01 08:22:00
@@ -17,6 +17,7 @@
 #pragma interface "taskbar.h"
 #endif
 
+#include <shellapi.h>
 #include "wx/icon.h"
 
 // private helper class:
@@ -37,6 +38,7 @@
     bool SetIcon(const wxIcon& icon, const wxString& tooltip = wxEmptyString);
     bool RemoveIcon(void);
     bool PopupMenu(wxMenu *menu); //, int x, int y);
+    bool ShowBalloon(wxString title, wxString message, unsigned int timeout = 10000, int icon = NIIF_INFO);
 
 #if WXWIN_COMPATIBILITY_2_4
     wxDEPRECATED( bool IsOK() const );
 
 
Index: src/msw/taskbar.cpp
===================================================================
RCS file: /pack/cvsroots/wxwindows/wxWindows/src/msw/taskbar.cpp,v
retrieving revision 1.46
diff -u -r1.46 taskbar.cpp
--- src/msw/taskbar.cpp 2005/05/31 09:20:33      1.46
+++ src/msw/taskbar.cpp 2005/08/01 12:43:45
@@ -328,6 +328,25 @@
     }
 
     return 0;
+}
+
+bool wxTaskBarIcon::ShowBalloon(wxString title, wxString message, unsigned int timeout, int icon)
+{
+    if (!IsOk())
+        return false;
+
+    NotifyIconData notifyData((HWND)m_win->GetHWND());
+    notifyData.uFlags = NIF_INFO;
+
+    wxStrncpy(notifyData.szInfo, message.c_str(), WXSIZEOF(notifyData.szInfo));
+    wxStrncpy(notifyData.szInfoTitle, title.c_str(), WXSIZEOF(notifyData.szInfoTitle));
+    notifyData.dwInfoFlags = icon;
+    notifyData.uTimeout = timeout;
+       
+    if (m_iconAdded)
+        return Shell_NotifyIcon(NIM_MODIFY, &notifyData);
+    else
+        return false;
 }
 
 #endif // __WIN95__ 

Possible values for icon are:

  • NIIF_ERROR - An error icon.
  • NIIF_INFO - An information icon.
  • NIIF_NONE - No icon.
  • NIIF_WARNING - A warning icon.

[edit] Generic Way

A generic way to do balloons is to create a frame without a border and paint its background. It is impossible to know where the icon is located so the only solution is to display this fake-balloon in a corner.

baloon class header
class TaskBarBaloon : public wxFrame
{
    public:
        TaskBarBaloon(wxString sTitle, wxString sMessage);
        virtual ~TaskBarBaloon() { delete timer; }
 
        /** painting bg */
        void OnPaint(wxPaintEvent& event);
        /** timer to close window */
        void OnTimerTick(wxTimerEvent & event);
        /** click on the baloon */
        void OnClick(wxMouseEvent & event);
 
        /** display the baloon and run the timer */
        void showBaloon(unsigned int iTimeout);
    private:
        wxTimer * timer;
 
        DECLARE_EVENT_TABLE();
 
};
baloon class code
BEGIN_EVENT_TABLE(TaskBarBaloon, wxFrame)
    EVT_PAINT(TaskBarBaloon::OnPaint)
    EVT_LEFT_DOWN(TaskBarBaloon::OnClick)
    EVT_TIMER(TIMER_BALOON,TaskBarBaloon::OnTimerTick)
END_EVENT_TABLE()
 
TaskBarBaloon::TaskBarBaloon(wxString sTitle, wxString sMessage)
    : wxFrame(NULL,-1,wxT("no title"),wxDefaultPosition,wxDefaultSize,wxNO_BORDER | wxSTAY_ON_TOP | wxFRAME_SHAPED | wxFRAME_NO_TASKBAR)
{
    wxColour bgColour(255,255,231); // yellow BG
    this->SetBackgroundColour(bgColour);
    wxBoxSizer * mainSizer = new wxBoxSizer(wxVERTICAL);
 
    wxStaticText * title = new wxStaticText(this, -1, sTitle);
    wxFont titleFont = this->GetFont();
    titleFont.SetWeight(wxFONTWEIGHT_BOLD);
    title->SetFont(titleFont);
    mainSizer->Add(title,0,wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 5);
    title->Connect(wxEVT_LEFT_DOWN,
                   wxMouseEventHandler(TaskBarBaloon::OnClick), NULL, this );
    title->Connect(wxEVT_KEY_DOWN,
                   wxKeyEventHandler(TaskBarBaloon::OnEscape), NULL, this );
 
    wxStaticText * text = new wxStaticText(this, -1, sMessage);
    mainSizer->Add(text,1,wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 5);
    text->Connect(wxEVT_LEFT_DOWN,
                  wxMouseEventHandler(TaskBarBaloon::OnClick), NULL, this );
    text->Connect(wxEVT_KEY_DOWN,
                   wxKeyEventHandler(TaskBarBaloon::OnEscape), NULL, this );
 
    this->SetSizer(mainSizer);
    mainSizer->SetSizeHints( this );
 
    this->timer = new wxTimer(this,TIMER_BALOON);
 
    // here, we try to align the frame to the right bottom corner
    this->Center();
    int iX = 0, iY = 0;
    this->GetPosition( &iX, &iY );
    iX = (iX * 2) - 2;
    iY = (iY * 2) - 2;
    this->Move( iX, iY );
}
 
void TaskBarBaloon::OnPaint(wxPaintEvent& event)
{
    wxPaintDC dc(this);
 
    int iWidth = 0, iHeight = 0;
    this->GetClientSize( &iWidth, &iHeight );
 
    wxPen pen(this->GetForegroundColour());
    dc.SetPen(pen);
 
    wxBrush brush(this->GetBackgroundColour());
    dc.SetBrush(brush);
 
    dc.Clear();
    dc.DrawRectangle(0,0,iWidth,iHeight);
}
 
/** closing frame at end of timeout */
void TaskBarBaloon::OnTimerTick(wxTimerEvent & event)
{
    this->Destroy();
}
 
/** showing frame and running timer */
void TaskBarBaloon::showBaloon(unsigned int iTimeout)
{
    this->Show(false);
    this->Show(true);
    this->timer->Start(iTimeout,wxTIMER_ONE_SHOT);
}

[edit] Hiding a Frame from the Taskbar

It's pretty neat to be able to hide your program from the taskbar when it's available from the tray anyway.

Quoting Austin Morgan: To remove the frame from the task bar all you have to do is catch EVT_ICONIZE(SBViewFrame::OnIconize) in your frame, then for the function do:

void SBViewFrame::OnIconize(wxIconizeEvent& event)
{
    this->Show(!event.Iconized());
}

Vadim proposes a similar approach: You have to hide the frame instead of iconizing it. To do this you must handle WM_SIZE in your wxFrame-derived class directly and call Hide() if wParam == SIZE_MINIMIZED. There is no way to do it portable AFAIK, although we certainly could add some wxTLW::DoIconize() which would be called when the window must be iconized.

Lars adds: It's very important to generate a wxIconizeEvent to restore the main frame (with iconize = FALSE, of course), otherwise the main frame doesn't respond anymore to minimize button clicks, I've discovered.

You could also add a line to remove the taskbar icon if the main frame is restored and to add the taskbar icon if the main frame is iconized.

Personal tools