Qt下的悬浮窗最近项目需要一个类似于360悬浮球类似的悬浮窗,当鼠标放入停留一段时间,就会展开悬浮窗,移出区域就会自动收起。随便在网上找了一下,没找到,想着熟悉Qt提升自己编程技术的出发点,我就自己造了个轮子,如果有问题,希望大家指正。 QPropertyAnimation我用的是Qt自带的动画类,官方文档的解释是: 
上面画红框的意思是,你可以指定属性的开始和结束值。 使用方法如下:
m_Animation = new QPropertyAnimation(this, "geometry");
m_Animation->setDuration(600);
m_Animation->setEndValue(QRect(m_posX,m_posY,
this->width(), this->height()));
m_Animation->setStartValue(QRect(m_posX - ui->m_menu->width(), m_posY,
this->width(), this->height()));
m_Animation->setEasingCurve(QEasingCurve::InQuad);
m_Animation->start();
关于setEasingCurve()这个函数,这个是设置动画的行动轨迹,参看Qt官方文档: 
这里介绍了很多的动画曲线。 QTimer另外一个核心的是定时器,简易的逻辑是: 当鼠标移入标题栏时,会开启弹出定时器,到时间就会执行弹出函数,当没有到时间,但是移除了标题时,关闭弹出计时器; 当鼠标移入菜单栏时,会关闭收起定时器,当移出菜单栏时,会开启收起定时器,到时间就会执行收起函数,当没有到时间就移入的时,关闭收起定时器;
定时器的初始化代码如下: m_expandTimer = new QTimer();
m_flodTimer = new QTimer();
m_expandTimer->setInterval(700);
m_flodTimer->setInterval(700);
connect(m_expandTimer, &QTimer::timeout, this, &Floating::expandMenu);
connect(m_flodTimer, &QTimer::timeout, this, &Floating::flodMenu);
定时器时间到处理函数如下: void Floating::expandMenu()
{
if (m_Animation->state() == QPropertyAnimation::Running) {
return;
}
m_isExpand = true;
setTitleIcon();
m_Animation->setStartValue(QRect(m_posX, m_posY,
this->width(), this->height()));
m_Animation->setEndValue(QRect(m_posX - ui->m_menu->width(), m_posY,
this->width(), this->height()));
m_Animation->start();
m_expandTimer->stop();
}
void Floating::flodMenu()
{
if (m_Animation->state() == QPropertyAnimation::Running) {
return;
}
m_isExpand = false;
setTitleIcon();
m_Animation->setEndValue(QRect(m_posX,m_posY,
this->width(), this->height()));
m_Animation->setStartValue(QRect(m_posX - ui->m_menu->width(), m_posY,
this->width(), this->height()));
m_Animation->start();
m_flodTimer->stop();
}
事件过滤需要将悬浮窗的子控件的鼠标移入移出事件进行一个设计,代码如下: bool Floating::eventFilter(QObject *target, QEvent *event)
{
if (target == ui->m_title) {
if (event->type() == QEvent::Enter) {
if (!m_bDragFlag && !m_isExpand) {
m_expandTimer->start();
return QWidget::eventFilter(target, event);
}
}
if (event->type() == QEvent::Leave) {
m_expandTimer->stop();
}
}
if (target == ui->m_menu || target == this) {
if (event->type() == QEvent::Enter) {
m_flodTimer->stop();
return QWidget::eventFilter(target, event);
}
if (event->type() == QEvent::Leave) {
if (!m_bDragFlag && m_isExpand) {
m_flodTimer->start();
}
}
}
return QWidget::eventFilter(target, event);
}
图标变换void Floating::setTitleIcon()
{
m_isExpand ? ui->m_title->setProperty("status", "show")
: ui->m_title->setProperty("status", "hide");
ui->m_title->style()->polish(ui->m_title);
}
这里是根据设置的动态属性来设置对应的样式,详情请参见这篇博客 自适应窗口大小由于有时候会出现窗口大小调整后,悬浮窗的位置可能会重新变化,或者分辨率改变之后。所以需要重载需要放置的窗口的resizeEvent来动态的设置悬浮窗的大小。 代码如下:
class MainWindow
{
protected:
virtual void resizeEvent(QResizeEvent* event) override;
}
void resizeEvent(QResizeEvent* event)
{
m_floating->adjustParent(this.width());
}
void Floating::adjustParent(int parentWidth)
{
int horSpacing = static_cast<QGridLayout*>(this->layout())->horizontalSpacing();
m_posX = parentWidth - ui->m_title->width() - horSpacing;
m_posY = 50;
this->move(m_posX, m_posY);
}
使用方法把文件复制到项目文件夹下 在pro文件里引入pri文件 include(floating/floating.pri)
加入头文件 include "floating/floating"
获取单例对象:
Floating* m_floating;
<
|