我正在尝试制作一个简单的工具,使用户可以从正常操作模式切换到禁用所有应用程序消息并使用鼠标进行一些自由绘图的模式,然后再次切换模式以保留他们的绘图在屏幕上,同时进行其他正常操作。如果我决定,这可能会演变成一个不错的工具,您可以使用它来保存您所做的装饰并稍后加载它们。
我知道代码可能很糟糕。我会考虑所有建议,只是我对这个主题不太清楚,不明白发生了什么,这使得修复变得困难。这段代码在我的电脑上运行,基本上每隔一段时间就会放置一个全屏黑色矩形。
我的主要问题是:有没有办法在屏幕上绘制而不会在底层窗口更新时被擦除?我现在唯一能想到的真正方法就是存储用户绘制的所有小线段的位置,并在屏幕顶部不断重绘它们。乍一看,这似乎非常低效和浪费内存。
另外,在写这篇文章时,我确信我不需要提供任何理论代码示例。大部分已经消失了,但这确实是一个理论问题。
编辑: 我刚刚发现了TransparentBlt函数,它似乎非常适合这种情况,所以我尝试使用它来替换SRCPAINT和SRCAND BitBlts,结果产生了相同的结果:一个黑色矩形覆盖了屏幕,有时当我的鼠标移动到其他地方时会消失一部分。
当我开始这个项目(大约半年前,发现Windows API后不久)时,我只是全局跟踪鼠标,并将其画成GetDC(NULL)hdc中的圆形。当然,问题在于当其下方更新时,它会消失,并且仍会通过鼠标消息,因此,例如,如果我按住桌面上的按钮,它会在绘画中放置调整大小的矩形。
今天,自从6个月前进行了最后一次主要工作后,我终于有了一些空闲时间,决定重新制作并看看能否实现我想要的效果。我制作了一个透明、最上层、WS_CHILD、分层、最大化的窗口(基本上屏幕不会改变,但是有一个窗口在所有东西的顶部让消息通过)。接下来,我使它在绘画模式下,将alpha值设置为1,并允许用户绘画。我没有意识到的问题是,由于窗口的alpha值为1,所以绘画中的任何内容都不可见。接下来,我尝试使用GetDC(NULL),但记得当某些东西更新时,它会被擦除。
现在我想使用位图和DC来重复地将屏幕存储到一个DC中,在另一个DC上绘制,然后带有未绘制部分的透明度将其复制回已存储屏幕的那个DC中,并将其复制回屏幕。但我感到有些泄气了。这是我的源代码(遮罩函数取自此教程)。如果有不必要的部分,请告诉我。我已经使用位图进行了双缓冲,但我不确定何时需要使用它们。
//Global mask since it takes longer to make
HBITMAP mask;
//Window Procedure Start
HDC screenDC; //hdc for entire screen
screenDC = GetDC (NULL); //get DC for screen
HDC memDC = CreateCompatibleDC (screenDC); //create DC for holding the screen+paint
HBITMAP bm = CreateCompatibleBitmap (screenDC, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN)); //create bitmap for memDC
HDC paintDC = CreateCompatibleDC (screenDC); //create DC to paint on
HBITMAP paintBM = CreateCompatibleBitmap (screenDC, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN)); //create bitmap for paintDC
SelectObject (memDC, bm); //select bitmap into memDC
SelectObject (paintDC, paintBM); //select painting bitmap into paintDC
BitBlt (memDC, 0, 0, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN), screenDC, 0, 0, SRCCOPY); //copy screen to memDC
SetBkColor (paintDC, RGB(0,0,0)); //set background of paintDC to black so it's all transparent to start
//WM_CREATE
mask = CreateBitmapMask (bm, RGB(0,0,0)); //create black mask (paint colours are limited 1-255 now)
//painting is done into paintDC
//at end of Window Procedure
SelectObject (paintDC, mask); //select mask into paintDC
BitBlt (memDC, 0, 0, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN), paintDC, 0, 0, SRCAND); //this in combination with the next should make it bitblt with all of the black taken out I thought
SelectObject (paintDC, paintBM); //select bitmaps into DCs
SelectObject (memDC, bm);
BitBlt (memDC, 0, 0, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN), paintDC, 0, 0, SRCPAINT); //second part of transparent bitblt
BitBlt (screenDC, 0, 0, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN), paintDC, 0, 0, SRCCOPY); //copy memDC back to screen
DeleteObject (paintBM); //delete stuff
DeleteObject (mask);
DeleteDC (memDC);
DeleteDC (paintDC);
ReleaseDC (hwnd, screenDC);
//CreateBitmapMask() (taken directly from http://www.winprog.org/tutorial/transparency.html
HBITMAP CreateBitmapMask(HBITMAP hbmColour, COLORREF crTransparent)
{
HDC hdcMem, hdcMem2;
HBITMAP hbmMask;
BITMAP bm;
// Create monochrome (1 bit) mask bitmap.
GetObject(hbmColour, sizeof(BITMAP), &bm);
hbmMask = CreateBitmap(bm.bmWidth, bm.bmHeight, 1, 1, NULL);
// Get some HDCs that are compatible with the display driver
hdcMem = CreateCompatibleDC(0);
hdcMem2 = CreateCompatibleDC(0);
SelectObject(hdcMem, hbmColour);
SelectObject(hdcMem2, hbmMask);
// Set the background colour of the colour image to the colour
// you want to be transparent.
SetBkColor(hdcMem, crTransparent);
// Copy the bits from the colour image to the B+W mask... everything
// with the background colour ends up white while everythig else ends up
// black...Just what we wanted.
BitBlt(hdcMem2, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
// Take our new mask and use it to turn the transparent colour in our
// original colour image to black so the transparency effect will
// work right.
BitBlt(hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem2, 0, 0, SRCINVERT);
// Clean up.
DeleteDC(hdcMem);
DeleteDC(hdcMem2);
return hbmMask;
}
我知道代码可能很糟糕。我会考虑所有建议,只是我对这个主题不太清楚,不明白发生了什么,这使得修复变得困难。这段代码在我的电脑上运行,基本上每隔一段时间就会放置一个全屏黑色矩形。
我的主要问题是:有没有办法在屏幕上绘制而不会在底层窗口更新时被擦除?我现在唯一能想到的真正方法就是存储用户绘制的所有小线段的位置,并在屏幕顶部不断重绘它们。乍一看,这似乎非常低效和浪费内存。
另外,在写这篇文章时,我确信我不需要提供任何理论代码示例。大部分已经消失了,但这确实是一个理论问题。
编辑: 我刚刚发现了TransparentBlt函数,它似乎非常适合这种情况,所以我尝试使用它来替换SRCPAINT和SRCAND BitBlts,结果产生了相同的结果:一个黑色矩形覆盖了屏幕,有时当我的鼠标移动到其他地方时会消失一部分。