jjzjj

c++ - 将 HBITMAP 绘制到分层窗口上。怎么了?

coder 2023-11-12 原文

大家好,美好的一天,

我的最终目标是将包含 alpha 的 PNG 文件绘制到屏幕上 - 这意味着不是绘制到自己的窗口中,而是绘制到桌面上的某个位置。 将 PNG 加载到 HBITMAP 的部分现在可以工作(以不同的方式测试)但我无法绘制它包括 alpha。

据我所知,执行此操作的最佳方法是使用分层窗口。所以我做了很多工作来重做几个示例和小教程。

下面的代码编译没有问题并且没有提示任何消息(这意味着 showError("#") 函数从未被调用)。

但屏幕上什么都看不到:/

抱歉,它太长了...希望有人愿意至少快速查看它..

LRESULT CALLBACK WndProc(HWND hWindow, UINT msg, WPARAM wParam, LPARAM lParam);


int main(HINSTANCE hInstance)
{


    WNDCLASSEX WndClass;
    char sClassName[]  = "mainClass";
    WndClass.cbSize     = sizeof(WNDCLASSEX);
    WndClass.style      = NULL;
    WndClass.lpfnWndProc   = WndProc;//WndProc;
    WndClass.cbClsExtra = 0;
    WndClass.cbWndExtra = 0;
    WndClass.hInstance  = hInstance;
    WndClass.hIcon      = NULL;
    WndClass.hCursor    = LoadCursor(NULL, IDC_ARROW);
    WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    WndClass.lpszMenuName  = NULL;
    WndClass.lpszClassName = sClassName;
    WndClass.hIconSm    = LoadIcon(NULL, IDI_APPLICATION);
    if (RegisterClassEx(&WndClass) == 0) showError("-1");





    HWND screen = CreateWindowEx(WS_EX_LAYERED,//WS_EX_LEFT
        "mainClass",
        "UpdateLayeredWind",
        WS_DISABLED | WS_VISIBLE,
        200,200,260,260,
        NULL /*eventuelly, GM window*/,
        NULL,
        hInstance,
        NULL);  


    if (screen == NULL) showError("0");




        HBITMAP img = LoadImageResource("D://ThreadDraw/ThreadDraw-test/ThreadDraw/test.png");
            if (img == NULL) showError("1");






    BLENDFUNCTION blend = {0};

    blend.AlphaFormat = AC_SRC_ALPHA;
    blend.SourceConstantAlpha = 155;

    POINT ptPos = {200,300};
    SIZE sizeWnd = {260,260};
    POINT ptPos2 = {200,300};


    ShowWindow(screen, SW_SHOW);



    while (1)
    {


        PAINTSTRUCT             ps;
        HDC                     hdc;
        BITMAP                  bitmap;
        HDC                     hdcMem;
        HGDIOBJ                 oldBitmap;

        hdc = BeginPaint(screen, &ps);

        hdcMem = CreateCompatibleDC(hdc);
        oldBitmap = SelectObject(hdcMem, img);

        GetObject(img, sizeof(bitmap), &bitmap);


        if (SetLayout(hdc,LAYOUT_RTL) == GDI_ERROR)
            showError("5");



            if (!BitBlt(hdc, 0, 0, 64, 64, hdcMem, 0, 0, SRCCOPY))
                showError("4");



            if (!UpdateLayeredWindow(screen,hdcMem,&ptPos,&sizeWnd,hdc,&ptPos2,RGB(255,255,255),&blend,ULW_ALPHA))//ULW_OPAQUE))
            showError("2");



        EndPaint(screen, &ps);

        SelectObject(hdcMem, oldBitmap);
        DeleteDC(hdcMem);


        Sleep(10);

    }



    return 0;
}



LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) 
{
    switch(Message) 
    {
        case WM_CLOSE:
            DestroyWindow(hwnd);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hwnd, Message, wParam, lParam);
    }
    return 0;
}

