WxTaskBarIcon
From WxWiki
[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:
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, ¬ifyData); + 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.
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(); };
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.
