Posted By: object88 | Jul 20th, 2004 @ 10:09 AM
page 1 of 1
Comments: 3 | Views: 3390
object88
object88
amplify.
I'm writing a control that displays a graphic (larger than the control itself), which can zoom in and rotate, and I'm having loads of trouble with (I think) the scroll area.

OK, so it's a .NET WinForms usercontrol, and I'm taking advantage of the auto-scroll features.  I draw the base image onto the control, and use the Transform in the Graphics object in the OnPaint event to zoom in and out and rotate.  I'm currently rotating about the zero-point, so I also have to apply a translate to the Transform matrix (to keep the image in positive coordinates).

I've got it so that I can rotate 0, 90, 180, or 270 degrees (I'm not concerned about fine-grain rotation) when the whole image is displayed.  If the image is larger than the control client area (necessitating scroll bars), the image will initially display, but disappear when I move the scroll bars.

I'm guessing that the auto-scrollbars are moving the visible control area without knowing about how to change to the proper coordinate system.  I can't find anything in the UserControl that allows me to hook into the AutoScroll functionality, so I can't seem to control that movement myself.

Incidently, in terms of the matrix, I first apply my scale, then rotate, then translate.  I know it would be "easier" to use the bitmap rotation methods, but this is just the start-- I'm also drawing markups on top of the image, so I might as well do all my coordinate system adjustment in one place: the Graphics transform.

I think what I need to do is drop fhe auto-scroll features and create my own scroll bars, then translate their movement into movement that makes sense in my funky coordinate system.

Does this make sense?  Am I barking up the wrong tree?  Does anyone know of any online material that talks about how to do this stuff?

Thanks for any advice!
Bryn Waibel
Bryn Waibel
I'm not an actor, but i play one on channel9
I don't know if this will be helpful to you or not, but I would recommend separating your image manipulation from the rendering. Do all of your work on a bitmap object (which i'm sure you're already doing) and then clone it and assign the clone to render inside a regular old picturebox. The picturebox will take care of scrolling for you I believe.

Hmm, after re-reading this again, i think you may be trying to retain focus on a single point after the zoom. I do remember having some significant trouble with this using autoscroll. I'd suggest moving to a custom scroll bar solution, which is actually not as difficult as it would seem. It's really just a matter of setting Location coordinates of the image (I'd still use a picturebox) relative to the percent of scroll. Anyway, here's a little code that I just wrote (which may not work at all) which may help you when dealing with the scrollbars. The form I pasted this from is just one of my play projects, so bear with me as far as the variable names go. The vertical scrolling isn't quite right either. The scroll area is laid out such that there is a main panel. Inside that panel is another panel, docked right, with a vScrollBar inside it, docked fill, the panel has an 18 pixel DockPadding.Bottom. Also inside the main panel, is hScrollBar, docked bottom (18px tall). Also inside the main panel is another panel, docked fill. Inside that panel is an image, pictureBox2. NewImage is the method that is called when I am finished preparing an image. The xFactor and yFactor stuff should maintain the scroll position between images.

private void NewImage(Image image)

{

   float xFactor = (float)image.Width / (float)this.pictureBox2.Image.Width;

   float yFactor = (float)image.Height / (float)this.pictureBox2.Image.Height;

   
   this.pictureBox2.Image = image;

   this.pictureBox2.Size = this.pictureBox2.Image.Size;
   this.vScrollBar1.Maximum = this.pictureBox2.Height;

   this.vScrollBar1.Minimum = 0;

   this.hScrollBar1.Maximum = this.pictureBox2.Width;

   this.hScrollBar1.Minimum = 0;

   this.vScrollBar1.Value = (int)((float)this.vScrollBar1.Value * yFactor);

   this.hScrollBar1.Value = (int)((float)this.hScrollBar1.Value * xFactor);

   this.vScrollBar1.SmallChange = 10; // totally random

   this.hScrollBar1.SmallChange = 10; // totally random

   this.vScrollBar1.LargeChange = this.vScrollBar1.Width;

   this.hScrollBar1.LargeChange = this.hScrollBar1.Width;

   SetPictureLocation();

}

private void SetPictureLocation()

{

   this.pictureBox2.Left = -this.hScrollBar1.Value;

   this.pictureBox2.Top = -this.vScrollBar1.Value;

}

private void hScrollBar1_Scroll(object sender, System.Windows.Forms.ScrollEventArgs e)

{

   SetPictureLocation();

}

private void vScrollBar1_Scroll(object sender, System.Windows.Forms.ScrollEventArgs e)

{

   SetPictureLocation();

}

Bryn Waibel
Bryn Waibel
I'm not an actor, but i play one on channel9
Another thing I notice, which should address your problem more directly, is that the graphics area will throw away any painting that you do outside of the client area of the control. It looks like you might be trying to paint your image on the entire (visible and non visible) surface of your control once, rather than painting the correct portion of an in-memory image into the invalidated rectangles represented in the PaintEventArgs.ClipRectangle property.