顺便说一下,如果我在 UpdateLayeredWindow 中使用 ULW_OPAQUE 而不是 ULW_ALPHA,则会出现一个大小合适的黑色窗口,因此认为问题必须与 PAINTSTRUKT 或 BitBlt 函数相关。但我尝试了很多方法没有任何变化。

希望有人能帮忙。非常感谢您!

最佳答案

这主要是错误的。您的代码应该:

  • 使用 CreateWindowEx 创建分层窗口。
  • 使用 UpdateLayeredWindow 将位图附加到它。
  • 使用 ShowWindow 显示窗口。 Windows 将负责绘制分层窗口,因此您无需处理 WM_PAINT 或调用 BeginPaint
  • 进入消息循环。

就是这样。

如果您使用的是 Visual Studio,请创建一个新的 Win32 项目,它会为您创建一个带有消息循环的新项目。

更新

这是一个创建透明分层窗口的示例程序。它需要一个函数来加载 PNG 作为透明位图。而且它没有错误检查。

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
    LPCTSTR szWindowClass = _T("TransparentClass");

    // Register class
    WNDCLASSEX wcex = {0};

    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.lpfnWndProc    = DefWindowProc;
    wcex.hInstance      = hInstance;
    wcex.lpszClassName  = szWindowClass;

    RegisterClassEx(&wcex);

    HWND hWnd = CreateWindowEx(WS_EX_LAYERED, szWindowClass, 0, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

    int width;
    int height;
    HBITMAP hbmp = LoadPng(L"sample.png", &width, &height);

    HDC hdcScreen = GetDC(0);
    HDC hdc = CreateCompatibleDC(hdcScreen);
    ReleaseDC(0, hdcScreen);
    HBITMAP hbmpold = (HBITMAP)SelectObject(hdc, hbmp);

    POINT dcOffset = {0, 0};
    SIZE size = {width, height};
    BLENDFUNCTION bf;
    bf.BlendOp = AC_SRC_OVER;
    bf.BlendFlags = 0;
    bf.SourceConstantAlpha = 255;
    bf.AlphaFormat = AC_SRC_ALPHA;
    UpdateLayeredWindow(hWnd, 0, 0, &size, hdc, &dcOffset, 0, &bf, ULW_ALPHA);
    SelectObject(hdc, hbmpold);
    DeleteDC(hdc);
    DeleteObject(hbmp);

    ShowWindow(hWnd, SW_SHOW);

    MSG msg;

    // Main message loop:
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int)msg.wParam;
}

另一个更新

下面是一些代码,用于将红色、绿色和蓝色值预乘 alpha。它假定 splash_image 指向大小为 width*height 的 32bpp ARGB 数据。

LPBYTE bits = (LPBYTE)splash_image;
int size = width * height;
for (int pixel = 0; pixel != size; ++pixel)
{
    bits[0] = bits[0] * bits[3] / 255;
    bits[1] = bits[1] * bits[3] / 255;
    bits[2] = bits[2] * bits[3] / 255;
    bits += 4;
}

关于c++ - 将 HBITMAP 绘制到分层窗口上。怎么了?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12626729/

