C# Application to Zoom in/out the image in a PictureBox - c#

I am somewhat new to programming in general, but I am eager to learn more and I was wondering if anyone could possibly help me out with an idea.
(main goal)
I want to make a simple program that consists of a C# Windows Forms Application that displays a preset image (of 6000x6000 pixel dimensions, SizeMode set to Zoom so the entire image is visible on the form at once) in a PictureBox that will take up the entire form practically, save for a space at the bottom of the form where I want to display a TrackBar that will allow you to zoom the image in and out; as well as a horizontal scroll bar at the base of the PictureBox, and a vertical scroll bar on the right side of the PictureBox to scroll around the map when it is zoomed, and I wanted to be able to control these scroll bars by either clicking and dragging in a corresponding direction on the PictureBox (preferred but not sure if its possible) or by using the scroll wheel on the mouse (probably easier but once again not sure).
(reference)
[ Here is my form completed exactly as I described, with a 6000x6000 placement holder demo texture in a PictureBox using SizeMode Zoom, as an example - THIS HAS BEEN HANDLED, NEXT PART OF THE PROBLEM IS UPDATED BELOW:]
(addendum)
The only issue I am having is the code, as I am pretty much greenhorn in that department. I have been working to learn Visual Studio's workflow, but I really could use some help.
Thank you so much in advance for anything you can help me with.
UPDATE:
After doing research on the subject and taking time to do some thinking, I have come up with the code listed below; but my problem is that when I pan my image too far, the image is allowed to be pulled too far over, thus exposing the panel behind it when the image is panned/pulled too far over to one corner. Also, when I zoom too far out, the image is allowed to become WAY smaller than the Picturebox.
Panning issue, the grey parts of the panel are the problem
Zoom issue, the grey parts of the panel are the problem
So, my last question: How would I go about revising the code below to 'lock' the image that I am panning and zooming from being allowed to pan or zoom outside of its frame and expose the panel behind it?
public partial class ImageZoomMainForm : Form
{
Image img;
Point mouseDown;
int startx = 0;
int starty = 0;
int imgx = 0;
int imgy = 0;
bool mousepressed = false;
float zoom = 1;
public ImageZoomMainForm()
{
InitializeComponent();
string imagefilename = #"..\..\ViewPort_MAIN.tif";
img = Image.FromFile(imagefilename);
Graphics g = this.CreateGraphics();
zoom = ((float)pictureBox.Width / (float)img.Width) * (img.HorizontalResolution / g.DpiX);
pictureBox.Paint += new PaintEventHandler(imageBox_Paint);
}
private void pictureBox_MouseMove(object sender, EventArgs e)
{
MouseEventArgs mouse = e as MouseEventArgs;
if (mouse.Button == MouseButtons.Left)
{
Point mousePosNow = mouse.Location;
int deltaX = mousePosNow.X - mouseDown.X;
int deltaY = mousePosNow.Y - mouseDown.Y;
imgx = (int)(startx + (deltaX / zoom));
imgy = (int)(starty + (deltaY / zoom));
pictureBox.Refresh();
}
}
private void imageBox_MouseDown(object sender, EventArgs e)
{
MouseEventArgs mouse = e as MouseEventArgs;
if (mouse.Button == MouseButtons.Left)
{
if (!mousepressed)
{
mousepressed = true;
mouseDown = mouse.Location;
startx = imgx;
starty = imgy;
}
}
}
private void imageBox_MouseUp(object sender, EventArgs e)
{
mousepressed = false;
}
protected override void OnMouseWheel(MouseEventArgs e)
{
float oldzoom = zoom;
if (e.Delta > 0)
{
zoom += 0.1F;
}
else if (e.Delta < 0)
{
zoom = Math.Max(zoom - 0.1F, 0.01F);
}
MouseEventArgs mouse = e as MouseEventArgs;
Point mousePosNow = mouse.Location;
int x = mousePosNow.X - pictureBox.Location.X;
int y = mousePosNow.Y - pictureBox.Location.Y;
int oldimagex = (int)(x / oldzoom);
int oldimagey = (int)(y / oldzoom);
int newimagex = (int)(x / zoom);
int newimagey = (int)(y / zoom);
imgx = newimagex - oldimagex + imgx;
imgy = newimagey - oldimagey + imgy;
pictureBox.Refresh();
}
private void imageBox_Paint(object sender, PaintEventArgs e)
{
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
e.Graphics.ScaleTransform(zoom, zoom);
e.Graphics.DrawImage(img, imgx, imgy);
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
const int WM_KEYDOWN = 0x100;
const int WM_SYSKEYDOWN = 0x104;
if ((msg.Msg == WM_KEYDOWN) || (msg.Msg == WM_SYSKEYDOWN))
{
switch (keyData)
{
case Keys.Right:
imgx -= (int)(pictureBox.Width * 0.1F / zoom);
pictureBox.Refresh();
break;
case Keys.Left:
imgx += (int)(pictureBox.Width * 0.1F / zoom);
pictureBox.Refresh();
break;
case Keys.Down:
imgy -= (int)(pictureBox.Height * 0.1F / zoom);
pictureBox.Refresh();
break;
case Keys.Up:
imgy += (int)(pictureBox.Height * 0.1F / zoom);
pictureBox.Refresh();
break;
case Keys.PageDown:
imgy -= (int)(pictureBox.Height * 0.90F / zoom);
pictureBox.Refresh();
break;
case Keys.PageUp:
imgy += (int)(pictureBox.Height * 0.90F / zoom);
pictureBox.Refresh();
break;
}
}
return base.ProcessCmdKey(ref msg, keyData);
}
private void ImageZoomMainForm_Load(object sender, EventArgs e)
{
}
}
}

