我正在编写一个应用程序,它可以作为Java代码的API使用JNI。Java应用程序假定窗口客户端区域为800x400像素。无法修改此值。图像元素的所有大小和位置都与此格式相关。因此,必须将800x400表示“转换”为客户端区域内容。到目前为止,我是通过阻止用户调整窗口大小来做到这一点的:
LONG_PTR style = GetWindowLongPtr(hwnd, GWL_STYLE);
style &= ~(WS_THICKFRAME| WS_MAXIMIZEBOX);
SetWindowLongPtr(hwnd, GWL_STYLE, style);
SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
显然,这在用户体验方面是不好的。因此,我想要一种方法来调整800x400区域的内容。
到目前为止,该区域是通过以下算法绘制的,该算法运行良好:
LRESULT CALLBACK WindowCallbackF(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
WindowInterface* wi;
wi = getInterface(hwnd)/*This call always succeeds when HWND was created with this API;
What it does is irrelevant here(In case you are interested: it looks up hwnd in a global std::unordered_map of hwnd,WindowInterface* pairs*/;
switch (uMsg)
{
case WM_PAINT: {
PAINTSTRUCT ps;
ImageToRender* figure;
if (!hwnd) {
return 0;
}
HDC hdc = BeginPaint(hwnd, &ps);
HDC compatible = CreateCompatibleDC(hdc);
if ((wi->flags) && WindowFlags::BackgroundSet) {
SelectObject(compatible, wi->backgroundImage/*HBITMAP for the Background Image*/);
BitBlt(hdc, 0, 0, wi->initWidth/*800*/, wi->initHeight/*400*/, compatible, 0, 0, SRCCOPY);
}
wi->lock.lock();
/*wi->lock is a std::unique_lock<std::mutex>, and wi->figures is a std::vector<ImageToRender*>*/
for (size_t i = (wi->figures).size(); i > 0; --i) {
figure = (wi->figures)[i - 1];
if (figure->flags & ImageToRenderFlags::Visible) {
SelectObject(compatible, figure->bitmap/*Bitmap for the Item*/);
TransparentBlt(hdc,figure->xPos,figure->yPos/*Position of the figure in the client area*/,
figure->width/*width of the figure in the client area*/,
figure->height/*height of the figure in the client area*/,
compatible, 0, 0,
figure->bmpWidth/*Width of the original bitmap*/,
figure->bmpHeight/*Height of the original Bitmap*/,
RGB(0xFF,0xFF,0xFF));
}
}
DeleteDC(compatible);
wi->lock.unlock();
EndPaint(hwnd, &ps); }
return 0;
[...]
我的想法是将上面算法的结果绘制到800x400格式的Compatible Device Context中,然后使用StretchBlt
将其拉伸到真实的窗口中,同时保持比例为2:1。为此,我编写了以下算法:
LRESULT CALLBACK WindowCallbackF(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
WindowInterface* wi;
wi = getInterface(hwnd);
switch (uMsg)
{
case WM_PAINT: {
PAINTSTRUCT ps;
ImageToRender* figure;
if (!hwnd) {
return 0;
}
HDC hdc = BeginPaint(hwnd, &ps);
HDC drawDC = CreateCompatibleDC(hdc);
HDC compatible = CreateCompatibleDC(hdc);
if ((wi->flags) && WindowFlags::BackgroundSet) {
SelectObject(compatible, wi->backgroundImage/*HBITMAP for the Background Image*/);
BitBlt(drawDC, 0, 0, wi->initWidth/*800*/, wi->initHeight/*400*/, compatible, 0, 0, SRCCOPY);
}
wi->lock.lock();
/*wi->lock is a std::unique_lock<std::mutex>, and wi->figures is a std::vector<ImageToRender*>*/
for (size_t i = (wi->figures).size(); i > 0; --i) {
figure = (wi->figures)[i - 1];
if (figure->flags & ImageToRenderFlags::Visible) {
SelectObject(compatible, figure->bitmap/*Bitmap for the Item*/);
TransparentBlt(drawDC,figure->xPos,figure->yPos/*Position of the figure in the client area*/,
figure->width/*width of the figure in the client area*/,
figure->height/*height of the figure in the client area*/,
compatible, 0, 0,
figure->bmpWidth/*Width of the original bitmap*/,
figure->bmpHeight/*Height of the original Bitmap*/,
SRCCOPY);
}
}
DeleteDC(compatible);
int height = wi->height;
int width = wi->width;
int xPos = 0;
int yPos = 0;
if (wi->flags & WindowFlags::Y_DIM_OVERRIDE) {
height = wi->dimensionOverride;
yPos = wi->dimensionOffset;
}
else if (wi->flags & WindowFlags::X_DIM_OVERRIDE) {
width = wi->dimensionOverride;
xPos = wi->dimensionOffset;
}
RECT fillRect;
fillRect.top = 0;
fillRect.left = 0;
fillRect.right = wi->width + 1;
fillRect.bottom = wi->height + 1;
FillRect(hdc, &fillRect, reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)));
//FillRect Sets the background to black. Due to the 2:1-Ratio being maintained, not everything is painted; The unpainted parts should have a black background. This call succeeds.
StretchBlt(hdc, 0, 0, width/*destination width*/, height/*destination height*/, drawDC, 0, 0, wi->initWidth/*800*/, wi->initHeight/*400*/, RGB(0xFF,0xFF,0xFF));
DeleteDC(drawDC);
wi->lock.unlock();
EndPaint(hwnd, &ps); }
return 0;
case WM_SIZE:
{
RECT clientRects;
GetClientRect(hwnd, &clientRects);
//Dimensions of the Window are updated here
(*wi).width = clientRects.right - clientRects.left;
(*wi).height = clientRects.bottom - clientRects.top;
if (wi->width > (wi->height * 2)) {
//Left+Right are filled with black background
(*wi).flags &= ~WindowFlags::Y_DIM_OVERRIDE;
(*wi).flags |= WindowFlags::X_DIM_OVERRIDE;
(*wi).dimensionOverride = wi->height * 2;
(*wi).dimensionOffset = (wi->width - wi->dimensionOverride) / 2;
}
else if (wi->width==wi->height*2) {
//No black background when width==height*2
(*wi).flags &= ~(WindowFlags::Y_DIM_OVERRIDE|WindowFlags::X_DIM_OVERRIDE);
}
else {
//Top+Bottom are filled with black background
(*wi).flags &= ~WindowFlags::X_DIM_OVERRIDE;
(*wi).flags |= WindowFlags::Y_DIM_OVERRIDE;
(*wi).dimensionOverride = wi->width / 2;
(*wi).dimensionOffset = (wi->height - wi->dimensionOverride) / 2;
}
std::thread thread{RedrawWindow, hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN};//Starting RedrawWindow in a new Thread prevents deadlocks where the window message thread waits for RedrawWindow, and RedrawWindow waits for the window message thread to process WM_PAINT
thread.detach();
};
return 0;
[...]
这里的问题是,即使直接在BeginPaint
返回的HDC上使用paint操作也可以工作,但当以这种方式使用时,会出现错误,窗口只是黑色的。这意味着,FillRect
成功,但StretchBlt
似乎默默地失败了(它返回1,但没有应用更改)。我已经不知道该怎么办了,在网上什么也没找到,问ChatGPT也没用。
1条答案
按热度按时间mitkmikd1#
CreateCompatibleDC
创建的位图为1x11位。你需要为它创建更有趣的位图。