Qt实现隐藏任务栏图标及显示系统托盘图标
整理使用Qt编写窗体应用时用到的一些功能。
1.隐藏任务栏图标
使用QWidget
类中的setWindowFlags
方法:
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
{
...
this->setWindowFlags(Qt::Tool | Qt::X11BypassWindowManagerHint); //隐藏任务栏图标
...
}
2.显示系统托盘图标
通过QSystemTrayIcon
类实现此功能:设置一全局指针QSystemTrayIcon *
在构造函数中创建系统托盘图标。
//在头文件中
...
class QSystemTrayIcon;
class QMenu;
...
class Widget : public QWidget
{
...
private:
QSystemTrayIcon *m_sys_tray; //系统托盘图标
QMenu *m_sys_tray_menu; //系统托盘弹出菜单
...
}
//在源文件中
...
#include <QSystemTrayIcon>
#include <QMenu>
...
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
{
...
m_sys_tray = new QSystemTrayIcon; //新建一个QSystemTrayIcon指针
QIcon icon(":/img/images/sysTray.png"); //系统托盘图标
m_sys_tray->setIcon(icon); //设置系统托盘图标
m_sys_tray->setToolTip("This is a demo."); //设置系统托盘图标提示
m_sys_tray = new QMenu; //新建一个QMenu指针
m_sys_tray_menu->addAction(ui->actionQuit); //为菜单添加菜单项
m_sys_tray->setContextMenu(m_sys_tray_menu); //为系统托盘设置弹出菜单
m_sys_tray->show(); //显示系统托盘
m_sys_tray->showMenssage("Tips", "I'm here!"); //设置系统托盘信息提示
...
}
3.窗体始终置顶
通过QWidget
类中的setWindowFlags
或setWindowFlag
方法,设置Qt::WindowStaysOnTopHint
枚举项:
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
{
...
this->setWindowFlag(Qt::WindowStaysOnTopHint); //设置窗体始终置顶
...
}
4.窗体背景透明及无边框
通过QWidget
类中的setWindowFlags
或setWindowFlag
方法,设置Qt::FramlessWindowHint
枚举项,使窗体无边框,同时需要QWidget
类中的setAttribute
方法设置Qt::WA_TranslucentBacground
枚举项使窗体背景透明。
需要注意的是,设置Qt::FramlessWindowHint
会使窗体无法移动和改变大小,因为Qt
是通过检测鼠标移动窗体的边框来实现窗体移动和改变大小,窗体无边框自然无法移动窗体和改变大小,一般需要配合第5个功能。而且由于关闭、最大化、最小化灯功能也在边框上,因此需要设置系统托盘图标之类以满足能使窗体关闭,程序结束的功能。若使窗口关闭,需要使用setAttribute
方法设置Qt::WA_QuitOnClose
枚举项,以使窗体正常关闭以及程序正常退出。
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
{
...
this->setWindowFlag(Qt::FramlessWindowHint); //设置窗体无边框
this->setAttribute(Qt::WA_TranslucentBackground); //设置窗体背景透明
this->setAttribute(Qt::WA_QuitOnClose);
...
}
5.窗体无边框时实现移动功能
为实现窗体无边框移动,需要重写QWidget
类中的mousePressEvent(QMouseEvent*), mouseMoveEvent(QMouseEvent*), mouseReleaseEvent(QMouseEvent*)
三个方法。
首先设置一个全局变量m_is_left_button_pressed
记录鼠标左键的状态,只有鼠标左键在窗体的有效区域内(即能够触发mousePressEvent
方法的区域)单击才会为true
,否则为false
;
然后鼠标左键在窗体有效区域内单击时记录其相对窗体的坐标,记录在m_mouse_pos
中;
根据鼠标的移动更新窗体的位置,使用QWidget
中的move
方法。
void Widget::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton){ //若鼠标左键暗笑
m_is_left_button_pressed = true; //修改状态
m_mouse_pos = event->pos(); //记录相对坐标
}
}
void Widget::mouseMoveEvent(QmouseEvent *event)
{
if(m_is_left_button_pressed){ //若鼠标左键依然按下
move(event->globalPos() - m_mouse_pos); //移动窗体
}
}
void Widget::mouseReleaseEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton){ //若鼠标左键释放
m_is_left_button_pressed = false; //修改状态
}
}
6.窗体贴边隐藏
窗体贴边隐藏需要重写QWidget
类中的mouseMoveEvent(QMouseEvent*), enterEvent(QEvent*), leaveEvent(QEvent*)
方法。
首先,通过鼠标移动的位置判断窗体的位置,这里创建一个函数isWindowInScreen
来实现,这里窗体的位置通过设置一个枚举类来实现,并设置一全局变量记录窗体位置:
class Widget : public QWidget
{
...
private:
//窗体位置枚举类型
enum WindowPosition {
WP_None = 0, //窗体在屏幕中央
WP_Left, //窗体贴左侧
WP_Right, //窗体贴右侧
WP_Up, //窗体贴上侧
WP_Down //窗体贴下侧
};
WindowPosition m_window_position; //记录窗体位置
int m_screen_width; //屏幕水平分辨率
int m_screen_height; //屏幕垂直分辨率
...
}
另外需要获取用户的屏幕分辨率,记录在全局变量m_screen_width
和m_screen_height
中:
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
{
...
QRect rect = QGuiApplication::primaryScreen()->geometry();
m_screen_width = rect.width();
m_screen_height = rect.height();
...
}
isWindowInScreen
实现如下:
//若窗体不在屏幕中央,返回false;否则返回true
bool isWindowInScreen(QPoint pos)
{
if(pos.x() < 5){
m_window_position = Widget::WP_Left;
return false;
} else if(pos.x() > m_screen_width - 5){
m_window_position = Widget::WP_Right;
return false;
} else if(pos.y() < 5){
m_window_position = Widget::WP_Up;
return false;
} else if(pos.y() > m_screen_height - 5){
m_window_position = Widget::WP_Down;
return false;
} else {
m_window_position = Widget::WP_None;
return true;
}
}
然后根据判断位置移动窗体:
void Widget::mouseMoveEvent(QMouseEvent *event)
{
if(m_is_left_button_pressed){
if(!isWindowInScreen(event->globalPos())){
int x = event->globalX();
int y = event->globalY();
if(m_window_position == Widget::WP_Left){
move(0, y - m_mouse_pos.y());
} else if(m_window_position == Widget::WP_Right){
move(m_screen_width - width(), y - m_mouse_pos.y());
} else if(m_window_position == Widget::WP_Up){
move(x - m_mouse_pos.x(), 0);
} else if(m_window_position == Widget::WP_Down){
move(x - m_mouse_pos.x(), m_screen_height - height());
}
} else {
move(event->globalPos() - m_mouse_pos);
}
}
}
并在enterEvent
和leaveEvent
中实现鼠标进入窗体和离开窗体应该实现的功能,即窗体贴边隐藏动画:
void Widget::enterEvent(QEvent *event)
{
Q_UNUSED(event);
if(m_window_position != Widget::WP_None){ //若窗体不在屏幕中央,动画显示窗体
QPropertyAnimation *animation = new QPropertyAnimation(this, "geometry");
int x = this->x();
int y = this->y();
int width = this->width();
int height = this->height();
animation->setStartValue(QRect(x, y, width, height));
if(m_window_position == Widget::WP_Left){
animation->setEndValue(QRect(0, y, width, height));
} else if(m_window_position == Widget::WP_Right){
animation->setEndValue(QRect(m_screen_width - width, y, width, height));
} else if(m_window_position == Widget::WP_Up){
animation->setEndValue(QRect(x, 0, width, height));
} else if(m_window_position == Widget::WP_Down){
animation->setEndValue(QRect(x, m_screen_height - height, width, height));
}
animation->setDuration(250);
animation->start(QAbstractAnimation::DeleteWhenStopped);
}
}
void Widget::leaveEvent(QEvent *event)
{
Q_UNUSED(event);
if(m_window_position != Widget::WP_None){ //若窗体不在屏幕中央,动画隐藏窗体
QPropertyAnimation *animation = new QPropertyAnimation(this, "geometry");
int x = this->x();
int y = this->y();
int width = this->width();
int height = this->height();
animation->setStartValue(QRect(x, y, width, height));
if(m_window_position == Widget::WP_Left){
animation->setEndValue(QRect(0 - width + 5, y, width, height));
} else if(m_window_position == Widget::WP_Right){
animation->setEndValue(QRect(m_screen_width - 5, y, width, height));
} else if(m_window_position == Widget::WP_Up){
animation->setEndValue(QRect(x, 0 - height + 5, width, height));
} else if(m_window_position == Widget::WP_Down){
animation->setEndValue(QRect(x, m_screen_height - 5, width, height));
}
animation->setDuration(250);
animation->start(QAbstractAnimation::DeleteWhenStopped);
}
}