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

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

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

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

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

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

Ответ 1

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

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

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

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

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

Ответ 2

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

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, найденный в Проект кода.

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

Ответ 3

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

Привет! OnPaint example

Скачать здесь: 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