有关c++ - 将 HBITMAP 绘制到分层窗口上。怎么了?的更多相关文章

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

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

  2. ruby - Ruby 中的隐式返回值是怎么回事? - 2

    所以我开始关注ruby​​,很多东西看起来不错,但我对隐式return语句很反感。我理解默认情况下让所有内容返回self或nil但不是语句的最后一个值。对我来说,它看起来非常脆弱(尤其是)如果你正在使用一个不打算返回某些东西的方法(尤其是一个改变状态/破坏性方法的函数!),其他人可能最终依赖于一个返回对方法的目的并不重要,并且有很大的改变机会。隐式返回有什么意义?有没有办法让事情变得更简单?总是有返回以防止隐含返回被认为是好的做法吗?我是不是太担心这个了?附言当人们想要从方法中返回特定的东西时,他们是否经常使用隐式返回,这不是让你组中的其他人更容易破坏彼此的代码吗?当然,记录一切并给出

  3. ruby - 怎么来的(a_method || :other) returns :other only when assigning to a var called a_method? - 2

    给定以下方法:defsome_method:valueend以下语句按我的预期工作:some_method||:other#=>:valuex=some_method||:other#=>:value但是下面语句的行为让我感到困惑:some_method=some_method||:other#=>:other它按预期创建了一个名为some_method的局部变量,随后对some_method的调用返回该局部变量的值。但为什么它分配:other而不是:value呢?我知道这可能不是一件明智的事情,并且可以看出它可能有多么模棱两可,但我认为应该在考虑作业之前评估作业的右侧...我已经在R

  4. ruby-on-rails - 我该怎么办 :remote location validation with CarrierWave? - 2

    我在我的Rails3示例应用程序上使用CarrierWave。我想验证远程位置上传,因此当用户提交无效URL(空白或非图像)时,我不会收到标准错误异常:CarrierWave::DownloadErrorinImageController#createtryingtodownloadafilewhichisnotservedoverHTTP这是我的模型:classPaintingtrue,:length=>{:minimum=>5,:maximum=>100}validates:image,:presence=>trueend这是我的Controller:classPaintingsC

  5. 电脑0x0000001A蓝屏错误怎么U盘重装系统教学 - 2

      电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug,只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢?来看看以下的详细操作方法教学吧。  准备工作:  1、U盘一个(尽量使用8G以上的U盘)。  2、一台正常联网可使用的电脑。  3、ghost或ISO系统镜像文件(Win10系统下载_Win10专业版_windows10正式版下载-系统之家)。  4、在本页面下载U盘启动盘制作工具:系统之家U盘启动工具。  U盘启动盘制作步骤:  注意:制作期间,U盘会被格式化,因此U盘中的重要文件请注

  6. 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.你能做的最好的事情是:

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

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

  8. ruby - (Ruby || Python) 窗口管理器 - 2

    我想用这两种语言中的任何一种(最好是ruby​​)制作一个窗口管理器。老实说,除了我需要加载某种X模块外,我不知道从哪里开始。因此,如果有人有线索,如果您能指出正确的方向,那就太好了。谢谢 最佳答案 XCB,X的下一代API使用XML格式定义X协议(protocol),并使用脚本生成特定语言绑定(bind)。它在概念上与SWIG类似,只是它描述的不是CAPI,而是X协议(protocol)。目前,C和Python存在绑定(bind)。理论上,Ruby端口只是编写一个从XML协议(protocol)定义语言到Ruby的翻译器的问题。生

  9. ruby - EventMachine - 你怎么知道你是否落后了? - 2

    我正在研究使用EventMachine支持的twitter-streamruby​​gem来跟踪和捕获推文。我对整个事件编程有点陌生。我如何判断我在事件循环中所做的任何处理是否导致我落后?有没有简单的检查方法? 最佳答案 您可以通过使用周期性计时器并打印出耗时来确定延迟。如果您使用的是1秒的计时器,您应该已经过了大约1秒,如果它更长,您就知道您正在减慢react器的速度。@last=Time.now.to_fEM.add_periodic_timer(1)doputs"LATENCY:#{Time.now.to_f-@last}"@

  10. ruby - 如果它是标点符号,我怎么能从字符串中删除最后一个字符,在 ruby​​ 中? - 2

    啊,正则表达式有点困惑。我正在尝试删除字符串末尾所有可能的标点符号:ifstr[str.length-1]=='?'||str[str.length-1]=='.'||str[str.length-1]=='!'orstr[str.length-1]==','||str[str.length-1]==';'str.chomp!end我相信有更好的方法来做到这一点。有什么指点吗? 最佳答案 str.sub!(/[?.!,;]?$/,'')[?.!,;]-字符类。匹配这5个字符中的任何一个(注意,。在字符类中并不特殊)?-前一个字符或组

随机推荐