I'm trying to make a canvas where you can zoom and pan. The panning works, but zooming at the mouse position won't work.
EDIT: This almost works. The center for zoom is slightly offset however...
This is the code for the zooming:
public partial class Form1 : Form
{
PointF mouseDown;
float newX;
float newY;
float zoomFactor = 1.0F;
public Form1()
{
InitializeComponent();
mouseDown = new PointF(0F, 0F);
this.panel1.Paint += new PaintEventHandler(panel1_Paint);
this.panel1.MouseDown += new System.Windows.Forms.MouseEventHandler(panel1_MouseDown);
this.panel1.MouseMove += new System.Windows.Forms.MouseEventHandler(panel1_MouseMove);
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
base.OnPaint(e);
Graphics dc = e.Graphics;
dc.SmoothingMode = SmoothingMode.AntiAlias;
dc.TranslateTransform(newX, newY);
dc.ScaleTransform(zoomFactor, zoomFactor);
Color lineColor = Color.FromArgb(200, 200, 200);
Pen linePen = new Pen(lineColor,1*zoomFactor);
dc.DrawLine(linePen, 100, 100, 200, 200);
textBox1.Text = newX.ToString();
textBox2.Text = newY.ToString();
}
private void panel1_MouseDown(object sender, EventArgs e)
{
MouseEventArgs mouse = e as MouseEventArgs;
if (mouse.Button == MouseButtons.Right)
{
mouseDown = mouse.Location;
mouseDown.X = mouseDown.X - newX;
mouseDown.Y = mouseDown.Y - newY;
}
}
private void panel1_MouseMove(object sender, EventArgs e)
{
MouseEventArgs mouse = e as MouseEventArgs;
if (mouse.Button == MouseButtons.Right)
{
Point mousePosNow = mouse.Location;
float deltaX = mousePosNow.X - mouseDown.X;
float deltaY = mousePosNow.Y - mouseDown.Y;
newX = deltaX;
newY = deltaY;
panel1.Invalidate();
}
}
protected override void OnMouseWheel(MouseEventArgs e)
{
MouseEventArgs mouse = e as MouseEventArgs;
if (e.Delta > 0)
{
if (zoomFactor + 0.2 < 10)
{
zoomFactor += 0.2F;
}
}
else if (e.Delta < 0)
{
if (zoomFactor - 0.2 > 0.2)
{
zoomFactor -= 0.2F;
}
}
float x = (mouse.Location.X - newX) * zoomFactor;
float y = (mouse.Location.Y - newY) * zoomFactor;
newX = mouse.Location.X - x;
newY = mouse.Location.Y - y;
panel1.Invalidate();
}
}
I finally figured it out, so here's the solution.
public partial class Form1 : Form
{
PointF mouseDown;
float newX;
float newY;
float zoomFactor = 1.0F;
public Form1()
{
InitializeComponent();
mouseDown = new PointF(0F, 0F);
this.panel1.Paint += new PaintEventHandler(panel1_Paint);
this.panel1.MouseDown += new System.Windows.Forms.MouseEventHandler(panel1_MouseDown);
this.panel1.MouseMove += new System.Windows.Forms.MouseEventHandler(panel1_MouseMove);
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
base.OnPaint(e);
Graphics dc = e.Graphics;
dc.SmoothingMode = SmoothingMode.AntiAlias;
dc.TranslateTransform(newX, newY);
dc.ScaleTransform(zoomFactor, zoomFactor, MatrixOrder.Prepend);
Color lineColor = Color.FromArgb(200, 200, 200);
Pen linePen = new Pen(lineColor,1*zoomFactor);
dc.DrawLine(linePen, 100, 100, 200, 100);
dc.DrawLine(linePen, 200, 100, 200, 200);
dc.DrawLine(linePen, 200, 200, 100, 200);
dc.DrawLine(linePen, 100, 200, 100, 100);
dc.DrawLine(linePen, 100, 100, 200, 200);
dc.DrawLine(linePen, 200, 100, 100, 200);
}
private void panel1_MouseDown(object sender, EventArgs e)
{
MouseEventArgs mouse = e as MouseEventArgs;
if (mouse.Button == MouseButtons.Right)
{
mouseDown = mouse.Location;
mouseDown.X = mouseDown.X - newX;
mouseDown.Y = mouseDown.Y - newY;
}
}
private void panel1_MouseMove(object sender, EventArgs e)
{
MouseEventArgs mouse = e as MouseEventArgs;
if (mouse.Button == MouseButtons.Right)
{
PointF mousePosNow = mouse.Location;
float deltaX = mousePosNow.X - mouseDown.X;
float deltaY = mousePosNow.Y - mouseDown.Y;
newX = deltaX;
newY = deltaY;
panel1.Invalidate();
}
}
protected override void OnMouseWheel(MouseEventArgs e)
{
MouseEventArgs mouse = e as MouseEventArgs;
PointF mP = mouse.Location;
if (e.Delta > 0)
{
if (zoomFactor >= 1 && zoomFactor <= 10)
{
zoomFactor += 1F;
newX = newX - ((mP.X - newX) / (zoomFactor - 1));
newY = newY - ((mP.Y - newY) / (zoomFactor - 1));
}
else if (zoomFactor == 0.5)
{
zoomFactor = zoomFactor * 2;
newX = newX - ((mP.X - newX) );
newY = newY - ((mP.Y - newY) );
}
else if (zoomFactor < 0.5)
{
zoomFactor = zoomFactor * 2;
newX = newX - ((mP.X - newX) );
newY = newY - ((mP.Y - newY) );
}
}
else if (e.Delta < 0)
{
if (zoomFactor >2)
{
zoomFactor -= 1F;
newX = newX + (((mP.X - newX)) / (zoomFactor+1 ));
newY = newY + (((mP.Y - newY)) / (zoomFactor+1));
}
else if (zoomFactor == 2) {
zoomFactor -= 1F;
newX = newX + ((mP.X - newX)/2);
newY = newY + ((mP.Y - newY)/2);
}else if(zoomFactor <= 1 && zoomFactor > 0.2)
{
zoomFactor = zoomFactor / 2;
newX = newX + ((mP.X - newX) / 2);
newY = newY + ((mP.Y - newY) / 2);
}
}
panel1.Invalidate();
}
}
Maybe your MousePosition is different from PanelPosition? I mean on is relative to the control and one relative to the screen?
Control.PointToScreen is your friend!
Related
I have tried using the following code:
pictureBox1.Invalidate();
//or
pictureBox1.Update();
//or
Refresh();
But it just did nothing on it. I want to clear all the drawn graphics on my picture box as after I click the next page I want to draw the new rectangles on it. So, please don't provide me such a solution:
g.FillRectangle(Brushes.Black, new Rectangle(0, 0, pictureBox1.Width, pictureBox1.Height))
or
Graphics.Clear();
Anyone want to share the solution with me? I am appreciated with it.
page 2
page 3
Form2.cs
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Pen pen = new Pen(Color.Red, 2);
e.Graphics.DrawRectangle(pen, rect);
}
bool draw;
int x_start, y_start;
Rectangle rect;
//UserRect rect;
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
}
else if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
pictureBox1.Cursor = Cursors.Cross;
draw = true;
x_start = e.X;
y_start = e.Y;
}
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
}else if(e.Button == MouseButtons.Right)
{
pictureBox1.Cursor = Cursors.Cross;
}
if (!draw) return;
LocalMousePosition = pictureBox1.PointToClient(Cursor.Position);
int x = Math.Min(x_start, LocalMousePosition.X);
int y = Math.Min(y_start, LocalMousePosition.Y);
int width = Math.Max(x_start, LocalMousePosition.X) - Math.Min(x_start, LocalMousePosition.X);
int height = Math.Max(y_start, LocalMousePosition.Y) - Math.Min(y_start, LocalMousePosition.Y);
rect = new Rectangle(x, y, width, height);
xx = x;
yy = y;
ww = width;
hh = height;
Refresh();
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
//pictureBox1.Cursor = Cursors.Default;
draw = false;
rectang = new UserRect(rect);
rect = new Rectangle(e.X, e.Y, 0, 0);
rectang.SetPictureBox(this.pictureBox1);
}
else if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
pictureBox1.Cursor = Cursors.Default;
_tracking = false;
}
}
UserRect.cs
public void Draw(Graphics g)
{
g.DrawRectangle(new Pen(Color.Green), rect);
foreach (PosSizableRect pos in Enum.GetValues(typeof(PosSizableRect)))
{
g.DrawRectangle(new Pen(Color.Red), GetRect(pos));
}
}
public void SetPictureBox(PictureBox p)
{
this.mPictureBox = p;
mPictureBox.MouseDown += new MouseEventHandler(mPictureBox_MouseDown);
mPictureBox.MouseUp += new MouseEventHandler(mPictureBox_MouseUp);
mPictureBox.MouseMove += new MouseEventHandler(mPictureBox_MouseMove);
mPictureBox.Paint += new PaintEventHandler(mPictureBox_Paint);
}
private void mPictureBox_Paint(object sender, PaintEventArgs e)
{
try
{
Draw(e.Graphics);
}
catch (Exception exp)
{
System.Console.WriteLine(exp.Message);
}
}
private void mPictureBox_MouseDown(object sender, MouseEventArgs e)
{
mIsClick = true;
nodeSelected = PosSizableRect.None;
nodeSelected = GetNodeSelectable(e.Location);
if (rect.Contains(new Point(e.X, e.Y)))
{
mMove = true;
}
oldX = e.X;
oldY = e.Y;
}
private void mPictureBox_MouseUp(object sender, MouseEventArgs e)
{
//MessageBox.Show(rect.ToString());
mIsClick = false;
mMove = false;
}
private void mPictureBox_MouseMove(object sender, MouseEventArgs e)
{
ChangeCursor(e.Location);
if (mIsClick == false)
{
return;
}
Rectangle backupRect = rect;
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
switch (nodeSelected)
{
case PosSizableRect.LeftUp:
rect.X += e.X - oldX;
rect.Width -= e.X - oldX;
rect.Y += e.Y - oldY;
rect.Height -= e.Y - oldY;
break;
case PosSizableRect.LeftMiddle:
rect.X += e.X - oldX;
rect.Width -= e.X - oldX;
break;
case PosSizableRect.LeftBottom:
rect.Width -= e.X - oldX;
rect.X += e.X - oldX;
rect.Height += e.Y - oldY;
break;
case PosSizableRect.BottomMiddle:
rect.Height += e.Y - oldY;
break;
case PosSizableRect.RightUp:
rect.Width += e.X - oldX;
rect.Y += e.Y - oldY;
rect.Height -= e.Y - oldY;
break;
case PosSizableRect.RightBottom:
rect.Width += e.X - oldX;
rect.Height += e.Y - oldY;
break;
case PosSizableRect.RightMiddle:
rect.Width += e.X - oldX;
break;
case PosSizableRect.UpMiddle:
rect.Y += e.Y - oldY;
rect.Height -= e.Y - oldY;
break;
default:
if (mMove)
{
rect.X = rect.X + e.X - oldX;
rect.Y = rect.Y + e.Y - oldY;
}
break;
}
}
oldX = e.X;
oldY = e.Y;
if (rect.Width < 5 || rect.Height < 5)
{
rect = backupRect;
}
TestIfRectInsideArea();
mPictureBox.Invalidate();
}
Generally, I would split drawing graphics between _Paint event as you have it (for interactive drawing, such as selection box and mouse-move related stuff) and separate underlaying image.
There are several reasons for that, such as control over what you want to draw (imagine you want to draw only retangle 1, 3 and 5, if a some checkbox is not checked and then draw all of 1 to 6 if it is checked) and performance (with large amount of data).
You can do all of that in _Paint, but it will bloat. In contrast to that, you can split draw task into several functions, which is very handy for large drawing.
Very simplified example - VB.NET:
Dim UnderlayingImage as Image
UnderLayingImage = New Bitmap(Me.PictureBox1.Width, Me.Picturebox1.Height)
Dim g As Graphics = Graphics.FromImage(UnderLayingImage)
Dim bgBrush As SolidBrush = New SolidBrush(Color.LightSlateGray)
Dim bgBrushWhite As SolidBrush = New SolidBrush(Color.White)
Dim shPen As Pen = New Pen(Color.Black)
Dim rect As RectangleF = New RectangleF(50, 50, 100, 100)
g.FillRectangle(bgBrush, rect)
g.DrawRectangle(Pens.Black, Rectangle.Round(rect))
Me.PictureBoxDrawing.Image = UnderLayingImage
Translated to C#:
Image UnderlayingImage;
UnderLayingImage = new Bitmap(this.PictureBox1.Width, this.Picturebox1.Height);
Graphics g = Graphics.FromImage(UnderLayingImage);
SolidBrush bgBrush = new SolidBrush(Color.LightSlateGray);
SolidBrush bgBrushWhite = new SolidBrush(Color.White);
Pen shPen = new Pen(Color.Black);
RectangleF rect = new RectangleF(50, 50, 100, 100);
g.FillRectangle(bgBrush, rect);
g.DrawRectangle(Pens.Black, Rectangle.Round(rect));
this.PictureBoxDrawing.Image = UnderLayingImage;
And back to your question: This way you don't Clear your drawing, but you redraw it and in the process you decide what to include and what to ommit.
i am trying to zoom in and zoom out on a content page using xamarin.forms.
I am able zoom in and zoom out but the problem is scrolling is not working.
i want zoom an image. with this code zooming is working perfectly. But while zooming i am not able to see full image. i must scroll to view the rest of the image. for that i need to scroll. but scrolling is not working.
XAML
xmlns:helper="clr-namespace:KPGTC.Deals.Mobile.Helpers"
<helper:PinchToZoomContainer>
<helper:PinchToZoomContainer.Content>
<Image x:Name="img_Popup"/>
</helper:PinchToZoomContainer.Content>
</helper:PinchToZoomContainer>
Code:
public class PinchToZoomContainer : ContentView
{
double MIN_SCALE = 1;
double MAX_SCALE = 4;
double startScale = 1;
double currentScale = 1;
double xOffset = 0;
double yOffset = 0;
bool _isActive = false;
public PinchToZoomContainer()
{
DependencyService.Get<IHelpers>().ShowAlert("Double-tap to zoom");
//var _pinchGesture = new PinchGestureRecognizer();
//_pinchGesture.PinchUpdated += OnPinchUpdated;
//GestureRecognizers.Add(_pinchGesture);
var _tapGesture = new TapGestureRecognizer { NumberOfTapsRequired = 2 };
_tapGesture.Tapped += On_Tapped;
GestureRecognizers.Add(_tapGesture);
var _panGesture = new PanGestureRecognizer();
_panGesture.PanUpdated += OnPanUpdated;
GestureRecognizers.Add(_panGesture);
TranslationX = 0;
TranslationY = 0;
_isActive = false;
}
private void OnPanUpdated(object sender, PanUpdatedEventArgs e)
{
if (_isActive)
{
if (e.TotalX > 0)
{
if (e.TotalX > 2)
{
TranslationX += 15;
}
}
else
{
if (e.TotalX < -2)
{
TranslationX -= 15;
}
}
}
}
private void On_Tapped(object sender, EventArgs e)
{
if (Scale > MIN_SCALE)
{
_isActive = false;
this.ScaleTo(MIN_SCALE, 250, Easing.CubicInOut);
this.TranslateTo(0, 0, 250, Easing.CubicInOut);
}
else
{
_isActive = true;
AnchorX = AnchorY = 0.5;
this.ScaleTo(MAX_SCALE, 250, Easing.CubicInOut);
}
}
void OnPinchUpdated(object sender, PinchGestureUpdatedEventArgs e)
{
if (e.Status == GestureStatus.Started)
{
startScale = Content.Scale;
Content.AnchorX = 0;
Content.AnchorY = 0;
}
if (e.Status == GestureStatus.Running)
{
currentScale += (e.Scale - 1) * startScale;
currentScale = Math.Max(1, currentScale);
double renderedX = Content.X + xOffset;
double deltaX = renderedX / Width;
double deltaWidth = Width / (Content.Width * startScale);
double originX = (e.ScaleOrigin.X - deltaX) * deltaWidth;
double renderedY = Content.Y + yOffset;
double deltaY = renderedY / Height;
double deltaHeight = Height / (Content.Height * startScale);
double originY = (e.ScaleOrigin.Y - deltaY) * deltaHeight;
double targetX = xOffset - (originX * Content.Width) * (currentScale - startScale);
double targetY = yOffset - (originY * Content.Height) * (currentScale - startScale);
Content.TranslationX = targetX.Clamp(-Content.Width * (currentScale - 1), 0);
Content.TranslationY = targetY.Clamp(-Content.Height * (currentScale - 1), 0);
Content.Scale = currentScale;
}
if (e.Status == GestureStatus.Completed)
{
xOffset = Content.TranslationX;
yOffset = Content.TranslationY;
}
}
}
Alright, this was quite a tough one and admittedly I don't understand fully how I made it, but I made it.
Some thoughts:
You mixed the translation of the container and the content, which is quite tricky to handle - if this is possible at all
When panning, you added 15 every time the pan event was raised, but there is a better way: Just store the initial offset of the content and then add the TotalX and TotalY respectively to the TranslationX and the TranslationY of the content (this was the easy part)
Panning while zooming was quite hard to get right and I had to find it out by trial and error
Basically you have to store the origin of the pinch gesture when the gesture starts and calculate the diff between the original origin and the current origin
Then you have to add the diff (multiplied by the with and height respectively of the control) to the target translation
Here is the code for the panning:
private void OnPanUpdated(object sender, PanUpdatedEventArgs e)
{
if (e.StatusType == GestureStatus.Started)
{
this.xOffset = this.Content.TranslationX;
this.yOffset = this.Content.TranslationY;
}
if (e.StatusType != GestureStatus.Completed
&& e.StatusType != GestureStatus.Canceled)
{
this.Content.TranslationX = this.xOffset + e.TotalX;
this.Content.TranslationY = this.yOffset + e.TotalY;
}
if (e.StatusType == GestureStatus.Completed)
{
this.xOffset = this.Content.TranslationX;
this.yOffset = this.Content.TranslationY;
}
}
And here for the pinching
void OnPinchUpdated(object sender, PinchGestureUpdatedEventArgs e)
{
if (e.Status == GestureStatus.Started)
{
this.startScale = this.Content.Scale;
this.Content.AnchorX = 0;
this.Content.AnchorY = 0;
this.startScaleOrigin = e.ScaleOrigin;
}
if (e.Status == GestureStatus.Running)
{
var originDiff = PinchToZoomContainer.CalculateDiff(e.ScaleOrigin, this.startScaleOrigin);
this.currentScale += (e.Scale - 1) * this.startScale;
this.currentScale = Math.Max(1, this.currentScale);
double renderedX = this.Content.X + this.xOffset;
double deltaX = renderedX / this.Width;
double deltaWidth = this.Width / (this.Content.Width * this.startScale);
double originX = (this.startScaleOrigin.X - deltaX) * deltaWidth;
double renderedY = this.Content.Y + this.yOffset;
double deltaY = renderedY / this.Height;
double deltaHeight = this.Height / (this.Content.Height * this.startScale);
double originY = (startScaleOrigin.Y - deltaY) * deltaHeight;
double targetX = this.xOffset - ((originX) * this.Content.Width) * (this.currentScale - this.startScale) - originDiff.X * this.Content.Width;
double targetY = this.yOffset - ((originY) * this.Content.Height) * (this.currentScale - this.startScale) - originDiff.Y * this.Content.Height;
this.Content.TranslationX = targetX.Clamp(-this.Content.Width * (this.currentScale - 1), 0);
this.Content.TranslationY = targetY.Clamp(-this.Content.Height * (this.currentScale - 1), 0);
this.Content.Scale = this.currentScale;
}
if (e.Status == GestureStatus.Completed)
{
this.xOffset = this.Content.TranslationX;
this.yOffset = this.Content.TranslationY;
}
}
(Of course you have to add Point startScaleOrigin to your class).
Finally you need the method to calculate the distance between two points
private static Point CalculateDiff(Point first, Point second)
{
return second.Offset(-first.X, -first.Y);
}
Unfortunately I did not manage to get the tapping right, but I think you should be able to figure it out from here.
I'm converting a fractal renderer from Java to C# for an assignment and I think I have everything set up but the fractal itself won't render.
This is a photo of when I run the program:
And here is how my files are laid out in the folder that contains the project itself:
This is the code that I am using for the actually rendering itself which I think has no errors but if I've missed something extremely obvious then I'm sorry for wasting all of your time:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
init();
start();
this.DoubleBuffered = true;
}
//code to convert HSB to RGB from HSB.cs. All your code so i made it take up less space.
public struct HSBColor
{
float h;
float s;
float b;
int a;
public HSBColor(float h, float s, float b) { this.a = 0xff; this.h = Math.Min(Math.Max(h, 0), 255); this.s = Math.Min(Math.Max(s, 0), 255); this.b = Math.Min(Math.Max(b, 0), 255); }
public HSBColor(int a, float h, float s, float b) { this.a = a; this.h = Math.Min(Math.Max(h, 0), 255); this.s = Math.Min(Math.Max(s, 0), 255); this.b = Math.Min(Math.Max(b, 0), 255); }
public float H { get { return h; } }
public float S { get { return s; } }
public float B { get { return b; } }
public int A { get { return a; } }
public Color Color { get { return FromHSB(this); } }
public static Color FromHSB(HSBColor hsbColor)
{
float r = hsbColor.b;
float g = hsbColor.b;
float b = hsbColor.b;
if (hsbColor.s != 0)
{
float max = hsbColor.b; float dif = hsbColor.b * hsbColor.s / 255f; float min = hsbColor.b - dif; float h = hsbColor.h * 360f / 255f;
if (h < 60f) { r = max; g = h * dif / 60f + min; b = min; }
else if (h < 120f) { r = -(h - 120f) * dif / 60f + min; g = max; b = min; }
else if (h < 180f) { r = min; g = max; b = (h - 120f) * dif / 60f + min; }
else if (h < 240f) { r = min; g = -(h - 240f) * dif / 60f + min; b = max; }
else if (h < 300f) { r = (h - 240f) * dif / 60f + min; g = min; b = max; }
else if (h <= 360f) { r = max; g = min; b = -(h - 360f) * dif / 60 + min; }
else { r = 0; g = 0; b = 0; }
}
return Color.FromArgb(hsbColor.a, (int)Math.Round(Math.Min(Math.Max(r, 0), 255)), (int)Math.Round(Math.Min(Math.Max(g, 0), 255)), (int)Math.Round(Math.Min(Math.Max(b, 0), 255)));
}
}
private const int MAX = 256; // max iterations
private const double SX = -2.025; // start value real
private const double SY = -1.125; // start value imaginary
private const double EX = 0.6; // end value real
private const double EY = 1.125; // end value imaginary
private static int x1, y1, xs, ys, xe, ye;
private static double xstart, ystart, xende, yende, xzoom, yzoom;
private static float xy;
private int c = 0;
//private Image picture; Taken out, not needed
// create rectangle variable JGB
Rectangle rec;
private Graphics g1;
//private Cursor c1, c2; Taken out, not needed
private System.Drawing.Bitmap bitmap;
public void init()
{
//setSize(640, 480); changed this code to JGB:
this.Size = new Size(640, 480);
// Taken all lines out below. Not needed.
/*finished = false;
addMouseListener(this);
addMouseMotionListener(this);
c1 = new Cursor(Cursor.WAIT_CURSOR);
c2 = new Cursor(Cursor.CROSSHAIR_CURSOR); */
x1 = 640;
y1 = 480;
xy = (float)x1 / (float)y1;
//picture = createImage(x1, y1); Taken out and replaced with JGB:
bitmap = new Bitmap(x1, y1);
//g1 = picture.getGraphics(); changed to get my bitmap
g1 = Graphics.FromImage(bitmap);
//finished = true; Finished variable deleted so not needed
}
//Code below didnt appear to do anything so i deleted it
/*public void destroy() // delete all instances
{
if (finished)
{
removeMouseListener(this);
removeMouseMotionListener(this);
picture = null;
g1 = null;
c1 = null;
c2 = null;
System.gc(); // garbage collection
}
} */
public void start()
{
//action = false;
//rectangle = false;
initvalues();
// added dialog box for instance loading and save varaibles needed for position and zoom to text file
DialogResult dialog = MessageBox.Show("Would You Like to Load Your Last Instance?", "Load Instance?", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
if (dialog == DialogResult.Yes)
{
string[] lines = System.IO.File.ReadAllLines(#"C:\Users\Public\Writelines.txt");
xzoom = System.Convert.ToDouble(lines[0]);
yzoom = System.Convert.ToDouble(lines[1]);
xstart = System.Convert.ToDouble(lines[2]);
ystart = System.Convert.ToDouble(lines[3]);
}
else
{
xzoom = (xende - xstart) / (double)x1;
yzoom = (yende - ystart) / (double)y1;
}
mandelbrot();
}
public void stop()
{
}
/*public void paint(Graphics g, PaintEventArgs e)
{
update(g);
}
public void update(Graphics g)
{
//g.DrawImage(picture, 0, 0);
}*/
private void mandelbrot()
{
int x, y;
float h, b, alt = 0.0f;
Color color;
Pen pen = new Pen(Color.Black);
for (x = 0; x < x1; x += 2)
for (y = 0; y < y1; y++)
{
h = pointcolour(xstart + xzoom * (double)x, ystart + yzoom * (double)y, c);
if (h != alt)
{
b = 1.0f - h * h;
color = HSBColor.FromHSB(new HSBColor(h * 255, 0.8f * 255, b * 255));
pen = new Pen(color);
alt = h;
}
g1.DrawLine(pen, x, y, x + 1, y);
}
}
private float pointcolour(double xwert, double ywert, int j)
{
double r = 0.0, i = 0.0, m = 0.0;
// int j = 0;
while ((j < MAX) && (m < 4.0))
{
j++;
m = r * r - i * i;
i = 2.0 * r * i + ywert;
r = m + xwert;
}
return (float)j / (float)MAX;
}
private void initvalues()
{
xstart = SX;
ystart = SY;
xende = EX;
yende = EY;
if ((float)((xende - xstart) / (yende - ystart)) != xy)
xstart = xende - (yende - ystart) * (double)xy;
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g1 = e.Graphics;
g1.DrawImage(bitmap, 0, 0, x1, y1);
using (Pen pen = new Pen(Color.White, 2))
{
e.Graphics.DrawRectangle(pen, rec);
}
Invalidate();
}
//added load method
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
xe = e.X;
ye = e.Y;
if (xs < xe)
{
if (ys < ye) rec = new Rectangle(xs, ys, (xe - xs), (ye - ys));
else rec = new Rectangle(xs, ye, (xe - xs), (ys - ye));
}
else
{
if (ys < ye) rec = new Rectangle(xe, ys, (xs - xe), (ye - ys));
else rec = new Rectangle(xe, ye, (xs - xe), (ys - ye));
}
this.Invalidate();
}
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
// e.consume();
xs = e.X;
ys = e.Y; // starting point y
this.Invalidate();
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
rec = new Rectangle(0, 0, 0, 0);
if (e.Button == MouseButtons.Left)
{
int z, w;
//e.consume();
//xe = e.X;
//ye = e.Y;
if (xs > xe)
{
z = xs;
xs = xe;
xe = z;
}
if (ys > ye)
{
z = ys;
ys = ye;
ye = z;
}
w = (xe - xs);
z = (ye - ys);
if ((w < 2) && (z < 2)) initvalues();
else
{
if (((float)w > (float)z * xy)) ye = (int)((float)ys + (float)w / xy);
else xe = (int)((float)xs + (float)z * xy);
xende = xstart + xzoom * (double)xe;
yende = ystart + yzoom * (double)ye;
xstart += xzoom * (double)xs;
ystart += yzoom * (double)ys;
}
xzoom = (xende - xstart) / (double)x1;
yzoom = (yende - ystart) / (double)y1;
mandelbrot();
string stringxzoom = xzoom.ToString();
string stringyzoom = yzoom.ToString();
string stringystart = ystart.ToString();
string stringxstart = xstart.ToString();
string[] lines = { stringxzoom, stringyzoom, stringxstart, stringystart };
System.IO.File.WriteAllLines(#"C:\Users\Public\Writelines.txt", lines);
this.Invalidate();
//Repaint();
}
}
private void restartToolStripMenuItem_Click(object sender, EventArgs e)
{
Application.Restart();
}
private void exitToolStripMenuItem1_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void menuToolStripMenuItem_Click(object sender, EventArgs e)
{
}
private void menuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
}
}
}
Change your Form1() code into these
InitializeComponent();
init();
start();
this.DoubleBuffered = true;
this.pictureBox1.Image = bitmap;
You took out the InitializeComponent call (which should be automatically generated) and you never set the resulting bitmap as the image of the pictureBox. Also, you might wanna set the picturebox Size mode to Zoom and enlarge it.
I'm using windows forms chart control and this is the wheel mouse event:
void chart1_MouseWheel(object sender, MouseEventArgs e)
{
if (e.Delta < 0)
{
chart1.ChartAreas[0].AxisX.ScaleView.ZoomReset();
chart1.ChartAreas[0].AxisY.ScaleView.ZoomReset();
}
if (e.Delta > 0)
{
double xMin = chart1.ChartAreas[0].AxisX.ScaleView.ViewMinimum;
double xMax = chart1.ChartAreas[0].AxisX.ScaleView.ViewMaximum;
double yMin = chart1.ChartAreas[0].AxisY.ScaleView.ViewMinimum;
double yMax = chart1.ChartAreas[0].AxisY.ScaleView.ViewMaximum;
double posXStart = chart1.ChartAreas[0].AxisX.PixelPositionToValue(e.Location.X) - (xMax - xMin) / 4;
double posXFinish = chart1.ChartAreas[0].AxisX.PixelPositionToValue(e.Location.X) + (xMax - xMin) / 4;
double posYStart = chart1.ChartAreas[0].AxisY.PixelPositionToValue(e.Location.Y) - (yMax - yMin) / 4;
double posYFinish = chart1.ChartAreas[0].AxisY.PixelPositionToValue(e.Location.Y) + (yMax - yMin) / 4;
chart1.ChartAreas[0].AxisX.ScaleView.Zoom(posXStart, posXFinish);
chart1.ChartAreas[0].AxisY.ScaleView.Zoom(posYStart, posYFinish);
}
}
The problem is in the chart paint event when I draw points and connect them with lines when I use the wheel the points and lines are gone I don't think they are scaling right.
Pen pen = new Pen(Color.Blue, 2.5f);
SolidBrush myBrush = new SolidBrush(Color.Red);
private void chart1_Paint(object sender, PaintEventArgs e)
{
if (paintToCalaculate)
{
Series s = chart1.Series.FindByName("dummy");
if (s == null) s = chart1.Series.Add("dummy");
drawPoints.Clear();
s.Points.Clear();
foreach (PointF p in valuePoints)
{
s.Points.AddXY(p.X, p.Y);
DataPoint pt = s.Points[0];
double x = chart1.ChartAreas[0].AxisX.ValueToPixelPosition(pt.XValue);
double y = chart1.ChartAreas[0].AxisY.ValueToPixelPosition(pt.YValues[0]);
drawPoints.Add(new Point((int)x, (int)y));
s.Points.Clear();
}
paintToCalaculate = false;
chart1.Series.Remove(s);
}
foreach (Point p in drawPoints)
{
e.Graphics.FillEllipse(Brushes.Red, p.X - 2, p.Y - 2, 4, 4);
}
if (drawPoints.Count > 1)
{
e.Graphics.DrawLines(pen, drawPoints.ToArray());
}
}
How can I take care in the wheel mouse event also about the points and lines I draw in the paint event ?
I think you may need to set your 'paintToCalaculate' flag when zooming. It gets turned off during the first paint event and is not turned back on when zooming, so your lines are not being rescaled.
I'm trying to create a canvas for drawing different objects. I've created zoom and pan functions using graphics.scaleTransform and graphics.translateTransform, but i wan't the canvas background (a grid) to allways fill out the entire window, however it does not, using the following code:
EDIT: I've tried using the coordinates in the transformed graphics object, but it seems it won't accept negative numbers?!?
EDIT: This picture explains my problem:
public partial class Form1 : Form
{
PointF mouseDown;
float newX;
float newY;
float zoomFactor = 1F;
Region _rgn;
Graphics _dc;
PointF zoomPoint = new PointF(150, 150);
public Form1()
{
InitializeComponent();
mouseDown = new PointF(0F, 0F);
this.panel1.Paint += new PaintEventHandler(panel1_Paint);
this.panel1.MouseDown += new System.Windows.Forms.MouseEventHandler(panel1_MouseDown);
this.panel1.MouseMove += new System.Windows.Forms.MouseEventHandler(panel1_MouseMove);
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
base.OnPaint(e);
//Graphics bg =
Graphics dc = e.Graphics;
_dc = dc;
dc.SmoothingMode = SmoothingMode.AntiAlias;
Color gridColor = Color.FromArgb(230, 230, 230);
Pen gridPen = new Pen(gridColor, 1);
for (float i = 0; i < this.Height * (zoomFactor); i = i + 30*zoomFactor)
{
dc.DrawLine(gridPen, 0, i, this.Width * (zoomFactor), i);
}
for (float i = 0; i < this.Width * (zoomFactor); i = i + 30*zoomFactor)
{
dc.DrawLine(gridPen, i, 0, i, this.Height * (zoomFactor));
}
dc.TranslateTransform(newX, newY);
dc.ScaleTransform(zoomFactor, zoomFactor, MatrixOrder.Prepend);
float XPosition = 10;
float YPosition = 10;
float CornerRadius = 5;
float Width = 50;
float Height = 50;
Color BoxColor = Color.FromArgb(0, 0, 0);
Pen BoxPen = new Pen(BoxColor, 2);
GraphicsPath Path = new GraphicsPath();
Path.AddLine(XPosition + CornerRadius, YPosition, XPosition + Width - (CornerRadius * 2), YPosition);
Path.AddArc(XPosition + Width - (CornerRadius * 2), YPosition, CornerRadius * 2, CornerRadius * 2, 270, 90);
Path.AddLine(XPosition + Width, YPosition + CornerRadius, XPosition + Width, YPosition + Height - (CornerRadius * 2));
Path.AddArc(XPosition + Width - (CornerRadius * 2), YPosition + Height - (CornerRadius * 2), CornerRadius * 2, CornerRadius * 2, 0, 90);
Path.AddLine(XPosition + Width - (CornerRadius * 2), YPosition + Height, XPosition + CornerRadius, YPosition + Height);
Path.AddArc(XPosition, YPosition + Height - (CornerRadius * 2), CornerRadius * 2, CornerRadius * 2, 90, 90);
Path.AddLine(XPosition, YPosition + Height - (CornerRadius * 2), XPosition, YPosition + CornerRadius);
Path.AddArc(XPosition, YPosition, CornerRadius * 2, CornerRadius * 2, 180, 90);
Path.CloseFigure();
LinearGradientBrush lgb = new LinearGradientBrush(new PointF(XPosition+(Width/2),YPosition), new PointF(XPosition+(Width/2),YPosition + Height), Color.RosyBrown, Color.Red);
dc.FillPath(lgb, Path);
dc.DrawPath(BoxPen, Path);
Matrix transformMatrix = new Matrix();
transformMatrix.Translate(newX, newY);
transformMatrix.Scale(zoomFactor, zoomFactor);
_rgn = new Region(Path);
_rgn.Transform(transformMatrix);
}
private void panel1_MouseDown(object sender, EventArgs e)
{
MouseEventArgs mouse = e as MouseEventArgs;
if (mouse.Button == MouseButtons.Right)
{
mouseDown = mouse.Location;
mouseDown.X = mouseDown.X - newX;
mouseDown.Y = mouseDown.Y - newY;
}
else if (mouse.Button == MouseButtons.Left)
{
if (_rgn.IsVisible(mouse.Location, _dc))
{
MessageBox.Show("tada");
}
}
}
private void panel1_MouseMove(object sender, EventArgs e)
{
MouseEventArgs mouse = e as MouseEventArgs;
if (mouse.Button == MouseButtons.Right)
{
PointF mousePosNow = mouse.Location;
float deltaX = mousePosNow.X - mouseDown.X;
float deltaY = mousePosNow.Y - mouseDown.Y;
newX = deltaX;
newY = deltaY;
panel1.Invalidate();
}
}
protected override void OnMouseWheel(MouseEventArgs e)
{
MouseEventArgs mouse = e as MouseEventArgs;
PointF mP = mouse.Location;
if (e.Delta > 0)
{
if (zoomFactor >= 1 && zoomFactor <= 10)
{
zoomFactor += 1F;
newX = newX - ((mP.X - newX) / (zoomFactor - 1));
newY = newY - ((mP.Y - newY) / (zoomFactor - 1));
}
else if (zoomFactor == 0.5)
{
zoomFactor = zoomFactor * 2;
newX = 2 * newX - mP.X ;
newY = 2 * newY - mP.Y ;
}
else if (zoomFactor < 0.5)
{
zoomFactor = zoomFactor * 2;
newX = 2 * newX - mP.X;
newY = 2 * newY - mP.Y;
}
}
else if (e.Delta < 0)
{
if (zoomFactor >2)
{
zoomFactor -= 1F;
newX = newX + (((mP.X - newX)) / (zoomFactor+1 ));
newY = newY + (((mP.Y - newY)) / (zoomFactor+1));
}
else if (zoomFactor == 2) {
zoomFactor -= 1F;
newX = newX + ((mP.X - newX)/2);
newY = newY + ((mP.Y - newY)/2);
}else if(zoomFactor <= 1 && zoomFactor > 0.2)
{
zoomFactor = zoomFactor / 2;
newX = newX + ((mP.X - newX) / 2);
newY = newY + ((mP.Y - newY) / 2);
}
}
panel1.Invalidate();
}
}
Draw your GRID BEFORE transforming the coordinate system.
If you can't, use GetTransform() and ResetTransform(), then draw grid, then SetTransform back (the one got in the first step).
IMHO: It would be much better if you scale you image 'manually' instead of using coordinate transformation. You'll have much greater control this way, and won't hit the wall with anything.
EDIT:
Also: you have a bug in your grid drawing routine:
for (float i = 0; i < this.Height * (zoomFactor); i = i + 30*zoomFactor)
try replacing with
for (float i = 0; i < this.Height; i = i + 30*zoomFactor)