Reputation: 81
I need to draw a PORTION of the graphics contents in a buffer to the screen during OnPaint override for a custom control, but only familiar with using .Render which draws the whole thing.
I use code like this to create the buffer.
private BufferedGraphicsContext context;
private BufferedGraphics grafx;
context = BufferedGraphicsManager.Current;
grafx = context.Allocate(CreateGraphics(), DisplayRectangle);
At various events things get drawn to buffer. Then...
protected override void OnPaint(PaintEventArgs e)
{
grafx.Render(e.Graphics);
}
This fills the control using the entire buffer - as it should. Sometimes, I only want to draw a portion of the content of buffer grafx.Graphics to e.Graphics. Like dest Rect <- src Rect or something.
Any ideas?
------------ Following part added 4/4/2023 in response to comment
So my project has two custom controls: one is a track bar with some custom features and the other is an audio waveform viewer that shows a cursor (a vertical line across the horizontally oriented bitmap strip). it's called PictureZoomer because there will ultimately be a zoomed in version of the wave below. The track bar is owner-drawn entirely from geometric commands in its OnPaint(). The waveform viewer creates a graphics buffer that covers the entire surface of the control. When a song is opened, a waveform bitmap is created and drawn to the buffer. When music is playing, a timer periodically updates the song playback position including changing the track bar .Value and also the wave viewer .Position (which is where to draw the cursor). I also can change the playback position by selecting the track bar "thumb" and moving it around. The controls are drawn in such a way that the track bar thumb seems attached to the waveform cursor as one unit.
tldr; The problem is: The cursor movement handling is too slow, and visually the cursor and tracking thumb get "disconnected" if I drag the thumb even moderately quickly. The OnPaint() of the viewer renders, with .Render(), the entire buffer to screen when the cursor position is changed, and then the cursor is drawn on top. I'd like OnPaint() only to redraw enough of the buffer to "erase" the cursor's former position, and then draw it again in a new, slightly shifted, spot.
The viewer class starts with...
public partial class PictureZoomer : Control
{ // PRIVATE VARIABLES
BufferedGraphicsContext myContext = BufferedGraphicsManager.Current;
BufferedGraphics myBuffer; // used to self-manage double buffer graphics
private Rectangle topFrame = new Rectangle();
In my properties section there is...
private int _position = 0;
public int Position
{
get => _position;
set
{
if ((value != _position) && (value >= 0) && (value <= PictureWidth))
{
/*if (value > _position) // moving right
Invalidate(new Rectangle(Gutter + _position - 2, topFrame.Top, value - _position + 2, topFrame.Height));
else // moving left
Invalidate(new Rectangle(Gutter + value - 2, topFrame.Top, _position - value + 2, topFrame.Height));*/
_position = value;
Invalidate();
}
}
}
And also...
protected override void OnPaint(PaintEventArgs pe)
{
myBuffer.Render();
pe.Graphics.DrawLine(new Pen(SystemColors.Highlight, 2), Gutter + Position, topFrame.Top, Gutter + Position, topFrame.Bottom);
}
Finally the track bar (slider1) emits an event when the thumb is moved that is handled in the Form...
private void slider1_ValueChanging(object sender, EventArgs e)
{
toolTip1.SetToolTip(slider1, FormatTime(Convert.ToInt32(slider1.Value)));
pzmWaveViewer.Position = Convert.ToInt32(slider1.Value * Convert.ToSingle(pzmWaveViewer.PictureWidth) / (slider1.ValueMax - slider1.ValueMin));
}
In the _position property, I currently Invalidate() the whole thing. You can see my former attempt to invalidate just around the cursor - that "worked" but then I couldn't draw the cursor in a new place outside the clipping region. I tried .ResetClip() after the render but that seemed to fail (re: my 2nd comment below). In the code shown, I have extended the invalidate region to include the new cursor position, which works but isn't ideal - and still prevents me drawing outside the clipRegion so I can't add things like tab stop indicators, which I will need at some point.
So my latest thinking was to avoid the invalidate and just set some flag so that in OnPaint I would copy in from the buffer enough to erase the cursor and then draw a new one. That's the foundation for my original post.
Also - I don't know how to ever state these problems in a concise way that makes sense! Sorry for the lengthy addition.
Upvotes: 0
Views: 138