Сделать недействительным собственное растровое изображение
Я хочу закадровый рендеринг элемента управления для некоторого растрового изображения, чтобы иметь быстрый доступ к нему.
к несчастью Control.DrawToBitmap
кажется, рисует весь элемент управления, на котором он вызывается, включая все его дочерние элементы управления. Внутренне он выдает сообщение WM_PRINT с самодостаточным DC в растровое изображение. Это временное растровое изображение затем добавляется в предоставленное пользователем растровое изображение. Для меня это неприемлемо, я бы предпочел обновлять это растровое изображение по мере необходимости, чтобы свести к минимуму снижение производительности при необходимости растрового изображения.
В идеальном случае я бы хотел, чтобы форма вела себя так, как будто она была видна на экране (но это не может быть). Это будет означать, что если, скажем, некоторый контроль имеет Text
свойство изменилось, форма будет частично признана недействительной. После перехвата соответствующих сообщений / событий я мог бы либо указать свой собственный DC для формы, которую нужно нарисовать, либо просто привязать DC формы к моему собственному.
Некоторые направления, в которых я смотрел:
PaintEventArgs
параметр вOnPaint
Кажется, он содержит элемент SavedGraphicsState, возможно, он может быть использован, чтобы выяснить, что не требует аннулирования- Наличие формы видимой, но за пределами области экрана. Тем не менее, элементы управления не окрашиваются.
- Вызов RedrawWindow() вручную в окне, та же история
3 ответа
Я думаю, что есть две проблемы:
- обнаружение неверной области элемента управления (без помощи окон)
- рендеринг только недействительной части.
Что касается первого вопроса, я думаю, что вы в значительной степени самостоятельно. Вы должны следить за тем, какие элементы управления меняются, и вести учет, который нуждается в обновлении.
Что касается второй проблемы, вы можете попытаться отправить сообщение 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. Если вы не видите, как это решается таким образом, просто обновите пример.
С уважением!
Загрузить здесь: 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