A picturebox inside a Panel,
the panel should be set its AutoSroll to True,
the picturebox with SizeMode to Zoom
the trackbar change can increase and decrease the size of inside picturebox so that the outer panel will have auto scroll
dragging also possible using several mouse events of the picturebox.

Related

Zoom and translate an Image from the mouse location

Issue: Attempting to zoom (scale) an Image from (or at the) mouse location using transforms in the Paint event to translate bitmap origin to mouse location, then scale the Image and translate its origin back.
The Image jumps and fails to scale from the relocated origin when translating the mouse location.
Rotate, scale, and pan function correctly without translating to the the mouse location.
Running on .Net 4.7.2, using Visual Studio in Windows 10 1909
v18363.778
The relevant code blocks:
private void trackBar1_Scroll(object sender, EventArgs e)
{
// Get rotation angle
ang = trackBar1.Value;
pnl1.Invalidate();
}
private void pnl1_MouseWheel(object sender, MouseEventArgs e)
{
// Get mouse location
mouse = e.location;
// Get new scale (zoom) factor
zoom = (float)(e.Delta > 0 ? zoom * 1.05 : zoom / 1.05);
pnl1.Invalidate();
}
private void pnl1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left) return;
pan = true;
mouX = e.X;
mouY = e.Y;
oldX = imgX;
oldY = imgY;
}
private void pnl1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left || !pan) return;
// Coordinates of panned image
imgX = oldX + e.X - mouX;
imgY = oldY + e.Y - mouY;
pnl1.Invalidate();
}
private void pnl1_MouseUp(object sender, MouseEventArgs e)
{
pan = false;
}
private void pnl1_Paint(object sender, PaintEventArgs e)
{
// Apply rotation angle # center of bitmap
e.Graphics.TranslateTransform(img.Width / 2, img.Height / 2);
e.Graphics.RotateTransform(ang);
e.Graphics.TranslateTransform(-img.Width / 2, -img.Height / 2);
// Apply scaling factor - focused # mouse location
e.Graphics.TranslateTransform(mouse.X, mouse.Y, MatrixOrder.Append);
e.Graphics.ScaleTransform(zoom, zoom, MatrixOrder.Append);
e.Graphics.TranslateTransform(-mouse.X, -mouse.Y, MatrixOrder.Append);
// Apply drag (pan) location
e.Graphics.TranslateTransform(imgX, imgY, MatrixOrder.Append);
// Draw "bmp" # location
e.Graphics.DrawImage(img, 0, 0);
}
A few suggestions and a couple of tricks.
Not exactly tricks, just some methods to speed up the calculations when more than one graphic transformation is in place.
Divide and conquer: split the different graphics effects and transformations in different, specialized, methods that do one thing. Then design in a way that makes it possible for these methods to work together when needed.
Keep it simple: when Graphics objects need to accumulate more than a couple of transformations, the order in which Matrices are stacked can cause misunderstandings. It's simpler (and less prone to generate weird outcomes) to calculate some generic transformations (translate and scale, mostly) beforehand, then let GDI+ render already pre-cooked objects and shapes.
Here, only Matrix.RotateAt and Matrix.Multiply are used.
Some notes about Matrix transformations here: Flip the GraphicsPath
Use the right tools: for example, a Panel used as canvas is not exactly the best choice. This Control is not double-buffered; this feature can be enabled, but the Panel class is not meant for drawing, while a PictureBox (or a non-System flat Label) supports it on its own.
Some more notes here: How to apply a fade transition effect to Images
The sample code shows 4 zoom methods, plus generates rotation transformations (which work side-by-side, don't accumulate).
The Zoom modes are selected using an enumerator (private enum ZoomMode):
Zoom modes:
ImageLocation: Image scaling is performed in-place, keeping the current Location on the canvas in a fixed position.
CenterCanvas: while the Image is scaled, it remains centered on the Canvas.
CenterMouse: the Image is scaled and translated to center itself on the current Mouse location on the Canvas.
MouseOffset: the Image is scaled and translated to maintain a relative position determined by the initial location of the Mouse pointer on the Image itself.
You can notice that the code simplifies all the calculations, applying translations exclusively relative to the Rectangle that defines the current Image bounds and only in relation to the Location of this shape.
The Rectangle is only scaled when the calculation needs to preemptively determine what the Image size will be after the Mouse Wheel has generated the next Zoom factor.
Visual sample of the implemented functionalities:
Sample code:
canvas is the Custom Control, derived from PictureBox (you can find its definition at the bottom). This control is added to the Form in code, here. Modify as needed.
trkRotationAngle is the TrackBar used to define the current rotation of the Image. Add this control to the Form in the designer.
radZoom_CheckedChanged is the event handler of all the RadioButtons used to set the current Zoom Mode. The value these Controls set is assigned in their Tag property. Add these controls to the Form in the designer.
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Windows.Forms;
public partial class frmZoomPaint : Form
{
private float rotationAngle = 0.0f;
private float zoomFactor = 1.0f;
private float zoomStep = .05f;
private RectangleF imageRect = RectangleF.Empty;
private PointF imageLocation = PointF.Empty;
private PointF mouseLocation = PointF.Empty;
private Bitmap drawingImage = null;
private PictureBoxEx canvas = null;
private ZoomMode zoomMode = ZoomMode.ImageLocation;
private enum ZoomMode
{
ImageLocation,
CenterCanvas,
CenterMouse,
MouseOffset
}
public frmZoomPaint()
{
InitializeComponent();
string imagePath = [Path of the Image];
drawingImage = (Bitmap)Image.FromStream(new MemoryStream(File.ReadAllBytes(imagePath)));
imageRect = new RectangleF(Point.Empty, drawingImage.Size);
canvas = new PictureBoxEx(new Size(555, 300));
canvas.Location = new Point(10, 10);
canvas.MouseWheel += canvas_MouseWheel;
canvas.MouseMove += canvas_MouseMove;
canvas.MouseDown += canvas_MouseDown;
canvas.MouseUp += canvas_MouseUp;
canvas.Paint += canvas_Paint;
Controls.Add(canvas);
}
private void canvas_MouseWheel(object sender, MouseEventArgs e)
{
mouseLocation = e.Location;
float zoomCurrent = zoomFactor;
zoomFactor += e.Delta > 0 ? zoomStep : -zoomStep;
if (zoomFactor < .10f) zoomStep = .01f;
if (zoomFactor >= .10f) zoomStep = .05f;
if (zoomFactor < .0f) zoomFactor = zoomStep;
switch (zoomMode) {
case ZoomMode.CenterCanvas:
imageRect = CenterScaledRectangleOnCanvas(imageRect, canvas.ClientRectangle);
break;
case ZoomMode.CenterMouse:
imageRect = CenterScaledRectangleOnMousePosition(imageRect, e.Location);
break;
case ZoomMode.MouseOffset:
imageRect = OffsetScaledRectangleOnMousePosition(imageRect, zoomCurrent, e.Location);
break;
default:
break;
}
canvas.Invalidate();
}
private void canvas_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left) return;
mouseLocation = e.Location;
imageLocation = imageRect.Location;
canvas.Cursor = Cursors.NoMove2D;
}
private void canvas_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left) return;
imageRect.Location =
new PointF(imageLocation.X + (e.Location.X - mouseLocation.X),
imageLocation.Y + (e.Location.Y - mouseLocation.Y));
canvas.Invalidate();
}
private void canvas_MouseUp(object sender, MouseEventArgs e) =>
canvas.Cursor = Cursors.Default;
private void canvas_Paint(object sender, PaintEventArgs e)
{
var drawingRect = GetDrawingImageRect(imageRect);
using (var mxRotation = new Matrix())
using (var mxTransform = new Matrix()) {
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
e.Graphics.PixelOffsetMode = PixelOffsetMode.Half;
mxRotation.RotateAt(rotationAngle, GetDrawingImageCenterPoint(drawingRect));
mxTransform.Multiply(mxRotation);
e.Graphics.Transform = mxTransform;
e.Graphics.DrawImage(drawingImage, drawingRect);
}
}
private void trkRotationAngle_ValueChanged(object sender, EventArgs e)
{
rotationAngle = trkAngle.Value;
canvas.Invalidate();
canvas.Focus();
}
private void radZoom_CheckedChanged(object sender, EventArgs e)
{
var rad = sender as RadioButton;
if (rad.Checked) {
zoomMode = (ZoomMode)int.Parse(rad.Tag.ToString());
}
canvas.Focus();
}
#region Drawing Methods
public RectangleF GetScaledRect(RectangleF rect, float scaleFactor) =>
new RectangleF(rect.Location,
new SizeF(rect.Width * scaleFactor, rect.Height * scaleFactor));
public RectangleF GetDrawingImageRect(RectangleF rect) =>
GetScaledRect(rect, zoomFactor);
public PointF GetDrawingImageCenterPoint(RectangleF rect) =>
new PointF(rect.X + rect.Width / 2, rect.Y + rect.Height / 2);
public RectangleF CenterScaledRectangleOnCanvas(RectangleF rect, RectangleF canvas)
{
var scaled = GetScaledRect(rect, zoomFactor);
rect.Location = new PointF((canvas.Width - scaled.Width) / 2,
(canvas.Height - scaled.Height) / 2);
return rect;
}
public RectangleF CenterScaledRectangleOnMousePosition(RectangleF rect, PointF mousePosition)
{
var scaled = GetScaledRect(rect, zoomFactor);
rect.Location = new PointF(mousePosition.X - (scaled.Width / 2),
mousePosition.Y - (scaled.Height / 2));
return rect;
}
public RectangleF OffsetScaledRectangleOnMousePosition(RectangleF rect, float currentZoom, PointF mousePosition)
{
var currentRect = GetScaledRect(imageRect, currentZoom);
if (!currentRect.Contains(mousePosition)) return rect;
float scaleRatio = currentRect.Width / GetScaledRect(rect, zoomFactor).Width;
PointF mouseOffset = new PointF(mousePosition.X - rect.X, mousePosition.Y - rect.Y);
PointF scaledOffset = new PointF(mouseOffset.X / scaleRatio, mouseOffset.Y / scaleRatio);
PointF position = new PointF(rect.X - (scaledOffset.X - mouseOffset.X),
rect.Y - (scaledOffset.Y - mouseOffset.Y));
rect.Location = position;
return rect;
}
#endregion
}
The simple PictureBoxEx custom control (modify and extend as needed):
This PictureBox is selectable, so it can be focused, with a Mouse click
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
[DesignerCategory("Code")]
public class PictureBoxEx : PictureBox
{
public PictureBoxEx() : this (new Size(200, 200)){ }
public PictureBoxEx(Size size) {
SetStyle(ControlStyles.Selectable | ControlStyles.UserMouse, true);
BorderStyle = BorderStyle.FixedSingle;
Size = size;
}
}
#Jimi: Thank you for the detailed information - very useful for visualizing the concepts involved in the graphics manipulations. I had arrived at a functioning solution (see code below) however, your code utilizes steps with greater efficiency. Admittedly, my code is developed with more of an intent to learn the mechanics of image manipulation - as I am still at the early part of the learning curve. Nonetheless, your illustration of the mechanics and techniques is extremely helpful.
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace ZoomImage
{
public partial class Form1 : Form
{
Image img;
Bitmap bmp;
float ang = 0;
float zoom = 1;
bool pan;
bool? ctr = false;
Point mcurrent;
PointF mouse;
PointF image;
PointF _image;
PointF rotate;
public Form1()
{
InitializeComponent();
MouseWheel += mouseWheel;
img = Image.FromFile(#"C:\testimage.jpg");
bmp = new Bitmap(img);
// Set initial scale to fit canvas window
float wRatio = (float)pbx.Width / (float)img.Width;
float hRatio = (float)pbx.Height / (float)img.Height;
zoom = Math.Min(wRatio, hRatio);
image.X = (pbx.Width - zoom * img.Width) / 2;
image.Y = (pbx.Height - zoom * img.Height) / 2;
}
private void label()
{
string _imgX = string.Format("{0:000}", image.X);
string _imgY = string.Format("{0:000}", image.Y);
lbl1.Text = "Location: " + _imgX + ", " + _imgY + "\r\nRotation: " + ang + "\r\nZoom: " + zoom + "\r\nMouse: " + mcurrent.X + ", " + mcurrent.Y;
}
private void btnRotate_Click(object sender, EventArgs e)
{
if (ModifierKeys == Keys.Control)
{
string msg = "Set center of rotation point:\r\n\nMove mouse to desired center ";
msg += "of rotation then hold \"Alt\" and left-click.\r\n\n";
msg += "To restore center of rotation to center of image:\r\n\nHold \"Shift\" and";
msg += " click \"Rotate\".";
MessageBox.Show(msg,"Change center of rotation");
ctr = null;
pbx.Focus();
return;
}
else if (ModifierKeys == Keys.Shift)
{
ctr = false;
return;
}
ang = ang == 270 ? 0 : ang += 90;
if (ang > 360) ang -= 360;
trackBar1.Value = (int)ang;
ctr = ctr == null ? false : ctr;
if (ctr == false) rotate = new PointF(img.Width / 2, img.Height / 2);
pbx.Invalidate();
}
private void trackBar1_Scroll(object sender, EventArgs e)
{
ang = trackBar1.Value;
if (ctr == false) rotate = new PointF(img.Width / 2, img.Height / 2);
pbx.Invalidate();
}
private void mouseWheel(object sender, MouseEventArgs e)
{
mouse = new PointF(e.X - image.X, e.Y - image.Y);
float zinc = 0.05f;
float zfac = 1 + zinc;
zoom = (float)(e.Delta > 0 ? zoom * (zfac) : zoom / (zfac));
// Adjust "img" (bitmap) orgin to maintain fixed focus # mouse location
if (e.Delta > 0)
{
image.X -= zinc * mouse.X;
image.Y -= zinc * mouse.Y;
}
else
{
image.X += (1 - 1 / (zfac)) * mouse.X;
image.Y += (1 - 1 / (zfac)) * mouse.Y;
}
image = new PointF(image.X, image.Y);
pbx.Invalidate();
}
private void mouseDown(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left) return;
if (ModifierKeys == Keys.Alt && ctr == null)
{
ctr = true;
rotate = new PointF((e.X - image.X) / zoom, (e.Y - image.Y) / zoom);
return;
}
pan = true;
mouse = e.Location;
_image = image;
}
private void mouseMove(object sender, MouseEventArgs e)
{
mcurrent = e.Location;
label();
if (e.Button != MouseButtons.Left || !pan) return;
image.X = _image.X + e.X - mouse.X;
image.Y = _image.Y + e.Y - mouse.Y;
image = new PointF(image.X, image.Y);
pbx.Invalidate();
}
private void mouseUp(object sender, MouseEventArgs e)
{
pan = false;
}
private void pbx_Paint(object sender, PaintEventArgs e)
{
label();
// Generate bitmap "bmp" - this can be saved as drawn...if deisred
bmp = new Bitmap(img.Width, img.Height);
using (Graphics g = Graphics.FromImage(bmp))
{
Matrix transform = new Matrix();
transform.Scale(zoom, zoom, MatrixOrder.Append);
transform.RotateAt(ang, rotate);
transform.Translate(image.X, image.Y, MatrixOrder.Append);
g.Transform = transform;
g.DrawImage(img, 0, 0);
}
e.Graphics.DrawImage(bmp, 0, 0);
}
}
}

