草庐IT

c++ - 全屏写意

coder 2024-02-23 原文

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

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

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

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

现在只想着用位图和dcs把画面反复存入一个dc,在另一个dc上画画,然后再复制回存画面的那个,没有画的部分是透明的,并将其复制回屏幕,但我失去了一点心。这是我的源代码(掩码函数取自 this tutorial )。请告诉我,如果其中一些是不必要的。我确实使用位图进行双缓冲,但我不确定我需要它们的位置。

//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,它产生了相同的结果:一个黑色矩形覆盖屏幕,有时当我的鼠标移过时部分消失东西。

最佳答案

也许是最简单的方法:

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

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

关于c++ - 全屏写意,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7604962/

有关c++ - 全屏写意的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  3. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  4. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  5. += 的 Ruby 方法 - 2

    有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=

  6. ruby - Sinatra + Heroku + Datamapper 使用 dm-sqlite-adapter 部署问题 - 2

    出于某种原因,heroku尝试要求dm-sqlite-adapter,即使它应该在这里使用Postgres。请注意,这发生在我打开任何URL时-而不是在gitpush本身期间。我构建了一个默认的Facebook应用程序。gem文件:source:gemcuttergem"foreman"gem"sinatra"gem"mogli"gem"json"gem"httparty"gem"thin"gem"data_mapper"gem"heroku"group:productiondogem"pg"gem"dm-postgres-adapter"endgroup:development,:t

  7. ruby - Ruby 中字符串运算符 + 和 << 的区别 - 2

    我是Ruby和这个网站的新手。下面两个函数是不同的,一个在函数外修改变量,一个不修改。defm1(x)x我想确保我理解正确-当调用m1时,对str的引用被复制并传递给将其视为x的函数。运算符当调用m2时,对str的引用被复制并传递给将其视为x的函数。运算符+创建一个新字符串,赋值x=x+"4"只是将x重定向到新字符串,而原始str变量保持不变。对吧?谢谢 最佳答案 String#+::str+other_str→new_strConcatenation—ReturnsanewStringcontainingother_strconc

  8. ruby - rails 3.2.2(或 3.2.1)+ Postgresql 9.1.3 + Ubuntu 11.10 连接错误 - 2

    我正在使用PostgreSQL9.1.3(x86_64-pc-linux-gnu上的PostgreSQL9.1.3,由gcc-4.6.real(Ubuntu/Linaro4.6.1-9ubuntu3)4.6.1,64位编译)和在ubuntu11.10上运行3.2.2或3.2.1。现在,我可以使用以下命令连接PostgreSQLsupostgres输入密码我可以看到postgres=#我将以下详细信息放在我的config/database.yml中并执行“railsdb”,它工作正常。开发:adapter:postgresqlencoding:utf8reconnect:falsedat

  9. ruby - 在 Ruby + Chef 中检查现有目录失败 - 2

    这是我在ChefRecipe中的一blockRuby:#ifdatadirdoesn'texist,moveoverthedefaultoneif!File.exist?("/vol/postgres/data")execute"mv/var/lib/postgresql/9.1/main/vol/postgres/data"end结果是:Executingmv/var/lib/postgresql/9.1/main/vol/postgres/datamv:inter-devicemovefailed:`/var/lib/postgresql/9.1/main'to`/vol/post

  10. ruby-on-rails - 使用 Pow 作为服务器在 RubyMine 中调试 - Ruby 2.1.1 + Rails 4 - 2

    我已经开始使用RubyMine6。我正在处理Rails4、Ruby2.1.1项目。我无法找到如何使用Pow作为服务器调试到RubyMine。你能给我指明正确的方向吗? 最佳答案 我能够使用远程调试从RubyMine进行调试。我正在使用RubyMine6、Rails3、Ruby2.1.1。首先创建一个.powenv文件并添加:exportRUBY_DEBUG_PORT=1234exportPOW_WORKERS=1将以下gem添加到您的Gemfile:gem'ruby-debug-ide'gem'debase'创建一个新的初始化器st

随机推荐