好久没来了更新了,今天使用Qt做了个异形窗口,这里记录下,效果如下。

 

 

老规矩,开发环境:

System:win10x64

Qt version:Qt 5.14.0

编译器:MINGW_64

Author : 点缀

 

  首先创建一个QWidget的项目,类名自己随便写,基类是继承QWidget,因为窗口是四方的,我们需要把窗口设置成图片的形状。代码如下:

  

QPixmap pixmap("../res/t6.jpg",nullptr,Qt::AvoidDither|Qt::ThresholdDither|Qt::ThresholdAlphaDither);

resize(pixmap.size());
setMask(pixmap.mask());
setWindowFlags(Qt::FramelessWindowHint
| Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint);

 

 

首先在构造函数里,将图片加载进QPixmap,resize函数将窗口大小设置成图片大小。然后利用setMask函数设置窗口的背景掩码,最后一步很重要,就是设置下窗口的属性:无边框,无标题栏,无最大最小化按钮。

到了这里,窗口就能变成你选择的图片的样子了,但是还没结束,我们还要做三点:一、因为我们取消了最大最小化按钮,所以窗口现在关不了了,所以我们得写下右键弹出菜单。二、让图片动起来(也可以不动,但我选择的是一个球体,动起来比较好看一点吧,哈哈)。
三、能移动窗口

一、添加右键菜单
这个功能很简单,直接重写右键菜单函数:
void contextMenuEvent(QContextMenuEvent *event) override;
先设置私有成员变量:
    QAction* act_start = nullptr;

    QAction* act_stop = nullptr;

    QAction* act_close = nullptr;

    QMenu* menu = nullptr;

接着在contextMenuEvent函数中添加和设置菜单:
void Widget::contextMenuEvent(QContextMenuEvent *event)
{
    Q_UNUSED(event)
    if(!menu)
    {
        menu = new QMenu(this);
    //为菜单设置样式,可以设置成自己喜欢的风格样式,感觉在写前端一样,哈哈。 menu
->setStyleSheet("QMenu{background-color:#ABABAB;border:1px solid black;margin:2px;}" "QMenu::item{padding: 2px 25px 2px 20px;margin:1px;border: 1px solid black;border-radius:5px;}" "QMenu::item:selected{background-color:#654321;border-color:darkblue;}" );

    //下面三个action就是菜单项 act_start
= menu->addAction("开始"); act_stop = menu->addAction("停止"); act_close = menu->addAction("关闭");

    //为菜单项关联信号与槽函数 connect(act_start,
&QAction::triggered,this,&Widget::act_start_slot); connect(act_stop,&QAction::triggered,this,&Widget::act_stop_slot); connect(act_close,&QAction::triggered,this,&Widget::close); } menu->exec(QCursor::pos()); //这一步很重要,别忘了写,让菜单显示出来。 }

//下面是两个槽函数的实现,最后的关闭函数close是窗口自带的,不需要我们写,直接用。
void Widget::act_start_slot()

{

    if(0 == timerId)

    {

        timerId = startTimer(100);

        act_start->setEnabled(false);

        act_stop->setEnabled(true);

    }

}



void Widget::act_stop_slot()

{

    if(timerId)

    {

        killTimer(timerId);

        timerId = 0;

        act_start->setEnabled(true);

        act_stop->setEnabled(false);

    }

}
 

到这里,右键菜单及其功能都实现了。

 

二、让星球转起来

  上面我们在实现右键菜单的时候,注意到我们使用了startTimer函数,这个函数是QWidget窗口自带的,我们并没有去new一个QTimer,然后为timer的timeout信号函数关联一个自己写的槽函数,并用connect去关联起来。我们也可以这样做,但是我不这样做的原因: 实现转动功能本身只需要一个定时器就够了,而且QWidget自带一个定时器,能偷懒就偷懒呗,哈哈。

 

  现在还有一个问题,既然上面使用了startTimer(100);那么意思就是每隔100ms就会触发定时器,那么定时器触发后去哪里实现超时函数呢?答案就是需要我们重写timerEvent函数:

1 void Widget::timerEvent(QTimerEvent *e)
2 {
3     Q_UNUSED(e)
4     angle+=5;
5     if(angle>=360)
6         angle = 0;
7     update();
8 
9 }

angle是我设置的成员变量,代表当前转动的角度,初始值设为0。也就是说每隔100ms,让角度转动5度(就是图片转动5度),当超过360度就重新从0开始计算,最后一个是更新显示函数update,就是我们主动去更新画面。既然使用了update函数,那么该函数会去执行paintEvent函数,所以我们得去实现它。

void Widget::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event)
    QPainter painter(this);
    painter.setRenderHint(QPainter::SmoothPixmapTransform);
    painter.translate(width()/2,height()/2);
    painter.rotate(angle);
    painter.translate(-(width()/2),-(height()/2));
    painter.drawPixmap(0,0,QPixmap("../res/test.jpg"));
}

上面的paintEvent函数里主要就是一个设置了防锯齿效果setRenderHint,还有就是转换坐标系,我们知道窗口的坐标系起点是左上角,然而我们要转动星球,当然是以星球的中心为原点来旋转,所以使用translate函数来重新设定坐标系原点为窗口的中心,然后使用rotate函数来旋转一定角度,最后我们需要将坐标系原点重新设置为左上角来绘制图片。搞定!!!

 

三、实现窗口的移动

功能:鼠标左键按下后移动,窗口也随着鼠标移动。

其实这个最简单了,无非就是实现(重写)鼠标的按下,移动和释放函数,直接上代码。

void Widget::mouseMoveEvent(QMouseEvent *event)
{
    if(ispressed)
    {
        move(event->globalPos() - point_deff);
    }

}

void Widget::mousePressEvent(QMouseEvent *event)
{
    if(event->button() & Qt::LeftButton)
    {
        ispressed = true;
        point_deff = event->globalPos() - pos();
    }
}

void Widget::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->button() & Qt::LeftButton)
        ispressed = false;
}

这里稍微解释下,ispressed和point_deff是两个成员变量,分别记录鼠标是否按下和坐标差。

point_deff是记录鼠标按下时,当前鼠标的全局坐标(相对于windows桌面的左上角)和当前窗口的全局坐标之差,说白了就是算出鼠标与当前窗口左上角的距离。然后当鼠标移动时,用鼠标的全局坐标减去point_deff就是当前窗口左上角的坐标位置了,使用move函数移动窗口就行了。

  终于记录完了,虽然只是写了一个小玩意,但里面涉及的点还是蛮多的,多玩玩就熟能生巧了,当然也可以根据自己的脑洞继续添加功能,比如星球的正反转啊之类的等等。

  不说了,老板喊我搬砖去了。溜了溜了,最后送上一个静态异形窗口小花花,哈哈。

  

 
posted on 2021-05-09 09:17  №点缀  阅读(607)  评论(0编辑  收藏  举报