Issues with flickering C#

I'm having trouble with a Bitmap flicking when it's moved or resized. I'm basically making a paint type application which will also include layers similar to that of photoshop.
I've set the scroll wheel to zoom/resize the Bitmap and set the middle mouse button to move the panel while it is held down and moving.
I have a panel with a checkered background image which is set to tile. This is so that the background pattern stays the same size when resizing.
This panel is basically used to set the size of a Bitmap and have a background.
Here is a video of of the issue:
https://youtu.be/HRcCGaPmNU0
Here is the script that draws and moves with the irrelevant stuff removed.
public Canvas()
{
InitializeComponent();
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.MouseWheel += new MouseEventHandler(Canvas_WheelZoom);
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer | ControlStyles.SupportsTransparentBackColor, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
}
private void panel_DrawArea_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
Graphics g;
g = e.Graphics;
//--------LAYERS--------//
layerCount = layerBMPs.Count;
if (layerCount > 0)
{
for (int i = 0; i < layerCount; i++)
{
Console.WriteLine("Draw Layer");
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half;
g.DrawImage(layerBMPs[i], 0, 0, canvasSize.Width, canvasSize.Height);
}
}
//--------LAYERS--------//
//--------GRID--------//
Console.WriteLine("Draw Grid");
Bitmap gridArea;
gridArea = new Bitmap(canvasSize.Width, canvasSize.Height);
Pen myPen = new Pen(Brushes.Black);
int tileCountX = canvasSize.Width / tileSize.Width;
int tileCountY = canvasSize.Height / tileSize.Height;
for (int i = 0; i < tileCountX; i++)
{
g.DrawLine(myPen, i * tileSize.Width * canvasScale, 0, i * tileSize.Width * canvasScale, canvasSize.Height);
}
for (int j = 0; j < tileCountY; j++)
{
g.DrawLine(myPen, 0, j * tileSize.Height * canvasScale, canvasSize.Width, j * tileSize.Height * canvasScale);
}
//--------GRID--------//
g.Dispose();
myPen.Dispose();
}
//Clicking the canvas
private void panel_DrawArea_MouseDown(object sender, MouseEventArgs e)
{
//Detect which mouse button is pressed
switch(MouseButtons)
{
case MouseButtons.Middle:
//Move Canvas
canvasMove = 1;
canvasMoveX = e.X;
canvasMoveY = e.Y;
break;
}
}
private void panel_DrawArea_MouseMove(object sender, MouseEventArgs e)
{
//Detect which mouse button is pressed
switch (MouseButtons)
{
case MouseButtons.Middle:
//Move Canvas
if (canvasMove == 1)
{
int xPos = Cursor.Position.X - canvasMoveX - this.Location.X;
int yPos = Cursor.Position.Y - canvasMoveY - this.Location.Y - 16;
drawAreaPos = new Point(xPos, yPos);
panel_DrawArea.Refresh(); <--- This makes it flicker really fast when moving or resizing.
//panel_DrawArea.Invalidate(); <--- Does nothing
}
break;
}
}
private void panel_DrawArea_MouseUp(object sender, MouseEventArgs e)
{
switch (MouseButtons)
{
case MouseButtons.Middle:
//Move Canvas
canvasMove = 0;
break;
}
}
So basically what happens here is that the list contains bitmaps. The loop in the draw event draws those bitsmaps. Once all of them have been drawn then the grip is drawn on top.
I've tried double buffering and endless ammounts of playing about with no success.
Is anyone able to help?
Thanks

