Suspended window under Qt
The recent project needs a suspension window similar to 360 suspension ball. When the mouse is placed and stayed for a period of time, the suspension window will be expanded and the removed area will be automatically retracted. I looked for it on the Internet, but I didn't find it. Thinking about getting familiar with Qt and improving my programming technology, I made a wheel myself. If there is a problem, I hope you can correct it.
QPropertyAnimation
I use the animation class provided by Qt. The official document explains:
The red box above means that you can specify the start and end values of the attribute.
The method of use is as follows:
// Set the property to geometry, representing the location size m_Animation = new QPropertyAnimation(this, "geometry"); // Set animation duration in MS m_Animation->setDuration(600); // Sets the end value of the animation m_Animation->setEndValue(QRect(m_posX,m_posY, this->width(), this->height())); // Start of animation m_Animation->setStartValue(QRect(m_posX - ui->m_menu->width(), m_posY, this->width(), this->height())); // Animated motion tracks m_Animation->setEasingCurve(QEasingCurve::InQuad); m_Animation->start();
For setEasingCurve() function, which is the action track for setting animation, please refer to Qt official document:
Many animation curves are introduced here.
QTimer
Another core is the timer. The simple logic is:
-
When the mouse moves into the title bar, the pop-up timer will be started, and the pop-up function will be executed when the time is up. When the time is not up, but the title is removed, the pop-up timer will be closed;
-
When the mouse moves into the menu bar, it will close the stow timer. When it moves out of the menu bar, it will start the stow timer, and the stow function will be executed at the time. When it moves in before the time, it will close the stow timer;
The initialization code of the timer is as follows:
m_expandTimer = new QTimer(); m_flodTimer = new QTimer(); // Set timer time (unit: ms) m_expandTimer->setInterval(700); m_flodTimer->setInterval(700); // Connecting signal and slot connect(m_expandTimer, &QTimer::timeout, this, &Floating::expandMenu); connect(m_flodTimer, &QTimer::timeout, this, &Floating::flodMenu);
When the timer expires, the processing function is as follows:
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(); }
Event filtering
You need to design the mouse in and out event of the child control of the floating window. The code is as follows:
bool Floating::eventFilter(QObject *target, QEvent *event) { //drag // TODO 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); }
Icon transformation
void Floating::setTitleIcon() { m_isExpand ? ui->m_title->setProperty("status", "show") : ui->m_title->setProperty("status", "hide"); // After setting, be sure to polish, otherwise the style may not be displayed ui->m_title->style()->polish(ui->m_title); }
Here, the corresponding styles are set according to the set dynamic attributes. For details, see This blog
Adaptive window size
Sometimes, the position of the suspended window may change again after the window size is adjusted, or after the resolution is changed. Therefore, you need to reload the resizeEvent of the window to be placed to dynamically set the size of the suspended window.
The code is as follows:
// mainwindow.h class MainWindow { // ... protected: virtual void resizeEvent(QResizeEvent* event) override; } // mainwindow.cpp void resizeEvent(QResizeEvent* event) { m_floating->adjustParent(this.width()); } // floating.cpp void Floating::adjustParent(int parentWidth) { // Here my posY is set to a fixed 50, // m_posX = width of main window - (width of title bar + gap of layout) int horSpacing = static_cast<QGridLayout*>(this->layout())->horizontalSpacing(); m_posX = parentWidth - ui->m_title->width() - horSpacing; m_posY = 50; // move windows this->move(m_posX, m_posY); }
usage method
-
Copy the file to the project folder
-
Introducing pri file into pro file
include(floating/floating.pri)
-
Add header file
include "floating/floating"
-
Get singleton object:
// .h Floating* m_floating; // And you need to add this sentence to the destructor of the class you use // Otherwise, there will be a problem of multiple releases because of this m_floating is released before the destructor // However, the relationship tree of the child window created before is still there, and the child object will be destructed when the main window is destructed // It will go wrong. Therefore, you need to delete this relationship in the object tree. m_floating->setParent(nullptr); // .cpp m_floating = &Floating::getInstance(this);
- Set style sheet
/* Set the style of the stow */ Floating QWidget#m_title[status=hide] { /* border-image:url(:/img/images/ZT.png);*/ background-color: rgba(12,55,214,1); } /* Set the style of the expansion */ Floating QWidget#m_title[status=show] { /* border-image:url(:/img/images/YT.png);*/ background-color: rgba(12,55,214,1); } /* Style the menu bar */ Floating QWidget#m_menu { border: 2px solid #969696; background-color: rgba(0, 25, 67, 0.9);; border-top-left-radius: 10px; /* Angle radian: lower left corner*/ border-bottom-left-radius: 10px; /* Angle radian: lower right corner*/ }
- If you need to change the position of the floating window after the main window changes, please overload the resize event of the main window to manually change the size of the floating window
// mainwindow.h class MainWindow { // ... protected: virtual void resizeEvent(QResizeEvent* event) override; } // mainwindow.cpp void resizeEvent(QResizeEvent* event) { m_floating->adjustParent(this.width()); }
Sure enough, only by writing or teaching others can I really test whether my knowledge is in place. My colleagues who are blogging have a deeper understanding of these codes and QPropertyAnimation.
Code resources, please go here download