wxTaskBarIcon

From WxWiki
Jump to navigation Jump to search
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