IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> Wallpaper透视效果的C++实现(含源文件) -> 正文阅读

[C++知识库]Wallpaper透视效果的C++实现(含源文件)

Wallpaper的透视图实际上包含了两张图,一张是非透视图,即正常情况下能够被看到的图片,另一张是透视图,即鼠标移到上面才会部分显示的图片。

本文将使用Qt框架实现类似效果

最终效果

代码

桌面子窗体?

将自己的窗体设置成桌面的子窗体,其原理在之前的Wallpaper文章中已经介绍过,故直接放出代码,不再解释。

void SetFather(HWND child){
    HWND hwnd = GetBackground();
    if(hwnd == NULL){
        SendMessage(hwnd,0x052C,0,0);
        hwnd = GetBackground();
    }
    if(hwnd != NULL){
        SetParent(child,hwnd);
    }
}

HWND GetBackground(){
    HWND hwnd = FindWindowA("progman","Program Manager");
    HWND worker = NULL;
    do{
        worker = FindWindowExA(NULL,worker,"workerW",NULL);
        if(worker != NULL){
            char buff[200] = {0};
            int ret = GetClassNameA(worker,(PCHAR)buff,sizeof(buff)*2);
            if(ret == 0){
                return NULL;
            }
        }
        if(GetParent(worker) == hwnd){
            return worker;
        }
    }while(worker != NULL);
    return NULL;
}

?鼠标事件捕捉

由于将窗体设置成了背景层的子窗体,而背景层上面还有一层图标层,所以我们自己写的窗体将无法接受鼠标事件,也就无法对鼠标移动做出反应,因此我们需要使用HOOK拦截系统的鼠标事件,HOOK程序将会在鼠标移动事件发生之前优先执行,这样就可以捕捉到鼠标移动事件。

HHOOK hook;
void GetHook(){
    hook = SetWindowsHookEx(WH_MOUSE_LL,mouseProc,GetModuleHandle(NULL),NULL);
}
LRESULT CALLBACK mouseProc(int nCode,WPARAM wParam,LPARAM lParam ){
    if(nCode == HC_ACTION){
        if(wParam == WM_MOUSEMOVE){
            main->repaint();//界面重绘,main是本窗体,相当于this
        }
    }
    return false;
}

绘图与蒙版

实现透视效果的原理是先绘制非透视图,然后根据鼠标位置绘制透视图的一小部分,为了方便,我们称非透视图为“背景图”,称透视图为“前景图”,因为透视图是覆盖在非透视图上面的。

全局变量

QPixmap *foreground;//前景图,透视图
QPixmap *background;//背景图,非透视图
QPixmap *cut;//透视图裁剪后的图片
QBitmap *maskBitmap;//蒙版
QPixmap *maskPic;//裁剪后的蒙版
QColor *color;//透视颜色
int x1,x2,y1,y2;//透视区域的坐标
int startX,startY;//蒙版起始坐标
int radius;//透视半径
int Desktop_width,Desktop_height;//桌面的尺寸
bool repaintable = true;//重绘

?LoadPicture()函数用来加载图片

