wxTaskBarIcon

From WxWiki
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
Official Classes SmallBlocks.png Archive Containers Controls Data Structures Database Date & Time Debug Device Contexts Dialogs Document & Views Drag & Drop Events Filesystem Frames Graphics Grid Cell Help HTML Logging Miscellaneous Networking Printing Sizers Streams Threading Windows

This class represents a taskbar icon.

A taskbar icon is an icon that appears in the 'system tray' and responds to mouse clicks, optionally with a tooltip above it to help provide information.

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

 CXX = g++
 
 # Standard flags for CC
 CFLAGS = -D_WIN32_IE=0x0600
 
 # Standard flags for C++
 CXXFLAGS = -D_WIN32_IE=0x0600
 
 # Standard preprocessor flags (common for CC and CXX)
 CPPFLAGS =

Index: include/wx/msw/taskbar.h

 #pragma interface "taskbar.h"
 #endif
 
 #include <shellapi.h>
 #include "wx/icon.h"
 
 // private helper class:
     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

     }
 
     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.

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);
}

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.

See Also