Недействительность в собственном растровом изображении
Я хочу отключить отображение элемента управления некоторым растровым изображением, чтобы у меня был быстрый доступ к нему.
К сожалению, 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