void Widget::LoadPicture(QString fore,QString back){
    foreground = new QPixmap();
    background = new QPixmap();
    cut = new QPixmap();
    foreground->load(fore);
    background->load(back);
    QDesktopWidget *desktop = QApplication::desktop();
    QRect rect = desktop->screenGeometry();
    Desktop_width = rect.width();
    Desktop_height = rect.height();
    *foreground = foreground->scaled(rect.width(),rect.height(),Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
    *background = background->scaled(rect.width(),rect.height(),Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
}

在SetRadius()函数中,需要初始化蒙版,先定义一个长为2*radius的正方形QBitmap,然后画上颜色为color(黑色)的圆形

void Widget::SetRadius(int r){
    if(radius == r) return;
    radius = r;
    QSize size(2*radius, 2*radius);
    maskBitmap = new QBitmap(size);
    maskPic = new QPixmap(size);
    color = new QColor(0,0,0);
    QPainter painter(maskBitmap);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setRenderHint(QPainter::SmoothPixmapTransform);
    painter.fillRect(0, 0, size.width(), size.height(), Qt::white);
    painter.setBrush(*color);
    painter.drawRoundedRect(0, 0, size.width(), size.height(), radius, radius);
    repaint();
}

根据鼠标位置计算出正确的区域大小,这是一个以鼠标为中心,2*radius为长的正方形,(x1,y1)是左上角坐标,(x2,y2)是右下角坐标,这两个坐标构成了一个裁剪框,但是这个坐标有可能会超出屏幕范围,一旦超出,就会导致裁剪的时候出现图片拉伸,所以需要加上判断语句来限制大小。

接着根据限制后的大小和位置,在前景图(透视图)上裁剪出相应区域。

startX和startY是蒙版的起始位置,如果(x1,y1)超出屏幕区域,就意味着裁剪框将不是正方形,而蒙版却是正方形的,所以必须对蒙版也进行裁剪,使蒙版的大小恰好等于裁剪框的大小。

void Widget::paintEvent(QPaintEvent *){
    GetCursorPos(&p);
    x1 = p.x - radius;
    y1 = p.y - radius;
    x2 = p.x + radius;
    y2 = p.y + radius;
    if(x1 < 0) {
        startX = -x1;
        x1 = 0;
    }else{
        startX = 0;
    }
    if(y1 < 0) {
        startY = -y1;
        y1 = 0;
    }else{
        startY = 0;
    }
    if(x2 > Desktop_width) x2 = Desktop_width;
    if(y2 > Desktop_height) y2 = Desktop_height;
    *cut = foreground->copy(x1,y1,x2-x1,y2-y1);//裁剪前景图(透视图)
    *maskPic = maskBitmap->copy(startX,startY,x2-x1,y2-y1);//裁剪蒙版
    cut->setMask(maskPic->createMaskFromColor(*color,Qt::MaskOutColor));//给cut设置蒙版
    QPainter painter(this);
    painter.drawPixmap(0,0,width(),height(),*background);//先画背景图
    painter.drawPixmap(x1,y1,x2-x1,y2-y1,*cut);//在画前景图(透视图),覆盖在背景图上面
}

内存释放

HOOK会降低计算机效率,所以在使用完毕后必须释放,当关闭程序时windows系统会自动释放HOOK,但是我们希望用户在主动关闭壁纸但是还未退出程序时也要释放掉HOOK,同时摧毁窗体。

Dispose()函数的用途就是摧毁窗体,然后释放HOOK

void Widget::Dispose(){
    this->hide();
    UnhookWindowsHookEx(hook);
    this->close();
}

任务栏角标

之前文章已经介绍过,这里直接放出代码。

void Set::AddTray(){
    //QSystemTrayIcon tray;   在.h文件中定义
    tray.setToolTip("X-Ray");
    tray.setIcon(QIcon(":Icon/ico.ico"));
    QMenu *menu = new QMenu();
    QAction *action_showDialog = new QAction("打开主窗口");
    QAction *action_free = new QAction("释放内存");
    QAction *action_exit = new QAction("退出");
    menu->addAction(action_showDialog);
    menu->addAction(action_free);
    menu->addSeparator();
    menu->addAction(action_exit);
    tray.setContextMenu(menu);
    connect(action_showDialog,SIGNAL(triggered(bool)),this,SLOT(ShowDialog()));
    connect(action_free,SIGNAL(triggered(bool)),this,SLOT(on_button_free_clicked()));
    connect(action_exit,SIGNAL(triggered(bool)),this,SLOT(on_button_exit_clicked()));
    tray.show();
}

源文件

https://dearx.lanzoui.com/ixRT2scl3nc

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-08 11:03:10  更:2021-08-08 11:06:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/9 17:12:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码