Form position on lower right corner of the screen

I am using c# WinForm to develop a sman notification app. I would like to place the main form on the lower right corner of the screen working area.
In case of multiple screens, there is a way to find the rightmost screen where to place the app, or at least remember the last used screen and palce the form on its lower right corner?
I don't currently have multiple displays to check, but it should be something like
public partial class LowerRightForm : Form
{
public LowerRightForm()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
PlaceLowerRight();
base.OnLoad(e);
}
private void PlaceLowerRight()
{
//Determine "rightmost" screen
Screen rightmost = Screen.AllScreens[0];
foreach (Screen screen in Screen.AllScreens)
{
if (screen.WorkingArea.Right > rightmost.WorkingArea.Right)
rightmost = screen;
}
this.Left = rightmost.WorkingArea.Right - this.Width;
this.Top = rightmost.WorkingArea.Bottom - this.Height;
}
}
Override the Form Onload and set the new location :
protected override void OnLoad(EventArgs e)
{
var screen = Screen.FromPoint(this.Location);
this.Location = new Point(screen.WorkingArea.Right - this.Width, screen.WorkingArea.Bottom - this.Height);
base.OnLoad(e);
}
//Get screen resolution
Rectangle res = Screen.PrimaryScreen.Bounds;
// Calculate location (etc. 1366 Width - form size...)
this.Location = new Point(res.Width - Size.Width, res.Height - Size.Height);
This following code should work :)
var rec = Screen.PrimaryScreen.WorkingArea;
int margain = 10;
this.Location = new Point(rec.Width - (this.Width + margain), rec.Height - (this.Height + margain));
int x = Screen.PrimaryScreen.WorkingArea.Right - this.Width;
int y = Screen.PrimaryScreen.WorkingArea.Bottom - this.Height;
// Add this for the real edge of the screen:
x = 0; // for Left Border or Get the screen Dimension to set it on the Right
this.Location = new Point(x, y);

