Qt创建异形窗口

摘要:
它已经很久没有更新了。今天,我用Qt创建了一个特殊的窗口,记录在这里。效果如下。旧规则,开发环境:System:win10x64Qtversion:Qt5.14.0编译器:MINGW_64作者:装饰:首先,创建一个QWidget项目。自由书写类名。基类继承QWidget。因为窗口是正方形的,我们需要将窗口设置为图像的形状。

  

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

Qt创建异形窗口第1张

老规矩,开发环境:

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函数移动窗口就行了。

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

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

Qt创建异形窗口第2张

  

 

免责声明:文章转载自《Qt创建异形窗口》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇桌面程序开发入门(WinForm with C#)在asp.net webform中的 gridview 里面的一些基本操作下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

(23)事件分发机制

新事件分发机制:在2.x 版本事件处理时,将要触发的事件交给代理(delegate)处理,再通过实现代理里面的onTouchBegan等方法接收事件,最后完成事件的响应。而在新的事件分发机制中,只需通过创建一个事件监听器-用来实现各种触发后的逻辑,然后添加到事件分发器_eventDispatcher,所有事件监听器有这个分发器统一管理,即可完成事件响应。...

手机端html5触屏事件(touch事件)

touchstart:触摸开始的时候触发touchmove:手指在屏幕上滑动的时候触发touchend:触摸结束的时候触发而每个触摸事件都包括了三个触摸列表,每个列表里包含了对应的一系列触摸点(用来实现多点触控):touches:当前位于屏幕上的所有手指的列表。targetTouches:位于当前DOM元素上手指的列表。changedTouches:涉及当...

Android_UI_点击按钮切换背景效果实现

实现按钮按下和释放,按钮背景图片相应切换效果的方法这里介绍两种,一种是在代码里实现,另一种是在xml文件里实现 一、在xml文件里 首先现在layout的一个xml文件下定义Button如下所示: [html]view plaincopy <Button android:id="@+id/btn_user_selected" android...

Node.js躬行记(4)——自建前端监控系统

这套前端监控系统用到的技术栈是:React+MongoDB+Node.js+Koa2。将性能和错误量化。因为自己平时喜欢吃菠萝,所以就取名叫菠萝系统。其实在很早以前就有这个想法,当时已经实现了前端的参数搜集,只是后台迟迟没有动手,也就拖着。 目前完成的还只是个雏形,仅仅是搜集了错误和相关的性能参数。 后台样式采用了封装过的matrix。 分析功能还很薄弱...

ZK框架笔记5、事件

        事件是org.zkoss.zk.ui.event.Event类,它通知应用程序发生了什么事情。每一种类型的事件都由一个特定的类来表示。         要响应一个事件,应用程序必须为事件注册一个或更多事件监听器。有3种方式可以为一个组件事件监听器。   (1)一般制定onXXX事件监听器为组件的属性,作为属性定义的事件监听器。 &...

IE、火狐(Firefox)和谷歌(Google Chrome)浏览器差异【收集】

项目的页面要求javascript在IE、火狐(Firefox)和谷歌(Google Chrome)三个浏览器中都能运行,期间遇到一些问题,现收集并总结一些: 1.获取鼠标的坐标时,使用event.clientX,不要使用event.x,因为火狐不支持event.x,最好使用event.screenX。 2.火狐中不能在js中直接使用event对象,必须将...