Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/139.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 全屏幕手绘_C++_Winapi_Bitmap_Gdi - Fatal编程技术网

C++ 全屏幕手绘

C++ 全屏幕手绘,c++,winapi,bitmap,gdi,C++,Winapi,Bitmap,Gdi,我正在尝试制作一个简单的小工具,允许用户从正常操作切换到一种模式,在这种模式下,所有应用程序消息都被禁用,他们可以使用鼠标进行一些徒手绘制,然后再次切换模式,以便在他们做任何其他他们想要的正常工作时,将其绘制保持在屏幕上。如果我决定的话,这可能会演变成一个很好的东西,你可以通过保存你所做的装饰并在以后加载它们来使用装饰过的屏幕 当我开始这项工作时(半年多以前,在发现Windows API后不久),我只做了全局鼠标跟踪,并在GetDC(NULL)hdc的任何位置画了一个圆圈。当然,问题是,当它下面

我正在尝试制作一个简单的小工具,允许用户从正常操作切换到一种模式,在这种模式下,所有应用程序消息都被禁用,他们可以使用鼠标进行一些徒手绘制,然后再次切换模式,以便在他们做任何其他他们想要的正常工作时,将其绘制保持在屏幕上。如果我决定的话,这可能会演变成一个很好的东西,你可以通过保存你所做的装饰并在以后加载它们来使用装饰过的屏幕

当我开始这项工作时(半年多以前,在发现Windows API后不久),我只做了全局鼠标跟踪,并在GetDC(NULL)hdc的任何位置画了一个圆圈。当然,问题是,当它下面的任何东西更新时,它会消失,并且仍然会有鼠标消息被输入,因此,如果我按住桌面上的按钮,例如,它会在整个绘画中放置调整大小的矩形

今天,自从6个月前的最后一次主要工作以来,我终于有了一些空闲时间,我决定重新制作它,看看是否能达到我想要的。我制作了一个透明的、最顶层的、WS_-CHILD的、分层的、最大化的窗口(基本上屏幕不会改变,但在所有东西的顶部都有一个窗口,可以让消息通过)。接下来,我将其设置为,当它处于绘制模式时,它会将alpha值设置为1,并让用户绘制。直到我做了这件事,我才意识到,因为窗口的alpha值是1,所以没有一幅画是可见的

接下来,我尝试使用GetDC(NULL),但我记得当某些内容更新时,它会被删除

现在我只想使用位图和dc将屏幕反复存储到一个dc中,在另一个dc上绘制,然后将其复制回具有存储的屏幕的dc中,并对未绘制的部分进行透明,然后将其复制回屏幕,但我失去了一点信心。下面是我的源代码(mask函数取自)。请告诉我这些是否是不必要的。我使用位图进行双缓冲当然,但我不太确定在哪里需要它们

//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;
}
我知道代码可能非常可怕。我把所有的建议都考虑进去了,只是我对这个问题不太清楚,没有了解正在发生的一切,这使得它很难修复。这段代码为我运行,几乎每隔一段时间就放一个全屏黑色矩形

我的主要问题是:当windows更新时,有没有办法在屏幕上画画而不被擦除?我现在能想到的唯一真实的事情是存储用户绘制的微小线段的所有位置,并在屏幕顶部不断地重新绘制它们。乍一看,它似乎效率很低,而且浪费内存

另外,在编写本文时,我非常确定,在提供代码段之前,我不需要任何理论上的代码示例。现在大部分都消失了,但这实际上更多的是一个理论问题

编辑:
我刚刚发现TransparentBlt函数似乎非常适合这种情况,所以我尝试使用它来代替SRCPAINT和src和bitblt,它产生了相同的结果:一个黑色矩形覆盖屏幕,有时,当我的鼠标移动到物体上时,某些部分会消失。

我认为最好先创建屏幕快照并将其保存在位图中(以内存DC的形式),然后再显示全屏显示内存DC内容的窗口。这样,您就可以在自己的窗口上获取由单击等引起的消息,并像往常一样处理它们

  • 捕获屏幕内容
  • 创建窗口(全屏)并使用捕获的内容
  • 画画
  • 保存内容(以bmp或其他格式)
  • 关闭窗口并返回常规桌面
  • 好主意?

    最简单的方法,也许是:

    在非绘图模式下,用于为透明窗口设置“透明键”颜色。使窗口的alpha完全不透明,但使用该关键点颜色填充窗口(FillRect或类似),窗口将全部显示为透明。然后,以非关键点颜色绘制的任何内容都将显示为实体,位于透明分层窗口下方的所有窗口顶部


    要进入绘图模式,一种方法是创建一个新窗口,在透明层的正下方创建一个桌面位图。或者避免使用位图,使其稍微不透明,并且全部为纯色-例如,使桌面看起来像是“灰色的”。关键是这个窗口不是完全透明的,所以它能够接收鼠标输入,然后你可以使用鼠标输入在实际的透明层上绘制。

    我看到的一个问题是(除非我想错了),在他们切换回可以做其他事情的地方后,我无法保留他们绘制的内容(即,这与透明度为1的分层窗口具有相同的效果,但在我绘制时,它下面的内容会实时更新。如果这不是你的意思,请更正我。当我回顾位图时,我希望保存/加载的是paintBM-带有用户图形的窗口。然后可以将其置于“顶部”其中一个是屏幕图像,然后可以应用回屏幕。将图形保存为捕获屏幕顶部的一个层是没有问题的。但是如果我理解正确,您希望在屏幕上绘图时更新屏幕?有点,主要的是能够在模式切换后使绘图保持不变(如果有人想知道,这是通过我的窗口处理的热键完成的)。我能想到的最终解决方案似乎是不可能的,不过是在顶部有一个背景透明的窗口,但之后不要再加任何东西。这会导致窗口停留在那里,可见的油漆粘在上面,而任何未上漆的部分都是看不见的。如果可能的话,我会非常高兴,但我没有