I have a custom control that zooms on a custom drawn document canvas.
I tried using AutoScroll but it was not giving satisfactory results. When I would set AutoScrollPosition and AutoScrollMinSize back to back (in any order) it would force a paint and cause jitter each time the zoom changes. I assume this was because it was calling an Update and not Invalidate when I modified both properties.
I am now manually setting the HorizontalScroll and VerticalScroll properties with AutoScroll set to false like so each time the Zoom level or the client size changes:
int canvasWidth = (int)Math.Ceiling(Image.Width * Zoom) + PageMargins.Horizontal;
int canvasHeight = (int)Math.Ceiling(Image.Height * Zoom) + PageMargins.Vertical;
HorizontalScroll.Maximum = canvasWidth;
HorizontalScroll.LargeChange = ClientSize.Width;
VerticalScroll.Maximum = canvasHeight;
VerticalScroll.LargeChange = ClientSize.Height;
if (canvasWidth > ClientSize.Width)
{
HorizontalScroll.Visible = true;
}
else
{
HorizontalScroll.Visible = false;
HorizontalScroll.Value = 0;
}
if (canvasHeight > ClientSize.Height)
{
VerticalScroll.Visible = true;
}
else
{
VerticalScroll.Visible = false;
VerticalScroll.Value = 0;
}
int focusX = (int)Math.Floor((FocusPoint.X * Zoom) + PageMargins.Left);
int focusY = (int)Math.Floor((FocusPoint.Y * Zoom) + PageMargins.Top);
focusX = focusX - ClientSize.Width / 2;
focusY = focusY - ClientSize.Height / 2;
if (focusX < 0)
focusX = 0;
if (focusX > canvasWidth - ClientSize.Width)
focusX = canvasWidth - ClientSize.Width;
if (focusY < 0)
focusY = 0;
if (focusY > canvasHeight - ClientSize.Height)
focusY = canvasHeight - ClientSize.Height;
if (HorizontalScroll.Visible)
HorizontalScroll.Value = focusX;
if (VerticalScroll.Visible)
VerticalScroll.Value = focusY;
In this case, FocusPoint is a PointF structure that holds the coordinates in the bitmap which the user is focused on (for example, when they mouse wheel to zoom in they are focusing on the current mouse location at that time). This functionality works for the most part.
What does not work is the scroll bars. If the user tries to manually scroll by clicking on either scroll bar, they both keep returning to 0. I do not set them anywhere else in my code. I have tried writing the following in the OnScroll() method:
if (se.ScrollOrientation == ScrollOrientation.VerticalScroll)
{
VerticalScroll.Value = se.NewValue;
}
else
{
HorizontalScroll.Value = se.NewValue;
}
Invalidate();
But this causes some very erratic behavior including flicking and scrolling out of bounds.
How am I supposed to write the code for OnScroll? I've tried the base.OnScroll but it didn't do anything while AutoScroll is set to false.
I ended up implementing my own custom scrolling by creating 3 child controls: an HScrollBar, a VScrollBar, and a Panel.
I hide ClientSize and ClientRectangle like so:
public new Rectangle ClientRectangle
{
get
{
return new Rectangle(new Point(0, 0), ClientSize);
}
}
public new Size ClientSize
{
get
{
return new Size(
base.ClientSize.Width - VScrollBar.Width,
base.ClientSize.Height - HScrollBar.Height
);
}
}
The layout is done in OnClientSizeChanged:
protected override void OnClientSizeChanged(EventArgs e)
{
base.OnClientSizeChanged(e);
HScrollBar.Location = new Point(0, base.ClientSize.Height - HScrollBar.Height);
HScrollBar.Width = base.ClientSize.Width - VScrollBar.Width;
VScrollBar.Location = new Point(base.ClientSize.Width - VScrollBar.Width, 0);
VScrollBar.Height = base.ClientSize.Height - HScrollBar.Height;
cornerPanel.Size = new Size(VScrollBar.Width, HScrollBar.Height);
cornerPanel.Location = new Point(base.ClientSize.Width - cornerPanel.Width, base.ClientSize.Height - cornerPanel.Height);
}
Each ScrollBar has their Scroll event subscribed to the following:
private void ScrollBar_Scroll(object sender, ScrollEventArgs e)
{
OnScroll(e);
}
And finally we can allow MouseWheel events to scroll with the following:
protected override void OnMouseWheel(MouseEventArgs e)
{
int xOldValue = VScrollBar.Value;
if (e.Delta > 0)
{
VScrollBar.Value = (int)Math.Max(VScrollBar.Value - (VScrollBar.SmallChange * e.Delta), 0);
OnScroll(new ScrollEventArgs(ScrollEventType.ThumbPosition, xOldValue, VScrollBar.Value, ScrollOrientation.VerticalScroll));
}
else
{
VScrollBar.Value = (int)Math.Min(VScrollBar.Value - (VScrollBar.SmallChange * e.Delta), VScrollBar.Maximum - (VScrollBar.LargeChange - 1));
OnScroll(new ScrollEventArgs(ScrollEventType.ThumbPosition, xOldValue, VScrollBar.Value, ScrollOrientation.VerticalScroll));
}
}
For custom painting, you would use the following statement:
e.Graphics.TranslateTransform(-HScrollBar.Value, -VScrollBar.Value);
This worked perfectly without the glitches present when using AutoScroll.
Related
I have a custom written chart control. My charts are displaying time on x-axis and current on y-axis. What I want is, selected zoom. So when user clicks and drag mouse over chart it shows selection rectangle and selects particular area on chart and updates the chart to display points of only selected area.
My problem is, I can zoom in for the first time and it shows me correct results on updated chart. with correctly updated x coordinates. But when I do it again (anytime after 1st zoom in) points are always off.
All I want is when user selects another area on already zoom in chart it should do further zoom in with updated x coordinates.
What I tried: From proper observation of my chart zoom in behavior I found that every time when I click on chart that point is mapped to my original chart width and not updated width(updated width I found as (endingXPoints - beginingXPoints) when I do zoom). So I have to map points according to updated width. But That does not work. I still do not get correct zoom in. Also I tried using scaling factor as chart size is changing but still result is not correct.
So my question how to map the points of zoomed chart on my original chart. I am doing this in windows form and using custom written library.
I just began my career as developer and still in learning process. Any suggestion will be great help to me. Thank you
Here is my mouse_up event, if that code helps. I have try to add as many comments as possible. In this code I am saving previous points clicked on stack and using it to get scale factor and get the scaled
private void chart_MouseUp(object sender, MouseEventArgs e)
{
Point p1, p2;
//when mouse up occurs it first checks, with isMousePressed, if mouse was pressed or not
if (isMousepressed)
{
isMousepressed = false;
isMouseEventOccured = true;
int xLeft = chartA.GetLeftDistToXaxis;//left distance from starting of control to x axis
int xWidth = chartA.chartWidth;//actual x-axis width shown on control
int yBottom = chartA.yTopPadding + chartA.chartHeight;//bottom distance from starting of control to y axis
//if no start - end points are selected then do nothing and return
if (endSelectionPoint == Point.Empty || beginSelectionPoint == Point.Empty) return;
//if start point is same as end point, do noting and return and if selection is made on left side of Y axis do nothing
if (endSelectionPoint.X == beginSelectionPoint.X) return;
if (endSelectionPoint.Y == beginSelectionPoint.Y) return;
if (beginSelectionPoint.X < xLeft && endSelectionPoint.X < xLeft) return;//avoid left chart area
if (beginSelectionPoint.Y > yBottom && endSelectionPoint.Y > yBottom) return;//avoid bottom chart area
endSelectionPoint.X = e.X;
endSelectionPoint.Y = e.Y;
//when all of the above conditions are false, we have two different start/end points which is not empty. map it & draw rectangle
p1 = ((Control)sender).PointToScreen(beginSelectionPoint);
p2 = ((Control)sender).PointToScreen(endSelectionPoint);
//draw selection rectangle
ControlPaint.DrawReversibleFrame(chartA.getRectangleForPoints(p1, p2), Color.Black, FrameStyle.Dashed);
//checking the begin and end value of x-y coordinates to see if they are on chart. if not then set the boundaries
//check it for begin coordinates
if (beginSelectionPoint.X < xLeft) { beginSelectionPoint.X = xLeft; }
if (beginSelectionPoint.X > (xLeft + chartA.Width)) { return; /*beginSelectionPoint.X = (xLeft + chartA.Width);*/ }
//if (beginSelectionPoint.Y < yBottom) { beginSelectionPoint.Y = yBottom; }
//if (beginSelectionPoint.Y > (yBottom + chartA.Height)) { beginSelectionPoint.Y = (yBottom + chartA.Height); }
//check it for end coordinates
if (endSelectionPoint.X > (xLeft + chartA.Width)) { endSelectionPoint.X = (xLeft + chartA.Width); }
if (endSelectionPoint.X < xLeft) { endSelectionPoint.X = xLeft; }
//if (endSelectionPoint.Y < yBottom) { endSelectionPoint.Y = yBottom; }
//if (endSelectionPoint.Y > (yBottom + chartA.Height)) { endSelectionPoint.Y = (yBottom + chartA.Height); }
//actual x-y value on chart.....x->corresponding time; y-> corresponding Amperage
xStart = 10 * chartA.MouseToXProportion(beginSelectionPoint.X );//multiplied with 10 to get the correct x values, if not used values in 0.+
yStart = chartA.MouseToYProportion(beginSelectionPoint.Y);
xEnd = 10 * chartA.MouseToXProportion(endSelectionPoint.X);
yEnd = chartA.MouseToYProportion(endSelectionPoint.Y);
if (zoomStack.Count != 0)
{
Point prevZoomPtEnd = (Point)zoomStack.Pop();
Point prevZoomPtStart = (Point)zoomStack.Pop();
double oldWidth = prevZoomPtEnd.X - prevZoomPtStart.X;
double zoomedWidth = endSelectionPoint.X - beginSelectionPoint.X;
double scaleFactor = zoomedWidth / oldWidth;
xStart = 10 * (chartA.MouseToXProportion(beginSelectionPoint.X) * scaleFactor);
xEnd = 10 * (chartA.MouseToXProportion(endSelectionPoint.X) * scaleFactor);
zoomStack.Push(beginSelectionPoint);
zoomStack.Push(endSelectionPoint);
}
else
{
zoomStack.Push(beginSelectionPoint);
zoomStack.Push(endSelectionPoint);
}
double xTemp;
if (xStart > xEnd) { xTemp = xEnd; xEnd = xStart; xStart = xTemp; }
//call updatechart() with start and end points on graph being p1/p2 or beginselection/endselection
updateChart(lastSelectedProfile, lastSelectedWeldIndex, xStart, xEnd);
}
else return;
}
Do you have to map the points? The chart's built in zoom should handle zooming correctly without trying to re-invent the wheel. The code below should be enough, hold left click and drag to zoom into the range.
private void setUserSelection(Chart cht)
{
cht.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
cht.ChartAreas[0].CursorX.IsUserEnabled = true;
cht.ChartAreas[0].CursorX.LineColor = Color.Transparent;
cht.ChartAreas[0].CursorX.SelectionColor = Color.Lime;
cht.ChartAreas[0].CursorX.Interval = 0;
cht.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
cht.ChartAreas[0].AxisX2.ScaleView.Zoomable = true;
cht.ChartAreas[0].CursorY.IsUserSelectionEnabled = true;
cht.ChartAreas[0].CursorY.IsUserEnabled = true;
cht.ChartAreas[0].CursorY.LineColor = Color.Transparent;
cht.ChartAreas[0].CursorY.SelectionColor = Color.Lime;
cht.ChartAreas[0].CursorY.Interval = 0;
cht.ChartAreas[0].AxisY.ScaleView.Zoomable = true;
cht.ChartAreas[0].AxisY2.ScaleView.Zoomable = true;
}
To zoom out back one zoom, you'll need to add the following code somewhere. In my example below I have mine on the mouse right click.
private void chart1_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
chart1.ChartAreas[0].AxisX.ScaleView.ZoomReset(1);
chart1.ChartAreas[0].AxisY.ScaleView.ZoomReset(1);
}
}
In WPF it has the default support for the vertical alignment for the TextBox control. but in Windows Forms there is no way to set the vertical alignment of the TextBox control.
In My case, I have using the multi-line text box and the text is need to be displayed on the bottom of the TextBox and it need to be maintain the alignment while typing on it.
I have tried to get the line count of the entered text and try to calculate the bounds of the text box based on the length of the text. but the line count is not get properly when editing the text with word wrap.
Can any one help me on this to maintain the vertical alignment of the TextBox while editing?
I have tried to change the location of the textbox using the suggestion given in that thread. when editing the text. When I try to edit the text the bounds is not updated properly and some part of the text is hidden in the text box. I have calculated the bounds based on the font size and text width.
Size textSize = TextRenderer.MeasureText(TextBoxText, this.textBoxControl.Font);
int textBoxTop = this.textBoxControl.Bounds.Top;
int nol = (textSize.Width > this.textBoxControl.Width) ? ((textSize.Width) / this.textBoxControl.Width) + 1 : 1;
{
if (nol > n)
{
n = nol;
rect1 = this.textBoxControl.Bounds;
if (top + (height - nol * textSize.Height) > top)
{
rect1.Y = top + (height - nol * textSize.Height);
rect1.Height = nol * textSize.Height;
this.textBoxControl.Bounds = rect1;
}
else
{
this.textBoxControl.Bounds = rect1;
}
}
else if (nol < n)
{
n = nol;
rect1 = this.textBoxControl.Bounds;
if (rect1.Y + nol * textSize.Height < top + height)
{
rect1.Y += textSize.Height - this.textBoxControl.Margin.Top;
rect1.Height -= textSize.Height;
//this.textBoxControl.Bounds = rect1;
}
if (nol == 1)
{
rect1.Y = top + height - textSize.Height;
rect1.Height = textSize.Height;
//this.textBoxControl.Bounds = rect1;
}
this.textBoxControl.Bounds = rect1;
}
}
Its working fine while editing the text, but in some cases the nol Line count is calculated wrongly. How can I get the actual line count of the textbox including the wrapped lines.?
I have created a control that has a TextBox docked to the bottom of a panel that looks kinda like a TextBox:
// Make sure you have this.
using System.Linq;
public class BottomAlignTextBox : Panel
{
public BottomAlignTextBox()
{
this.BackColor = Color.White;
this.BorderStyle = (Application.RenderWithVisualStyles) ? BorderStyle.FixedSingle : BorderStyle.Fixed3D;
this.Size = new Size(200, 200);
this.Padding = new Padding(5, 0, 4, 2);
bottomAlignTextBox.Dock = DockStyle.Bottom;
bottomAlignTextBox.Multiline = true;
bottomAlignTextBox.WordWrap = true;
bottomAlignTextBox.AcceptsReturn = true;
bottomAlignTextBox.BorderStyle = BorderStyle.None;
bottomAlignTextBox.Height = 20;
bottomAlignTextBox.TextChanged += delegate
{
if (bottomAlignTextBox.Height < this.Height - 20)
{
if (TextRenderer.MeasureText(bottomAlignTextBox.Text, bottomAlignTextBox.Font).Width > bottomAlignTextBox.Width + 6)
{
string longestLine = bottomAlignTextBox.Lines.OrderByDescending(s => TextRenderer.MeasureText(s, bottomAlignTextBox.Font).Width).First();
bottomAlignTextBox.Text = bottomAlignTextBox.Text.Replace(longestLine, longestLine.Substring(0, longestLine.Length - 1) + Environment.NewLine + longestLine[longestLine.Length - 1]);
bottomAlignTextBox.Height += 19;
bottomAlignTextBox.SelectionStart = bottomAlignTextBox.Text.Length + 2;
bottomAlignTextBox.SelectionLength = 0;
}
}
};
this.Controls.Add(bottomAlignTextBox);
this.Click += delegate { bottomAlignTextBox.Focus(); };
}
public new string Text
{
get { return bottomAlignTextBox.Text; }
set { bottomAlignTextBox.Text = value; }
}
private TextBox bottomAlignTextBox = new TextBox();
}
I am not sure if that is entirely possible, but I think you can wrap the control with a Panel control or some sort and Dock it to the bottom of the wrapping Panel control? If the size needs to be dynamic, playing around the Anchor properties should work as well.
I'm building custom control that will display tiles, like colored grid.
I've managed to do drawing, scrolling and basic logic, but I have problem with creating tooltip for each tile.
Each tile color depends on data that is "bound" to that tile.
I'll try to describe my idea:
Above image shows my control, I have 4 squares drawn there, I'd like to show different tooltip when user hovers different parts of my control.
Below is my tooltip (small red rectangle) and lower is standard WinForms Chart component.
I'd like to get this kind of behavior in my control (tooltip is outside of control, so long text is displayed properly).
Below is code of my control with just basic functionality:
public sealed class UC1 : UserControl
{
private bool _showTooltip;
private string _tooltipText;
private Point _mousePosition;
public UC1()
{
MinimumSize = new Size(100, 100);
Size = new Size(100, 100);
SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw | ControlStyles.OptimizedDoubleBuffer, true);
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.FillRectangle(Brushes.LightGoldenrodYellow, 0, 0, Width/2, Height/2);
e.Graphics.FillRectangle(Brushes.LightGray, Width/2, 0, Width, Height/2);
e.Graphics.FillRectangle(Brushes.LightSlateGray, 0, Height/2, Width/2, Height);
e.Graphics.FillRectangle(Brushes.LightSteelBlue, Width/2, Height/2, Width, Height);
using (var p = new Pen(Color.Black, 2))
{
e.Graphics.DrawLine(p, Width/2, 0, Width/2, Height);
e.Graphics.DrawLine(p, 0, Height/2, Width, Height/2);
}
if (_showTooltip)
{
SizeF c = e.Graphics.MeasureString(_tooltipText, DefaultFont);
int width = (int) c.Width;
int height = (int) c.Height;
const int offset = 12;
var x = _mousePosition.X + width + offset > Width ? _mousePosition.X - width : _mousePosition.X + offset;
var y = _mousePosition.Y + height + offset > Height ? _mousePosition.Y - height : _mousePosition.Y + offset;
e.Graphics.FillRectangle(Brushes.Red, x, y, width, height);
e.Graphics.DrawString(_tooltipText, DefaultFont, Brushes.Black, x, y);
}
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (e.X > 0 && e.X < Width/2 && e.Y > 0 && e.Y < Height/2)
{
Debug.WriteLine("1,1 square");
_tooltipText = "1,1";
}
else if (e.X > Width/2 && e.X < Width && e.Y > 0 && e.Y < Height/2)
{
Debug.WriteLine("1,2 square");
_tooltipText = "1,2";
}
else if (e.X > 0 && e.X < Width/2 && e.Y > Height/2 && e.Y < Height)
{
Debug.WriteLine("2,1 square");
_tooltipText = "2,1";
}
else if (e.X > Width/2 && e.X < Width && e.Y > Height/2 && e.Y < Height)
{
Debug.WriteLine("2,2 square");
_tooltipText = "2,2";
}
_mousePosition = e.Location;
_showTooltip = true;
Refresh();
}
protected override void OnMouseLeave(EventArgs e)
{
_showTooltip = false;
Refresh();
base.OnMouseLeave(e);
}
}
I've found similar question: How to make a floating (tooltip) control in Windows.Forms? but I'd like to avoid creating custom tooltip and instead use standard one.
How can I show standard tooltip that will change it text when hovering on different tiles. I'd like to add everything to my user control, so I won't have to add any code to form hosting my control.
Why do you try to draw the ToolTip yourself instead of using the system one?
Just add one to the UC class
// private bool _showTooltip; ?? probably not needed any more..
private string _tooltipText;
// private Point _mousePosition; ??..
ToolTip ttip = new ToolTip();
and set it like this:
// _mousePosition = e.Location; ??..
// _showTooltip = true; ??..
ttip.SetToolTip(this, _tooltipText); // use this in the mousemove
Refresh();
Of course now you can skip the whole Painting part..
If you want to control the location where the ToolTip is shown use one of the ShowToolTip() overloads instead of SetToolTip() ..!
While both are still there this is the result, going over the UC's border and displaying with a nice drop shadow..:
If you really want your ToolTip to look different from the usual ones, you can set its OwnerDraw to true and code its Draw event just like any other control with GDI+ graphics methods..
Update:
There is an inherent flicker problem; for an explanation see Hans' answer here; his recommendation #2 and one of the answers is helpful:
Remember last mouse position and set the tooltip only when the mouse
position changes.
So we need to add a last ToolTip location:
Point tipLoc = Point.Empty;
Which we test and set in the mouse move:
if (tipLoc != e.Location )
{
tipLoc = e.Location;
ttip.SetToolTip(this, _tooltipText);
}
My form has two objects: a background image that takes up the entire screen, and a dragable dialog control that only takes up a portion of the screen. I am using Mouse events for dragging and dropping the dialog control within the background image.
My problem is that while dragging, there is a copy of the control that is visible at it's previous location.
What is causing this shadow copy to appear, and how can I prevent it from happening?
My code looks something like this:
private void dialog_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
_dialogDragStart = e.Location;
dialog.MouseMove += new MouseEventHandler(dialog_MouseMove);
}
}
private void dialog_MouseUp(object sender, MouseEventArgs e)
{
dialog.MouseMove -= new MouseEventHandler(dialog_MouseMove);
_isDragging.Value = false;
}
private void dialog_MouseMove(object sender, MouseEventArgs e)
{
var difference = new Point(e.Location.X - _dialogDragStart.X, e.Location.Y - _dialogDragStart.Y);
if (!_isDragging.Value)
{
if (Math.Abs(difference.X) > SystemInformation.DragSize.Width || Math.Abs(difference.Y) > SystemInformation.DragSize.Height)
{
_isDragging.Value = true;
}
}
else if (_isDragging.Value && !difference.IsEmpty)
{
DialogOffset = GetValidDialogOffset(DialogOffset.X + difference.X, DialogOffset.Y + difference.Y);
this.Invalidate();
this.Update();
}
}
It should be noted that this entire UserControl contains a custom OnPaint event. The Paint event recalculates the Size and Location of the Dialog before painting it in a custom format. To get this working, I have simply adjusted the Location calculation to include the DialogOffset.
const int padding = 1;
const int shadowDepth = 3;
const int roudeCornerRadius = 5;
private void Paint(Graphics g, Rectangle clipRect)
{
try
{
dialog.Size = GetSize();
dialog.Location = new Point(
((backgroundImage.Width - dialog.Width) / 2) + DialogOffset.X,
((backgroundImage.Height - dialog.Height) / 2) + DialogOffset.Y);
if (Image != null && !backgroundImage.ClientRectangle.IsEmpty)
{
Rectangle imageBounds = new Rectangle(Point.Empty, Image.Size);
using (BufferedGraphics buffer = BufferedGraphicsManager.Current.Allocate(g, backgroundImage.ClientRectangle))
{
using (Bitmap img = ((Bitmap)backgroundImage).Clone(imageBounds, PixelFormat.Format16bppArgb1555) as Bitmap)
{
buffer.Graphics.Clear(Color.White);
buffer.Graphics.DrawImage(img,backgroundImage.ClientRectangle, imageBounds, GraphicsUnit.Pixel);
buffer.Render(g);
}
}
}
//Create Rectangles
Rectangle outerRect = dialog.ClientRectangle;
Rectangle innerRect = new Rectangle(padding, padding, outerRect.Width - (padding + shadowDepth), outerRect.Height - (padding + shadowDepth));
//create Paths
using (GraphicsPath innerPath = new GraphicsPath())
{
GraphicsHelper.GetRoundedRect(innerPath, innerRect, roudeCornerRadius, 1, 1);
//Assign outer rounded rectangle to the dialog's region property
Region region = new Region(innerPath);
if (dialog.Region != null)
dialog.Region.Dispose();
dialog.Region = region;
}
}
catch (Exception ex)
{
// Log error
}
}
I've seen suggestions to set the DoubleBufferred property to true, however its explicitly set to false in the existing code, and setting it to true causes no update at all while dragging.
I've tried taking a screenshot of the problem, however all screenshots only show one copy of the dialog control being dragged, even though I can clearly see a 2nd copy of the control on my screen while dragging.
What can be causing this, and how can I fix it?
I have implemented a picturebox in my in my form.I even implemented the scrollbars to make the image fit in it.so now the problem is when i try to scroll the button down,it scrolls down and immediately when i leave the mouse the button scrolls up ..here is the code implemnted please give some suggestions..
public void DisplayScrollBars()
{
// If the image is wider than the PictureBox, show the HScrollBar.
if (pictureBox1.Width > pictureBox1.Image.Width - this.vScrollBar1.Width)
{
hScrollBar1.Visible = false;
}
else
{
hScrollBar1.Visible = true;
}
// If the image is taller than the PictureBox, show the VScrollBar.
if (pictureBox1.Height >
pictureBox1.Image.Height - this.hScrollBar1.Height)
{
vScrollBar1.Visible = false;
}
else
{
vScrollBar1.Visible = true;
}
}
private void HandleScroll(Object sender, ScrollEventArgs se)
{
/* Create a graphics object and draw a portion
of the image in the PictureBox. */
Graphics g = pictureBox1.CreateGraphics();
g.DrawImage(pictureBox1.Image,
new Rectangle(0, 0, pictureBox1.Right - vScrollBar1.Width,
pictureBox1.Bottom - hScrollBar1.Height),
new Rectangle(hScrollBar1.Value, vScrollBar1.Value,
pictureBox1.Right - vScrollBar1.Width,
pictureBox1.Bottom - hScrollBar1.Height),
GraphicsUnit.Pixel);
pictureBox1.Update();
}
public void SetScrollBarValues()
{
// Set the Maximum, Minimum, LargeChange and SmallChange properties.
this.vScrollBar1.Minimum = 0;
this.hScrollBar1.Minimum = 0;
// If the offset does not make the Maximum less than zero, set its value.
if ((this.pictureBox1.Image.Size.Width - pictureBox1.ClientSize.Width) > 0)
{
this.hScrollBar1.Maximum =
this.pictureBox1.Image.Size.Width - pictureBox1.ClientSize.Width;
}
// If the VScrollBar is visible, adjust the Maximum of the
// HSCrollBar to account for the width of the VScrollBar.
if (this.vScrollBar1.Visible)
{
this.hScrollBar1.Maximum += this.vScrollBar1.Width;
}
this.hScrollBar1.LargeChange = this.hScrollBar1.Maximum / 10;
this.hScrollBar1.SmallChange = this.hScrollBar1.Maximum / 20;
// Adjust the Maximum value to make the raw Maximum value
// attainable by user interaction.
this.hScrollBar1.Maximum += this.hScrollBar1.LargeChange;
// If the offset does not make the Maximum less than zero, set its value.
if ((this.pictureBox1.Image.Size.Height - pictureBox1.ClientSize.Height) > 0)
{
this.vScrollBar1.Maximum =
this.pictureBox1.Image.Size.Height - pictureBox1.ClientSize.Height;
}
// If the HScrollBar is visible, adjust the Maximum of the
// VSCrollBar to account for the width of the HScrollBar.
if (this.hScrollBar1.Visible)
{
this.vScrollBar1.Maximum += this.hScrollBar1.Height;
}
this.vScrollBar1.LargeChange = this.vScrollBar1.Maximum / 10;
this.vScrollBar1.SmallChange = this.vScrollBar1.Maximum / 20;
// Adjust the Maximum value to make the raw Maximum value
// attainable by user interaction.
this.vScrollBar1.Maximum += this.vScrollBar1.LargeChange;
}
private void pictureBox1_Resize(object sender, EventArgs e)
{
// If the PictureBox has an image, see if it needs
// scrollbars and refresh the image.
if (pictureBox1.Image != null)
{
this.DisplayScrollBars();
this.SetScrollBarValues();
this.Refresh();
}
}
As I comment above, the correct way of doing this is to put your pictureBox in a panel and set the panel.AutoScroll=true. Also you need to set pictureBox.SizeMode=AutoSize so it is sized equal to the size of the image that it contains. Check: PictureBoxSizeMode Enumeration