Геометрия динамической прозрачности в MFC

#c #windows #winapi #mfc

#c #Windows #winapi #mfc

Вопрос:

Я создаю пошаговое руководство с новым пользовательским интерфейсом для своего приложения MFC и хочу выделить определенные элементы управления по мере прохождения пошагового руководства. В частности, я хочу затемнить все окно, кроме элемента управления, который я подчеркиваю.

Я попытался создать частично прозрачное черное наложение с помощью SetLayeredWindowAttributes , но это не позволяет мне сделать подобласть полностью прозрачной. UpdateLayeredWindow могу это сделать, но я не горю желанием создавать файл BMP / PNG для каждого элемента управления, который мне нужно выделить.

Могу ли я создать геометрию прозрачности динамически? Например, могу ли я нарисовать растровую прозрачность с нуля, а затем загрузить ее в UpdateLayeredWindow ?

Мне также необходимо быть совместимым с Windows 7 (несмотря на ее поддержку EOL).

Продолжение: Пытаюсь нарисовать прозрачные области GDI , но не работает:

 
    void ApplicationDlg::Highlight(const CRectamp; rect)
    {
        CRect wndRect;
        GetWindowRect(amp;wndRect);
        Gdiplus::Rect wndRectPlus(wndRect.left, wndRect.top, wndRect.Width(), wndRect.Height());
        Gdiplus::Region wndRegion(wndRectPlus);
    
        Gdiplus::Rect controlRectPlus(rect.left, rect.top, rect.Width(), rect.Height());
        Gdiplus::Region highlightRegion(controlRectPlus);
    
        wndRegion.Exclude(amp;highlightRegion);
    
        Gdiplus::SolidBrush transparentBrush(Gdiplus::Color(0, 0, 0, 0));
        Gdiplus::SolidBrush darkenBrush(Gdiplus::Color(128, 0, 0, 0));
    
        CDC* pDCScreen = m_WalkthroughDlg.GetDC();
        HDC hDC = CreateCompatibleDC(pDCScreen->m_hDC);
        HBITMAP hBmp = CreateCompatibleBitmap(hDC, wndRect.Width(), wndRect.Height());
        HBITMAP hBmpOld = (HBITMAP)SelectObject(hDC, hBmp);
    
        Gdiplus::Graphics graphics(hDC);
        graphics.FillRegion(amp;darkenBrush, amp;wndRegion);
        graphics.FillRegion(amp;transparentBrush, amp;highlightRegion);
    
        BLENDFUNCTION blend = {0};
        blend.BlendOp = AC_SRC_OVER;
        blend.SourceConstantAlpha = 255;
        blend.AlphaFormat = AC_SRC_ALPHA;
        SIZE sizeWnd = {wndRect.Width(), wndRect.Height()};
        POINT ptSrc = {0,0};
        m_WalkthroughDlg.UpdateLayeredWindow(pDCScreen, NULL, amp;sizeWnd, CDC::FromHandle(hDC), amp;ptSrc, NULL, amp;blend, ULW_ALPHA); // TODO cleanup FromHandle refs
        m_WalkthroughDlg.BringWindowToTop();
    
        SelectObject(hDC, hBmpOld);
        DeleteObject(hBmp);
        DeleteDC(hDC);
    }

  

Ответ №1:

Вы можете динамически создавать маску с помощью CRgn класса: https://learn.microsoft.com/en-us/cpp/mfc/reference/crgn-class?view=vs-2019

Это позволяет объединять области (если вам нужно выделить более одной области). Затем вы могли бы использовать FillRgn функцию для обновления hdcSrc постоянного тока, используемого в UpdateLayeredWindow .

В качестве альтернативы, если ваши основные моменты прямоугольные, вы могли бы просто нарисовать прямоугольники на этом hdcSrc .

Комментарии:

1. Пытаюсь использовать Region класс GDI , так как GDI CRgn не хватает прозрачности. Но, должно быть, что-то не так, окно наложения не отображается.

2. Благодарен, если вы могли бы взглянуть на код, которым я обновил свой вопрос.

3. Что вы видите в этом последнем коде? Я не знаком с GDI , но мог бы взглянуть, если вы каким-то образом прикрепите свой проект сюда.

4. Окно полностью прозрачно на 100%, несмотря на проверку того, что прямоугольник управления значительно меньше прямоугольника окна. К сожалению, я не могу поделиться проектом.

5. У меня действительно нет времени создавать фиктивный проект скелета, чтобы играть с этим. Однако вы можете вернуться к своему первоначальному решению, но вместо одного темного наложения создайте четыре, чтобы окружить выделенный элемент управления: один сверху, один снизу и по два с каждой стороны.