Как перерисовать только область многослойного окна?

У меня есть многослойное окно, которое обычно рисуется следующим образом:

    private void SelectBitmap(Bitmap bitmap)
    {
        IntPtr screenDc = GetDC(IntPtr.Zero);
        IntPtr memDc = CreateCompatibleDC(screenDc);
        IntPtr hBitmap = IntPtr.Zero;
        IntPtr hOldBitmap = IntPtr.Zero;

        try
        {
            hBitmap = bitmap.GetHbitmap(Color.FromArgb(0));
            hOldBitmap = SelectObject(memDc, hBitmap);

            POINT sourceLocation = new POINT(0, 0);
            BLENDFUNCTION blend = new BLENDFUNCTION();

            blend.BlendOp = AC_SRC_OVER;
            blend.BlendFlags = 0;
            blend.SourceConstantAlpha = 255;
            blend.AlphaFormat = AC_SRC_ALPHA;

            SIZE newSize = new SIZE(bitmap.Width, bitmap.Height);
            POINT newLocation = new POINT(Location.X, Location.Y);

            UpdateLayeredWindow(Handle, screenDc,
                ref newLocation, ref newSize,
                memDc,
                ref sourceLocation, 0,
                ref blend,
                ULW_ALPHA);
        }
        finally
        {
            ReleaseDC(IntPtr.Zero, screenDc);

            if (hBitmap != IntPtr.Zero)
            {
                SelectObject(memDc, hOldBitmap);
                DeleteObject(hBitmap);
            }

            DeleteDC(memDc);
        }
    }

Однако это, очевидно, перерисовывает все окно каждый раз, когда оно вызывается. Это большое снижение производительности на большом окне. (даже на моем лучшем ПК, что заставляет меня задуматься, как люди справляются с этим в Win2K)

Если я читаю статью Microsoft в многослойном окне, она говорит: UpdateLayeredWindow всегда обновляет все окно. Чтобы обновить часть окна, используйте традиционный WM_PAINT и установите значение смешивания, используя SetLayeredWindowAttributes.

Я просто не могу понять вышесказанное. Как WM_PAINT должен получить доступ к многоуровневому оконному растровому изображению и перерисовать только его часть в окне? Из того, что я понял, многослойные окна просто отключают сообщение WM_PAINT и ожидают, что пользователь сам нарисовает окно. Очевидно, что нет способа привязать WM_PAINT к пользовательскому чертежу.

Я что-то упускаю очень очевидное?

1 ответ

Решение

После длительного профилирования я обнаружил, что узким местом было не многоуровневое обновление окна. Обновление всего экрана, описанный выше метод SelectBitmap, в 1920*1200 занимало около 6-8 мс. Конечно, не очень удивительно, но достаточно для обновления со скоростью 30 FPS+.

В моем случае производительность исходит из некоторого потока, требующего обновления почти сто раз за перерисовку, что делает все вялым. Решение состояло в том, чтобы разбить обновление / перерисовку и разделить их. Один обновляет (объединяет) регион, а другой, когда не рисует, берет этот регион, рисует и затем очищает его.

Другие вопросы по тегам