How to zoom in using Mouse Position on that image

I have a userControl library, which consists of the main Panel and a PictureBox, I want to make a zoomable PictureBox tool, I zoom in and out using mouseWheel event of the main Panel, the problem that I can't figure out how do I zoom in by the mouse position on the image, so whenever I zoom in, the zoom goes the Top-Left corner of the panel, so how do I fix that?
private double ZOOMFACTOR = 1.15; // = 15% smaller or larger
private int MINMAX = 5;
void picPanel_MouseWheel(object sender, MouseEventArgs e)
{
if (e.Delta > 0)
{
ZoomIn();
}
else
{
ZoomOut();
}
}
private void ZoomIn()
{
if ((picBox.Width < (MINMAX * this.Width)) &&
(picBox.Height < (MINMAX * this.Height)))
{
picBox.Width = Convert.ToInt32(picBox.Width * ZOOMFACTOR);
picBox.Height = Convert.ToInt32(picBox.Height * ZOOMFACTOR);
}
}
private void picBox_MouseEnter(object sender, EventArgs e)
{
if (picBox.Focused) return;
picBox.Focus();
}
Update :
I have tried this, it looks like working, but not exactly as it should be!! Any ideas?
private void ZoomIn()
{
if ((picBox.Width < (MINMAX * this.Width)) &&
(picBox.Height < (MINMAX * this.Height)))
{
picBox.Width = Convert.ToInt32(picBox.Width * ZOOMFACTOR);
picBox.Height = Convert.ToInt32(picBox.Height * ZOOMFACTOR);
Point p = this.AutoScrollPosition;
int deltaX = e.X - p.X;
int deltaY = e.Y - p.Y;
this.AutoScrollPosition = new Point(deltaX, deltaY);
}
}
This is the example of Zoom image on mouse position....
tested verified.
protected override void OnMouseWheel(MouseEventArgs ea)
{
// flag = 1;
// Override OnMouseWheel event, for zooming in/out with the scroll wheel
if (picmap1.Image != null)
{
// If the mouse wheel is moved forward (Zoom in)
if (ea.Delta > 0)
{
// Check if the pictureBox dimensions are in range (15 is the minimum and maximum zoom level)
if ((picmap1.Width < (15 * this.Width)) && (picmap1.Height < (15 * this.Height)))
{
// Change the size of the picturebox, multiply it by the ZOOMFACTOR
picmap1.Width = (int)(picmap1.Width * 1.25);
picmap1.Height = (int)(picmap1.Height * 1.25);
// Formula to move the picturebox, to zoom in the point selected by the mouse cursor
picmap1.Top = (int)(ea.Y - 1.25 * (ea.Y - picmap1.Top));
picmap1.Left = (int)(ea.X - 1.25 * (ea.X - picmap1.Left));
}
}
else
{
// Check if the pictureBox dimensions are in range (15 is the minimum and maximum zoom level)
if ((picmap1.Width > (imagemappan.Width)) && (picmap1.Height > (imagemappan.Height)))
{
// Change the size of the picturebox, divide it by the ZOOMFACTOR
picmap1.Width = (int)(picmap1.Width / 1.25);
picmap1.Height = (int)(picmap1.Height / 1.25);
// Formula to move the picturebox, to zoom in the point selected by the mouse cursor
picmap1.Top = (int)(ea.Y - 0.80 * (ea.Y - picmap1.Top));
picmap1.Left = (int)(ea.X - 0.80 * (ea.X - picmap1.Left));
}
}
}
}
The problem is that your control is acting like a viewport - the origin is top left, so every time you stretch the image you're doing it from that corner - the upshot is you wind up zooming into the top left corner, you need to offset the stretched image and centre the point the user zoomed in on.
image size: 200,200
user clicks 100,50 and zooms in x2
stretch the image
image size 400,400, and the place the user clicked is now effectively at 200,100
you need to slide the image 100 px left and 50 px up to correct for re-sizing the image
You'll need to override the paint event handler to draw the image offset:
RectangleF BmpRect = new RectangleF((float)(Offset.X), (float)(Offset.Y), (float)(ZoomedWidth), (float)(ZoomedHeight));
e.Graphics.DrawImage(Bmp, ViewPort , BmpRect, GraphicsUnit.Pixel);
Bmp is your image; ViewPort is a Rectangle defined by your pictureBox control
Here is a thread that might help.

