學習一短時間Qt后想做一個桌面壁紙的程式,由于沒有學過 WinAPI 編程只會些Qt,所以取桌面的句柄和設定桌面的背景圖只能先從網上尋找,功夫不負有心人還是找到比較滿意的WinAPI的代碼,然后根據這些代碼學習了以下,下面是從網上尋找到的代碼,我根據這些代碼和在網上查資料做了些注釋,畢竟基礎不牢,感覺有很多的錯誤,
#include <windows.h> /** 宣告一個句柄類的 靜態變數 */ static HWND g_workerw = 0; /** 實作一個讓 EnumWindows()使用的,獲取我們要將程式設定到桌面位置的句柄回呼函式 */ static BOOL CALLBACK EnumWndCallback(HWND tophandle, LPARAM topparamhandle) { // 該函式的作用:由于我們要用的 視窗 是沒有視窗名但我們知道我們所需要的視窗的類名是:"WorkerW", // 我們還知道我們所需要的視窗的子視窗的 子視窗的類名是:"SHELLDLL_DefView" // 我們還知道我們所需要的視窗的子視窗的視窗風格是 可見的視窗風格 // 所以我們先尋找一個視窗的視窗風格是可見的視窗風格,再檢測該視窗的子視窗有沒有類名是 "SHELLDLL_DefView"的視窗, // 然后再檢測該視窗的父視窗有沒有類名是 "WorkerW" 的視窗,如果都吻合,那這個視窗就是我們所需要的視窗的子視窗, // 那變數 tophandle 存盤的句柄所對應的視窗的 父視窗就是我們需要的視窗 // 注意:topparamhandle形參之所以沒有使用,是因為 EnumWindows函式并沒有向 // 存盤獲取我們要想視窗的句柄的變數或者是變數指標,而是傳遞了 0,0是無法存盤資料的 // 所以通過 EnumWndCallback() 函式獲取的視窗句柄 只能通過 全域變數進行傳遞了 // GetWindowLong() 函式可獲取指定視窗的有關資訊, // tophandle 目標視窗句柄也就是 EnumWindows() 列舉螢屏上的所有的頂層視窗的句柄 // GWL_STYLE 的作用是獲取傳入視窗句柄的視窗的視窗風格 long wflags = GetWindowLong(tophandle, GWL_STYLE); // 判斷獲取到的視窗風格是否是 可見的視窗風格 // 判斷方法是 獲取的視窗風格 和 可見的視窗風格 WS_VISIBLE 進行 與(&) 操作 // 如果 獲取的視窗風格的二進制中的第 29 位是 1, // 那 進行 與(&) 操作 后的值 就是 WS_VISIBLE 所對應的值也就是不為 0 的值 // 如果 獲取的視窗風格的二進制中的第 29 位是 0, // 那 進行 與(&) 操作 后的值 就是 0 // WS_VISIBLE(十六進制是 10000000, 二進制是 1 0000 0000 0000 0000 0000 0000 000 0) // 然后根據 ! 運算子進行反轉 if (!(wflags & WS_VISIBLE)) { // 判斷 獲取的 視窗風格是否不是 可見的視窗風格 // 如果 不是可見的視窗風格,就回傳 TRUE, 就讓 EnumWindows() 函式繼續列舉新的視窗 return TRUE; }; // tophandle 是 EnumWindows() 列舉螢屏上的所有的頂層視窗的句柄 // 利用 FindWindowEx() 尋找父視窗的句柄是變數 tophandle 存盤的句柄的子視窗的類是 "SHELLDLL_DefView" 的視窗的句柄 // 我們尋找的視窗的類名是 "SHELLDLL_Defview" HWND p = FindWindowEx(tophandle, 0, L"SHELLDLL_DefView", 0); // 判斷 是否獲取了句柄 if (p != 0) { // Gets the WorkerW Window after the current one // 利用 FindWindowEx() 尋找子視窗的句柄是變數 tophandle 存盤的句柄的父視窗的類是 "SHELLDLL_DefView" 的視窗的句柄 // 我們尋找的視窗的類名是 "WorkerW" ,類名是 "WorkerW" 才是我們要用的視窗 g_workerw = FindWindowEx(0, tophandle, L"WorkerW", 0); // 判斷 g_workerw 中是否存盤了我們想要的視窗列舉值 if (0 != g_workerw) { // 傳給 EnumWindows() 函式 FALSE // 停止 EnumWindows() 函式的列舉 return FALSE; } } // 傳給 EnumWindows() 函式 TRUE // 讓 EnumWindows() 函式繼續列舉 return TRUE; } Widget::Widget(QWidget *parent) : QWidget(parent) { /** 利用 FindWindow() 函式獲取一個 類是 "Progman" 視窗標題是"Program Manager"的視窗句柄 */ HWND hwndPrgam = FindWindow(L"Progman", L"Program Manager"); // 利用 SendMessageTimeout() 函式將指定的訊息 0x052C, 發送 hwndPrgam 存盤的列舉值的視窗 // SMTO_NORMAL:呼叫執行緒等待函式回傳時,不被阻止處理其他請求, 1000 為超時周期指定以毫秒為單位的持續時間 SendMessageTimeout(hwndPrgam, 0x052C, 0,0,SMTO_NORMAL, 1000,0); // 上面的兩行代碼,根據查詢的知識做了些注釋但還是不清楚作用是什么,將上面的兩行代碼注釋掉 // 也可以實作 將程式設定到桌面壁紙上 // 利用 EnumWindows() 列舉螢屏上的所有的頂層視窗,并將列舉的視窗傳入 EnumWndCallback() 函式中 // 也就是,不停的傳視窗句柄給 EnumWndCallback() 函式直到找到需要的 視窗的句柄為止 // 或列舉完所有的視窗也沒有找到我們需要的視窗 // EnumWindows() 函式第二個形參傳入的是 0,意味著無法通過EnumWindows() 函式第二個形參獲取 // 我們想要的視窗句柄,只能通過 全域變數獲取 EnumWndCallback() 函式中找到的我們需要的視窗句柄 EnumWindows(EnumWndCallback, 0); // 判斷是否獲取了視窗句柄 if (g_workerw == 0) { // 如果沒有獲取到句柄就結束該程式 abort(); } else { // 如果 獲取了視窗句柄 // 將該程式設定到桌面的壁紙層中 SetParent((HWND)this->winId(), g_workerw); }
我用上面找到的代碼,然后結合我自己學習的Qt的知識,可以實作將程式放到桌面壁紙上但是當關閉程式時,桌面壁紙還是程式上的圖片,我用 Spy++ 查看,程式的句柄
已經沒有了,所有我到 Windows10 個性化中將壁紙從新設定以下,發現桌面壁紙不在是程式上的圖片了,所有我考慮是否可以用代碼設定系統的壁紙,所以我在網上尋找到了下面的代碼,并根據網上的知識做了些注釋,
// 通過 setting 獲取 Windows10系統的 "HKEY_CURRENT_USER\\Control Panel\\Desktop" 的注冊表 QSettings setting("HKEY_CURRENT_USER\\Control Panel\\Desktop", QSettings::NativeFormat); // 獲取 注冊表地址上名稱是 "WallPaper" 的值,也就是 Windows10系統的 // 當前桌面壁紙的路徑 QString src = https://www.cnblogs.com/MoonMagic/p/setting.value("WallPaper",true).toString(); // 將桌面壁紙的路徑轉換成寬位元組,很重要,否則顯示不了圖片 TCHAR *ptch = (TCHAR *)src.toStdWString().c_str(); // 顯示桌面壁紙 SPI_SETDESKWALLPAPER 表示要設定桌面墻紙,bmpfile 是要設定的圖片的路徑 // SPIF_UPDATEINIFILE:把新的系統引數的設定內容寫入用戶組態檔 SystemParametersInfo(SPI_SETDESKWALLPAPER, 0,ptch, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE );
使用上面的代碼就可以實作從系統的注冊表取出桌面壁紙的圖片路徑并又設定了一次桌面壁紙,
結合上面的兩端代碼,設定壁紙的核心就算搞定了,其他的可以用Qt 來寫了,
為了驗證自己的代碼是否成功又添加了一些 Qt的代碼,寫成了下面寫的Qt視窗類,畢竟只是驗證一下,下面的代碼還需要進行很多的完善,
頭檔案:
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QPainter> // Qt 的畫家類 #include <QPixmap> // Qt 的 Pixmap 類 #include <windows.h> // Windows.h是一個最重要的頭檔案,它包含了其他Windows頭檔案 #include <QSettings> // QSettings類提供持久的獨立于平臺的應用程式設定, class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); public slots: /** 接收傳過來的圖片路徑的槽函式 */ void gengGaiTuPian(QString path); /** 接收傳過來的圖片路徑的槽函式 */ void guanBiChuangKou(); private: /** 圖片路徑 */ QString tuPianLuJiang = ""; protected: /** 重寫繪圖事件 */ void paintEvent(QPaintEvent *event); }; #endif // WIDGET_H
源檔案:
#include "widget.h" /** 宣告一個句柄類的 靜態變數 */ static HWND g_workerw = 0; /** 實作一個讓 EnumWindows()使用的,獲取我們要將程式設定到桌面位置的句柄回呼函式 */ static BOOL CALLBACK EnumWndCallback(HWND tophandle, LPARAM topparamhandle) { // 該函式的作用:由于我們要用的 視窗 是沒有視窗名但我們知道我們所需要的視窗的類名是:"WorkerW", // 我們還知道我們所需要的視窗的子視窗的 子視窗的類名是:"SHELLDLL_DefView" // 我們還知道我們所需要的視窗的子視窗的視窗風格是 可見的視窗風格 // 所以我們先尋找一個視窗的視窗風格是可見的視窗風格,再檢測該視窗的子視窗有沒有類名是 "SHELLDLL_DefView"的視窗, // 然后再檢測該視窗的父視窗有沒有類名是 "WorkerW" 的視窗,如果都吻合,那這個視窗就是我們所需要的視窗的子視窗, // 那變數 tophandle 存盤的句柄所對應的視窗的 父視窗就是我們需要的視窗 // 注意:topparamhandle形參之所以沒有使用,是因為 EnumWindows函式并沒有向 // 存盤獲取我們要想視窗的句柄的變數或者是變數指標,而是傳遞了 0,0是無法存盤資料的 // 所以通過 EnumWndCallback() 函式獲取的視窗句柄 只能通過 全域變數進行傳遞了 // GetWindowLong() 函式可獲取指定視窗的有關資訊, // tophandle 目標視窗句柄也就是 EnumWindows() 列舉螢屏上的所有的頂層視窗的句柄 // GWL_STYLE 的作用是獲取傳入視窗句柄的視窗的視窗風格 long wflags = GetWindowLong(tophandle, GWL_STYLE); // 判斷獲取到的視窗風格是否是 可見的視窗風格 // 判斷方法是 獲取的視窗風格 和 可見的視窗風格 WS_VISIBLE 進行 與(&) 操作 // 如果 獲取的視窗風格的二進制中的第 29 位是 1, // 那 進行 與(&) 操作 后的值 就是 WS_VISIBLE 所對應的值也就是不為 0 的值 // 如果 獲取的視窗風格的二進制中的第 29 位是 0, // 那 進行 與(&) 操作 后的值 就是 0 // WS_VISIBLE(十六進制是 10000000, 二進制是 1 0000 0000 0000 0000 0000 0000 000 0) // 然后根據 ! 運算子進行反轉 if (!(wflags & WS_VISIBLE)) { // 判斷 獲取的 視窗風格是否不是 可見的視窗風格 // 如果 不是可見的視窗風格,就回傳 TRUE, 就讓 EnumWindows() 函式繼續列舉新的視窗 return TRUE; }; // tophandle 是 EnumWindows() 列舉螢屏上的所有的頂層視窗的句柄 // 利用 FindWindowEx() 尋找父視窗的句柄是變數 tophandle 存盤的句柄的子視窗的類是 "SHELLDLL_DefView" 的視窗的句柄 // 我們尋找的視窗的類名是 "SHELLDLL_Defview" HWND p = FindWindowEx(tophandle, 0, L"SHELLDLL_DefView", 0); // 判斷 是否獲取了句柄 if (p != 0) { // Gets the WorkerW Window after the current one // 利用 FindWindowEx() 尋找子視窗的句柄是變數 tophandle 存盤的句柄的父視窗的類是 "SHELLDLL_DefView" 的視窗的句柄 // 我們尋找的視窗的類名是 "WorkerW" ,類名是 "WorkerW" 才是我們要用的視窗 g_workerw = FindWindowEx(0, tophandle, L"WorkerW", 0); // 判斷 g_workerw 中是否存盤了我們想要的視窗列舉值 if (0 != g_workerw) { // 傳給 EnumWindows() 函式 FALSE // 停止 EnumWindows() 函式的列舉 return FALSE; } } // 傳給 EnumWindows() 函式 TRUE // 讓 EnumWindows() 函式繼續列舉 return TRUE; } Widget::Widget(QWidget *parent) : QWidget(parent) { /** 利用 FindWindow() 函式獲取一個 類是 "Progman" 視窗標題是"Program Manager"的視窗句柄 */ HWND hwndPrgam = FindWindow(L"Progman", L"Program Manager"); // 利用 SendMessageTimeout() 函式將指定的訊息 0x052C, 發送 hwndPrgam 存盤的列舉值的視窗 // SMTO_NORMAL:呼叫執行緒等待函式回傳時,不被阻止處理其他請求, 1000 為超時周期指定以毫秒為單位的持續時間 SendMessageTimeout(hwndPrgam, 0x052C, 0,0,SMTO_NORMAL, 1000,0); // 上面的兩行代碼,根據查詢的知識做了些注釋但還是不清楚作用是什么,將上面的兩行代碼注釋掉 // 也可以實作 將程式設定到桌面壁紙上 // 利用 EnumWindows() 列舉螢屏上的所有的頂層視窗,并將列舉的視窗傳入 EnumWndCallback() 函式中 // 也就是,不停的傳視窗句柄給 EnumWndCallback() 函式直到找到需要的 視窗的句柄為止 // 或列舉完所有的視窗也沒有找到我們需要的視窗 // EnumWindows() 函式第二個形參傳入的是 0,意味著無法通過EnumWindows() 函式第二個形參獲取 // 我們想要的視窗句柄,只能通過 全域變數獲取 EnumWndCallback() 函式中找到的我們需要的視窗句柄 EnumWindows(EnumWndCallback, 0); // 判斷是否獲取了視窗句柄 if (g_workerw == 0) { // 如果沒有獲取到句柄就結束該程式 abort(); } else { // 如果 獲取了視窗句柄 // 將該程式設定到桌面的壁紙層中 SetParent((HWND)this->winId(), g_workerw); } // 給視窗去掉邊框 this-> setWindowFlags(Qt::FramelessWindowHint | windowFlags() ); // 設定視窗全屏顯示 this->showFullScreen(); // 為 tuPianLuJiang 賦值 tuPianLuJiang = "://BeiJing.jpg"; } Widget::~Widget() { } void Widget::gengGaiTuPian(QString path) { // 判斷 path 是否不為空 if (!path.isEmpty()) { tuPianLuJiang = path; // 通過 update() 函式呼叫 繪圖事件 this->update(); } } void Widget::guanBiChuangKou() { // 隱藏該視窗 this->hide(); // 通過 setting 獲取 Windows系統的 "HKEY_CURRENT_USER\\Control Panel\\Desktop" 的注冊表 QSettings setting("HKEY_CURRENT_USER\\Control Panel\\Desktop", QSettings::NativeFormat); // 獲取 注冊表地址上名稱是 "WallPaper" 的值,也就是 Windows10系統的 // 當前桌面壁紙的路徑 QString src = https://www.cnblogs.com/MoonMagic/p/setting.value("WallPaper",true).toString(); // 將桌面壁紙的路徑轉換成寬位元組,很重要,否則顯示不了圖片 TCHAR *ptch = (TCHAR *)src.toStdWString().c_str(); // 顯示桌面壁紙 SPI_SETDESKWALLPAPER 表示要設定桌面墻紙,bmpfile 是要設定的圖片的路徑 // SPIF_UPDATEINIFILE:把新的系統引數的設定內容寫入用戶組態檔 SystemParametersInfo(SPI_SETDESKWALLPAPER, 0,ptch, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE ); // delete 該類 // 使用完該類后,delete 該類,句柄才會消失,當是主視窗時不用 delete delete this; } void Widget::paintEvent(QPaintEvent *event) { // 實體化 畫家的物件 // 需要先添加 #include <QPainter> 頭檔案 // this 是設定在哪里畫畫是指定繪圖的設備不是設定父類 QPainter painter(this); // 實體化一個 QPixmap,并傳入本地的一張圖片 QPixmap pixmap(tuPianLuJiang); // 將圖片 通過畫家類的實體繪制的 視窗上 painter.drawPixmap(0, 0, this->width(), this->height(), pixmap); }
由于對編程的愛好,學習了一段時間的編程,雖然學習的時間不短,但基礎實在是太弱了,第一次寫博客,這篇博客算是自己學習其他知識的一點總結,完善這個程式后再學習其他的Qt 知識,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/228330.html
標籤:C++
上一篇:快速排序
