问题描述
我正在制作一个在完全透明的窗口中显示图像的脚本,因此它只是屏幕上的图像本身,您可以移动它。结果如下:
简化代码:
#include <math.h>
#include <windows.h>
#include <windowsx.h>
#include <objidl.h>
#include <gdiplus.h>
using namespace Gdiplus;
#pragma comment (lib,"Gdiplus.lib")
HWND hWnd;
double imageZoom = 0.5;
VOID OnPaint(HWND hWnd,HDC hdc)
{
Bitmap image(L"example.png");
// Get image dimensions
int imageWidth = image.GetWidth();
int imageHeight = image.GetHeight();
// Update the dimensions using the image zoom
imageWidth = static_cast<int>(floor((double)imageWidth * imageZoom));
imageHeight = static_cast<int>(floor((double)imageHeight * imageZoom));
// Make a DC on which to draw the image
HDC drawingDC = CreateCompatibleDC(hdc);
// Create a new bitmap for drawing on it
HBITMAP newBitmap = CreateCompatibleBitmap(hdc,imageWidth,imageHeight);
// Select the new bitmap to draw on it and save the old one
HBITMAP oldBitmap = (HBITMAP)SelectObject(drawingDC,newBitmap);
// Draw image to the newly created DC
Graphics graphics(drawingDC);
Rect point(0,imageHeight);
graphics.DrawImage(&image,point);
// Create a blend function
BLENDFUNCTION blend = { 0 };
blend.BlendOp = AC_SRC_OVER;
blend.SourceConstantAlpha = 255;
blend.AlphaFormat = AC_SRC_ALPHA;
// Set window info
RECT coord;
GetWindowRect(hWnd,&coord);
POINT windowPosition = { coord.left,coord.top };
SIZE windowSize = { imageWidth,imageHeight };
POINT imagePosition = { 0,0 };
// Call UpdateLayeredWindow
UpdateLayeredWindow(hWnd,hdc,&windowPosition,&windowSize,drawingDC,&imagePosition,&blend,ULW_ALPHA);
SelectObject(drawingDC,oldBitmap);
DeleteObject(newBitmap);
DeleteDC(drawingDC);
ReleaseDC(NULL,hdc);
}
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
INT WINAPI WinMain(HINSTANCE hInstance,HINSTANCE,PSTR,INT iCmdShow)
{
// Initialize GDI+.
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken,&gdiplusStartupInput,NULL);
MSG msg;
WNDCLASS wndClass;
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WndProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = 0;
wndClass.hCursor = LoadCursor(NULL,IDC_ARROW);
wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = TEXT("Sticker");
RegisterClass(&wndClass);
hWnd = CreateWindowEx(
WS_EX_LAYERED,TEXT("Sticker"),// window class name
TEXT("Sticker"),// window caption
NULL,// window style
0,// initial x position
0,// initial y position
500,// initial x size
500,// initial y size
NULL,// parent window handle
NULL,// window menu handle
hInstance,// program instance handle
NULL); // creation parameters
ShowWindow(hWnd,iCmdShow);
while (GetMessage(&msg,NULL,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
GdiplusShutdown(gdiplusToken);
return msg.wParam;
} // WinMain
bool holding = false;
LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
switch (message)
{
case WM_CREATE:
hdc = BeginPaint(hWnd,&ps);
OnPaint(hWnd,hdc);
EndPaint(hWnd,&ps);
return 0;
case WM_LBUTTONDOWN:
// In short,this allows moving the image
PostMessage(hWnd,WM_NCLBUTTONDOWN,2,0);
return 0;
case WM_PAINT:
hdc = BeginPaint(hWnd,&ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_MBUTTONDOWN:
// Just to test the size changing
imageZoom += 0.1;
RedrawWindow(hWnd,RDW_INTERNALPAINT);
return 0;
case WM_RBUTTONDOWN:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hWnd,message,wParam,lParam);
}
} // WndProc
我不确定这是否是使用 DC 和 RedrawWindow()
的正确方法。问题是,如果我 RedrawWindow()
使用新的图像大小(我包含了 WM_MBUTTONDOWN 消息来测试),图像会更新并使用新大小绘制,但分层窗口的大小似乎保持不变不知何故相同。这是它的样子:
我不知道为什么会这样,所以也许有人知道为什么。
但主要的问题是,创建、更新和渲染分层窗口的正确方法是什么?我想这种方式不好,但我在互联网上找不到任何其他可以理解的例子
更新:
我已经更新了代码。现在它不使用 WM_PAINT 消息,只在需要时使用 UpdateLayeredWindow。
#include <math.h>
#include <windows.h>
#include <windowsx.h>
#include <objidl.h>
#include <gdiplus.h>
using namespace Gdiplus;
#pragma comment (lib,"Gdiplus.lib")
#include <wincodec.h>
#include <wincodecsdk.h>
#pragma comment(lib,"WindowsCodecs.lib")
HWND hWnd;
Bitmap* image;
double imageZoom = 0.5;
int originalWidth;
int originalHeight;
void firstUpdateLayeredWindow()
{
image = Bitmap::FromFile(L"example.png");
// Get image dimensions
originalWidth = image->GetWidth();
originalHeight = image->GetHeight();
// Update the dimensions using the image zoom
int imageWidth = static_cast<int>(floor((double)originalWidth * imageZoom));
int imageHeight = static_cast<int>(floor((double)originalHeight * imageZoom));
HDC hdc = GetDC(NULL);
// Make a DC which which hold the bitmap for drawing
HDC drawingDC = CreateCompatibleDC(hdc);
// Create a new bitmap for drawing on it
HBITMAP newBitmap = CreateCompatibleBitmap(hdc,imageHeight);
// Select the new bitmap onto the drawing DC and save the old one
HBITMAP oldBitmap = (HBITMAP)SelectObject(drawingDC,newBitmap);
// Draw image to the newly created DC
Graphics graphics(drawingDC);
Rect point(0,imageHeight);
graphics.DrawImage(image,hdc);
}
void followingUpdateLayeredWindow()
{
// Update the dimensions using the image zoom
int imageWidth = static_cast<int>(floor((double)originalWidth * imageZoom));
int imageHeight = static_cast<int>(floor((double)originalHeight * imageZoom));
HDC hdc = GetDC(NULL);
// Make a DC on which to draw the image
HDC drawingDC = CreateCompatibleDC(hdc);
// Create a new bitmap for drawing on it
HBITMAP newBitmap = CreateCompatibleBitmap(hdc,point);
// Create a blend function
BLENDFUNCTION blend = { 0 };
blend.BlendOp = AC_SRC_OVER;
blend.SourceConstantAlpha = 255;
blend.AlphaFormat = AC_SRC_ALPHA;
// Set window info
RECT coord;
GetWindowRect(hWnd,NULL);
MSG msg;
WNDCLASS wndClass;
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WndProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = 0;
wndClass.hCursor = LoadCursor(NULL,IDC_ARROW);
wndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = TEXT("Sticker");
RegisterClass(&wndClass);
hWnd = CreateWindowEx(
WS_EX_LAYERED,// window caption
WS_DLGFRAME,// program instance handle
NULL); // creation parameters
// Update the layered window for the first time,attaching a bitmap to it
firstUpdateLayeredWindow();
ShowWindow(hWnd,LPARAM lParam)
{
switch (message)
{
case WM_LBUTTONDOWN:
// In short,0);
return 0;
case WM_MBUTTONDOWN:
{
// Just to test the size changing
imageZoom += 0.1;
// Update the layered window with the function for updating it multiple times
followingUpdateLayeredWindow();
}
return 0;
case WM_RBUTTONDOWN:
PostQuitMessage(0);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hWnd,lParam);
}
} // WndProc
不幸的是,它仍然无法正常工作。图像已正确调整大小,但结果与之前的屏幕截图相同(图像被剪裁)。它仅在增加图像大小时发生,这就是为什么我认为问题在于分层窗口本身的大小。更奇怪的是,如果我增加 imageZoom 变量很多,然后移动窗口,它实际上会出于某种原因自行更新并以实际大小绘制整个图像,但这只会发生在窗口传递某个值什么的。
在更新附加到它的位图后,我什至尝试使用单独的 UpdateLayeredWindow()
函数更新分层窗口的大小。
更新:已解决但不知道为什么
我通过在分层窗口中包含 WS_POPUP 样式解决了图像被剪裁的奇怪行为。现在它完美运行,虽然我不知道为什么
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)