Сделать недействительным собственное растровое изображение

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

к несчастью Control.DrawToBitmap кажется, рисует весь элемент управления, на котором он вызывается, включая все его дочерние элементы управления. Внутренне он выдает сообщение WM_PRINT с самодостаточным DC в растровое изображение. Это временное растровое изображение затем добавляется в предоставленное пользователем растровое изображение. Для меня это неприемлемо, я бы предпочел обновлять это растровое изображение по мере необходимости, чтобы свести к минимуму снижение производительности при необходимости растрового изображения.

В идеальном случае я бы хотел, чтобы форма вела себя так, как будто она была видна на экране (но это не может быть). Это будет означать, что если, скажем, некоторый контроль имеет Text свойство изменилось, форма будет частично признана недействительной. После перехвата соответствующих сообщений / событий я мог бы либо указать свой собственный DC для формы, которую нужно нарисовать, либо просто привязать DC формы к моему собственному.

Некоторые направления, в которых я смотрел:

  • PaintEventArgs параметр в OnPaint Кажется, он содержит элемент SavedGraphicsState, возможно, он может быть использован, чтобы выяснить, что не требует аннулирования
  • Наличие формы видимой, но за пределами области экрана. Тем не менее, элементы управления не окрашиваются.
  • Вызов RedrawWindow() вручную в окне, та же история

3 ответа

Решение

Я думаю, что есть две проблемы:

  1. обнаружение неверной области элемента управления (без помощи окон)
  2. рендеринг только недействительной части.

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

Что касается второй проблемы, вы можете попытаться отправить сообщение WM_PRINT самостоятельно и предоставить DC, ссылающийся только на маленькую битовую карту. Исходный DC API позволял вам смещать и обрезать действительную область рисования HDC. Если вам очень повезет, окна выведут область рендеринга из HDC, а если нет, большинство команд рендеринга, которые полностью выпадают из растрового изображения, должны быть довольно дешевыми, поскольку нет пикселей, которые нужно менять.

Вы должны быть в состоянии проверить это путем печати в растровое изображение 1x1 и проверить, быстрее ли это, и / или проверить, уменьшена ли область клипа, отправленная в WM_PAINT, до размера растрового изображения.

Я думаю, что это будет работать, если клонировать элемент управления, так что вы получите элемент управления, который не находится на форме и не имеет дочерних элементов управления:

Control ctrl = ControlFactory.CloneCtrl(this.button3);
Bitmap bmp = new Bitmap(ctrl.Width, ctrl.Height);
ctrl.DrawToBitmap(bmp, new Rectangle(0, 0, ctrl.Width, ctrl.Height));
bmp.Save(@"C:\Users\Oli\Desktop\test.bmp");

Я использовал ControlFactory, написанную lxwde, найденную в The Code Project.

ControlFactory не идеален, но он достаточно прост и может быть легко улучшен.

Я сделал пример проекта для вас, где я показал некоторые события onPaint. Если вы не видите, как это решается таким образом, просто обновите пример.

С уважением!Пример OnPaint

Загрузить здесь: http://www.goldengel.ch/temp/OnPaintExample.zip

Private Sub Button1_Paint(sender As System.Object, e As System.Windows.Forms.PaintEventArgs) Handles Button1.Paint
    Dim bm As New Bitmap(Me.Button1.Width, Me.Button1.Height, PixelFormat.Format32bppRgb)

    Button1.DrawToBitmap(bm, New Rectangle(0, 15, bm.Width -5, bm.Height+2))
    Using gr As Graphics = Graphics.FromImage(bm)
        gr.DrawString(DateTime.Now.ToLongTimeString, Me.Font, Brushes.Lime, 0, 0)
    End Using
    Me.PictureBox1.BackgroundImageLayout = ImageLayout.Tile
    Me.PictureBox1.BackgroundImage = bm

End Sub
    Public Class myTextBox
        Inherits System.Windows.Forms.TextBox


        Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
            MyBase.OnPaint(e)
            e.Graphics.Clear(Color.Yellow)
            e.Graphics.DrawString(DateTime.Now.ToLongTimeString, Me.Font, Brushes.Gray, 0, 0)
        End Sub

        Public Sub New()
            SetStyle(ControlStyles.UserPaint, True)
        End Sub
    End Class
Другие вопросы по тегам