使用Qt编程的一些体会

Qt是一个很灵活的框架,其优秀的跨平台特性、丰富的界面定制功能和简明的信号-槽大大的简化了编程工作,并让代码很简洁优雅,但是在实际项目中,还是会遇到一些问题

1. 无边框窗口的移动问题

如果只是为了“能用”,那么网上现成的这类代码很多,简单的参考一下就可以写出这样的代码:

MyWidget::MyWidget(QWidget *parent) :
    QWidget(parent)
{
    //...
    this->setFixedSize(this->size());
    this->setWindowFlags(Qt::FramelessWindowHint);
    this->m_isHold = false;
    //...
}

void MyWidget::mousePressEvent(QMouseEvent *pEvent)
{
    if(pEvent->button() == Qt::LeftButton)
    {
        m_isHold = true;
        m_relativePoint = pEvent->globalPos() - this->pos();
    }
}

void MyWidget::mouseReleaseEvent(QMouseEvent *)
{
    m_isHold = false;
}

void MyWidget::mouseMoveEvent(QMouseEvent *pEvent)
{
    if(m_isHold)
    {
        this->move(pEvent->globalPos() - m_relativePoint);
    }
}

但是这种做法会导致一个很严重的问题,就是在鼠标拖动窗口的时候,可以把窗口拖到任务栏下面,联众游戏里面捆绑的联众助手就有这个问题。
有一种网上流传的土办法可以解决此问题:

this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);

这样做的话,窗口的确不会被拖到任务栏下了,但是总在最前的窗口也不能让人满意。
因为这个问题只会出现在Windows下,所以我们可以通过Win32 API来解决问题,MSDN里可以查到一个名叫ClipCursor的函数:

BOOL WINAPI ClipCursor(_In_opt_  const RECT *lpRect);
/*
Parameters: lpRect [in, optional] Type: const RECT*
A pointer to the structure that contains the screen coordinates
of the upper-left and lower-right corners of the confining rectangle.
If this parameter is NULL, the cursor is free to move anywhere on the screen.

Return value: Type: BOOL
If the function succeeds, the return value is nonzero.
*/

这个函数接收一个RECT*类型的参数,限制鼠标指针的活动在这个RECT限制的范围内。
于是我们有了以下的解决方案:

//类声明:
#include <windows.h>

class MyWidget: public QWidget
{
    Q_OBJECT
//...
private:
    RECT rtConfined;
    RECT rtDefault;
//...
}

//构造函数里:
{
//...
    ::SystemParametersInfo(SPI_GETWORKAREA , 0 , &this->rtConfined , 0);
    ::GetWindowRect(::GetDesktopWindow() , &this->rtDefault);
//...
}

//重写事件响应虚函数:
void MyWidget::mousePressEvent(QMouseEvent *pEvent)
{
//...
    if(pEvent->button() == Qt::LeftButton)
    {
        m_isHold = true;
        m_relativePoint = pEvent->globalPos() - this->pos();
    }
    ::ClipCursor(&rtConfined);
//...
}

void MyWidget::mouseReleaseEvent(QMouseEvent *)
{
    m_isHold = false;
    ::ClipCursor(&rtDefault);
}

2. Qt4无边框窗口失去焦点的问题

在项目从Qt5迁移到Qt4的过程中,出现过一个问题:一个无边框透明窗体,在showMinimized之后,点击任务栏图标,不会触发窗体的自动重绘,窗口表现为失去焦点
设置窗体透明的代码如下:

this->setWindowOpacity(1);
QPalette pal = palette();
pal.setColor(QPalette::Background, QColor(0x00,0xff,0x00,0x00));//Qt4里必须这样否则不透明
this->setPalette(pal);
this->setWindowFlags(Qt::FramelessWindowHint|Qt::WindowMinimizeButtonHint|Qt::WindowSystemMenuHint);
this->setAttribute(Qt::WA_TranslucentBackground, true);

在中文网路上查找了很久也没有找到解决方案,后来改去爆栈上搜,也没看出个所以然,但是初步怀疑是无边框窗口的缘故,最后用Google去“site:qt-project.org”里看到了相关资料,这是一个 Qt4的bug,可以参考官网的链接
Widget with Qt::FramelessWindowHint and Qt::WA_TranslucentBackground stops painting after minimize/restore
按照说明,得到了如下的workaround:

void MyWidget::showEvent(QShowEvent *pEvent)
{
    QApplication::postEvent(this, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority);
    QWidget::showEvent(pEvent);
}

是的,就是这样,问题就解决了。

原文地址:https://www.cnblogs.com/intervention/p/4031850.html