Qt 系统托盘(加hover效果)
生活随笔
收集整理的這篇文章主要介紹了
Qt 系统托盘(加hover效果)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
原文鏈接:http://www.cnblogs.com/qnkk123/p/6840944.html
最近項目需要添加系統托盤,本來Qt的QSystemTrayIcon可以實現的,但是要求要添加hover效果,并顯示未讀消息(就和qq的托盤差不多,移動上去顯示未讀列表),加了這個要求QSystemTrayIcon就沒法實現了,最后使用的是NOTIFYICONDATA實現的,記錄下。
1.創建一個系統托盤:
NOTIFYICONDATA m_nid; CMsgTrayPos m_traypos; QLabel *m_pSysIcon;
qApp->installNativeEventFilter(this);
//創建托盤圖標
m_pSysIcon = new QLabel;
m_nid.cbSize = sizeof m_nid;
m_nid.hIcon = qt_pixmapToWinHICON(QIcon(":/style/blue/signin/logo.png").pixmap(16, 16));
m_nid.hWnd = HWND(m_pSysIcon->winId());
m_nid.uCallbackMessage = WM_TRAYNOTIFY;
m_nid.uID = 1;
m_nid.uFlags = NIF_ICON | NIF_MESSAGE;
Shell_NotifyIcon(NIM_ADD, &m_nid);
m_traypos.SetNotifyIconInfo(HWND(this->winId()), 1, WM_TRAYNOTIFY);
2,這就創建好系統托盤了,接著就是鼠標事件函數:
bool CMainWindow::nativeEventFilter(const QByteArray & eventType, void * message, long * result)
{
if (eventType == "windows_generic_MSG" || eventType == "windows_dispatcher_MSG")
{
MSG * pMsg = reinterpret_cast<MSG *>(message);
if (pMsg->message == WM_TRAYNOTIFY)
{
switch (pMsg->lParam)
{
case WM_MOUSEMOVE:
m_traypos.OnMouseMove();
break;
case WM_MOUSEHOVER:
{
if (m_pSysNaviWidget->newMessageCount() > 0) // 有消息則移動上去顯示未讀列表
{
QPoint point = cursor().pos();
m_pSysNaviWidget->show();
m_pSysNaviWidget->move(point.x() - 200, point.y() - 150);
}
}
break;
case WM_MOUSELEAVE:
{
// 如果hover之后移動到未讀列表,則不消失,移動到其他地方則隱藏未讀列表
QPoint point = cursor().pos();
QPoint naviPoint = m_pSysNaviWidget->pos();
if (point.x() > naviPoint.x() && point.x() < naviPoint.x() + 200 &&
point.y() > naviPoint.y() && point.y() < naviPoint.y() + 150)
{
}
else
{
m_pSysNaviWidget->hide();
}
}
break;
case WM_LBUTTONDBLCLK:
{
//ShowWindow(HWND(this->winId()), SW_SHOW); 界面會假死
showWindow();
break;
}
case WM_LBUTTONDOWN:
//m_Menu->show();
break;
case WM_RBUTTONDOWN:
{
creatMenu();
m_pPop_menu->exec(QCursor::pos());
}
break;
}
}
}
return false;
}
3、現在hover就可以顯示未讀列表了,下一步是有消息時閃爍托盤圖標,設置的是定時器,事件到就調用下面這個函數
void CMainWindow::onFlickerSysIcon(bool bFlicker)
{
if (bFlicker)
{
m_nid.hIcon = qt_pixmapToWinHICON(QIcon(":/style/blue/signin/logo.png").pixmap(16, 16));
}
else
{
m_nid.hIcon = NULL;
}
Shell_NotifyIcon(NIM_MODIFY, &m_nid); // 修改圖標
}
4、閃爍搞定就是右鍵菜單
void CMainWindow::initSysMenu()
{
//創建菜單、菜單項
m_pPop_menu = new QMenu();
m_pControl_action = new QAction("打開主面板", m_pPop_menu);
m_pSetting_action = new QAction("設置", m_pPop_menu);
m_pOpinion_action = new QAction("意見反饋", m_pPop_menu);
m_pExit_action = new QAction("退出", m_pPop_menu);
//連接信號與槽
connect(m_pControl_action, SIGNAL(triggered()), this, SLOT(onControlAction()));
connect(m_pSetting_action, SIGNAL(triggered()), this, SLOT(onSettingAction()));
connect(m_pOpinion_action, SIGNAL(triggered()), this, SLOT(onOpinionAction()));
connect(m_pExit_action, SIGNAL(triggered()), this, SLOT(onBtnQuitSelected()));
}
void CMainWindow::creatMenu()
{
m_pPop_menu->addAction(m_pControl_action);
m_pPop_menu->addSeparator();
m_pPop_menu->addAction(m_pSetting_action);
m_pPop_menu->addAction(m_pOpinion_action);
m_pPop_menu->addAction(m_pExit_action);
}
右鍵是上面的鼠標事件函數中的WM_RBUTTONDOWN;
5.從托盤顯示界面,本來是使用ShowWindow(HWND(this->winId()), SW_SHOW); 但是顯示的界面會假死,不能操作,所以我選擇了個折中的方式:
void CMainWindow::showWindow()
{
if (!isVisible())
{
hide();
show();
}
}
6.退出程序是刪除托盤:
Shell_NotifyIcon(NIM_DELETE, &m_nid);
7.需要到的其他文件:
#ifndef CTRAYPOS_H
#define CTRAYPOS_H
#include <windows.h>
class CTrayPos
{
private:
POINT m_ptMouse;
HANDLE m_hThread;
HANDLE m_hExitEvent;
BOOL m_bTrackMouse;
CRITICAL_SECTION m_cs;
public:
CTrayPos();
virtual ~CTrayPos();
static UINT CALLBACK TrackMousePt(PVOID pvClass);
VOID OnMouseMove();
BOOL IsMouseHover();
protected:
virtual VOID OnMouseHover() = 0;
virtual VOID OnMouseLeave() = 0;
};
class CMsgTrayPos : public CTrayPos
{
private:
HWND m_hNotifyWnd;
UINT m_uID;
UINT m_uCallbackMsg;
public:
CMsgTrayPos(HWND hwnd=NULL, UINT uID=0, UINT uCallbackMsg=0);
~CMsgTrayPos();
VOID SetNotifyIconInfo(HWND hwnd, UINT uID, UINT uCallbackMsg);
protected:
VOID OnMouseHover();
VOID OnMouseLeave();
};
#endif
#include <process.h>
#include "CTraypos.h"
CTrayPos::CTrayPos()
{
UINT uThreadId;
m_bTrackMouse = FALSE;
m_hExitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
m_hThread = (HANDLE) _beginthreadex(NULL, 0, CTrayPos::TrackMousePt, this, 0, &uThreadId);
InitializeCriticalSection(&m_cs);
}
CTrayPos::~CTrayPos()
{
if(m_hThread != NULL)
{
SetEvent(m_hExitEvent);
if(WaitForSingleObject(m_hThread, 5000) == WAIT_TIMEOUT)
{
TerminateThread(m_hThread, 0);
}
CloseHandle(m_hThread);
m_hThread = NULL;
}
if(m_hExitEvent != NULL)
{
CloseHandle(m_hExitEvent);
m_hExitEvent = NULL;
}
DeleteCriticalSection(&m_cs);
}
UINT CALLBACK CTrayPos::TrackMousePt(PVOID pvClass)
{
POINT ptMouse;
CTrayPos *pTrayPos = (CTrayPos *) pvClass;
while(WaitForSingleObject(pTrayPos->m_hExitEvent, 100) == WAIT_TIMEOUT)
{
if(pTrayPos->m_bTrackMouse == TRUE)
{
GetCursorPos(&ptMouse);
if(ptMouse.x != pTrayPos->m_ptMouse.x || ptMouse.y != pTrayPos->m_ptMouse.y)
{
pTrayPos->m_bTrackMouse = FALSE;
pTrayPos->OnMouseLeave();
}
}
}
return 0;
}
VOID CTrayPos::OnMouseMove()
{
EnterCriticalSection(&m_cs);
GetCursorPos(&m_ptMouse);
if(m_bTrackMouse == FALSE)
{
OnMouseHover();
m_bTrackMouse = TRUE;
}
LeaveCriticalSection(&m_cs);
}
BOOL CTrayPos::IsMouseHover()
{
return m_bTrackMouse;
}
//////////////////////////////////////////////////////////////////////////
CMsgTrayPos::CMsgTrayPos(HWND hwnd, UINT uID, UINT uCallbackMsg)
: CTrayPos()
{
SetNotifyIconInfo(hwnd, uID, uCallbackMsg);
}
CMsgTrayPos::~CMsgTrayPos()
{
}
VOID CMsgTrayPos::SetNotifyIconInfo(HWND hwnd, UINT uID, UINT uCallbackMsg)
{
m_hNotifyWnd = hwnd;
m_uID = uID;
m_uCallbackMsg = uCallbackMsg;
}
VOID CMsgTrayPos::OnMouseHover()
{
if(m_hNotifyWnd != NULL && IsWindow(m_hNotifyWnd))
PostMessage(m_hNotifyWnd, m_uCallbackMsg, m_uID, WM_MOUSEHOVER);
}
VOID CMsgTrayPos::OnMouseLeave()
{
if(m_hNotifyWnd != NULL && IsWindow(m_hNotifyWnd))
PostMessage(m_hNotifyWnd, m_uCallbackMsg, m_uID, WM_MOUSELEAVE);
}
總結:本來打算用QSystemTrayIcon的Tooltip事件來完成hover的,但是事件調用沒效果,最后的效果圖:
總結
以上是生活随笔為你收集整理的Qt 系统托盘(加hover效果)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 简单为mysql 实现透明加密方法
- 下一篇: 励志电视剧(你们看过最好看的励志电视剧是