How to resize form in scale? C#

i need that in my form the width is twice the height (1:2) also when i resize
How i can do that?
Thanks for help and sorry for my english :)
Check out this post: Resizing forms while keeping aspect ratio.
The key is to respond to the WM_SIZING message, it allows you to change the window rectangle.
public partial class MyForm : Form
{
public MyForm()
{
InitializeComponent();
// Necessary to take the window frame width/height into account
this.chromeWidth = this.Width - this.ClientSize.Width;
this.chromeHeight = this.Height - this.ClientSize.Height;
this.ClientSize = new System.Drawing.Size(400, 200);
}
// ...
#region Resizer
private float constantWidth = 2;
private float constantHeight = 1;
private int chromeWidth;
private int chromeHeight;
// From Windows SDK
private const int WM_SIZING = 0x214;
private const int WMSZ_LEFT = 1;
private const int WMSZ_RIGHT = 2;
private const int WMSZ_TOP = 3;
private const int WMSZ_BOTTOM = 6;
struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_SIZING)
{
RECT rc = (RECT)Marshal.PtrToStructure(m.LParam, typeof(RECT));
int w = rc.Right - rc.Left - chromeWidth;
int h = rc.Bottom - rc.Top - chromeHeight;
switch (m.WParam.ToInt32()) // Resize handle
{
case WMSZ_LEFT:
case WMSZ_RIGHT:
// Left or right handles, adjust height
rc.Bottom = rc.Top + chromeHeight + (int)(constantHeight * w / constantWidth);
break;
case WMSZ_TOP:
case WMSZ_BOTTOM:
// Top or bottom handles, adjust width
rc.Right = rc.Left + chromeWidth + (int)(constantWidth * h / constantHeight);
break;
case WMSZ_LEFT + WMSZ_TOP:
case WMSZ_LEFT + WMSZ_BOTTOM:
// Top-left or bottom-left handles, adjust width
rc.Left = rc.Right - chromeWidth - (int)(constantWidth * h / constantHeight);
break;
case WMSZ_RIGHT + WMSZ_TOP:
// Top-right handle, adjust height
rc.Top = rc.Bottom - chromeHeight - (int)(constantHeight * w / constantWidth);
break;
case WMSZ_RIGHT + WMSZ_BOTTOM:
// Bottom-right handle, adjust height
rc.Bottom = rc.Top + chromeHeight + (int)(constantHeight * w / constantWidth);
break;
}
Marshal.StructureToPtr(rc, m.LParam, true);
}
base.WndProc(ref m);
}
#endregion
}
Use a TableLayoutControl to host your other controls. This works similarly to the HTML table.
You add your controls to a cell in the table, and then you can add ColumnStyles and RowStyles in which you can set the width and height of the cells. The measurments can be specified as auto, absolute or percentage. Percentage is the one that you really need here.
You then set this TableLayoutControl's dock to resize with your window, and the cells will get resized proportionally according to the percentages you set earlier.
To have the actual components resize as well, you have to set either of their Dock or Anchor properties. Any configuration that specifies how a control should be resized with respect to the cell it's in will work, e.g. you might want to have the controls resize only vertically in the cell and still remain the same width by setting the control's Anchor property to
AnchorStyle.Top | AnchorStyle.Bottom
In a nutshell:
Set how the control will be resized with respect to its cell
Set how the cells will be resized with respect to the TableLayoutControl (using ColumnStyles and RowStyles)
Set how the TableLayoutControl will be resized with respect to the form
More information can be found here: http://msdn.microsoft.com/en-us/vstudio/bb798032.aspx
Checkout the Control.Resize event -- also
private void Form1_Resize(object sender, System.EventArgs e)
{
Control control = (Control)sender;
control.Width = control.Height * 2;
}
Register to the resize event and literally do this:
this.ClientSize.Width = this.ClientSize.Height * 2;
or for the full form size (including borders)
this.Size.Width = this.Size.Height * 2;
You can use events such as onLoad, onClick and so others, to do resizing on certain conditions. So basically its up to you then.
There is some standard form properties height and width, so you can adjust these properties.
For example:
private void frmMain_Load(object sender, EventArgs e)
{
int height = 500;
frmMain.ActiveForm.Height = height;
frmMain.ActiveForm.Width = height / 2;
}
for resize the form below is better one
http://niravdaraniya.blogspot.in/2013/07/how-to-resize-form-in-cnet.html

Categories