I tried to find information on how to use a radial gauge in a windows form report.
I really can't find anything on this. Not sure if there is not much info on this.
Is there anyone who can get me some info on this? How would I be able to use a value from a text box in a report viewer to show this on a radial gauge and even using a track bar to get some idea how to use it.
Even if getting a small example to build on this would be really great :-)
You have several options even without any external stuff.
You can draw a gauge needle onto a gauge image. Here is an example.
You can draw the needle onto an image by either calulating the outer point and drawing a line to the center or by rotating the canvas as in the link.
Or you can use the built-in MSChart control and its Doughnut charttype.
Here is an example for this:
The code is simple:
first we set up the chart by adding three DataPoints; then we code a function to update the value.
The points are for
the open, transparent part
the value of the gauge in green
the rest of the scale in red
For testing I use these variables:
double valMin = 0; // user data minimum
double valMax = 100; // ~ maximum
float angle = 60; // open pie angle at the bottom
string valFmt = "{0}°"; // a format string
My current value is pulled from a trackbar.
Setup code:
void setupChartGauge(double val, double vMin, double vMax, float a)
{
valMin = vMin;
valMax = vMax;
angle = a;
Series s = gaugeChart.Series[0];
s.ChartType = SeriesChartType.Doughnut;
s.SetCustomProperty("PieStartAngle", (90 - angle/2) + "");
s.SetCustomProperty("DoughnutRadius", "10");
s.Points.Clear();
s.Points.AddY(angle);
s.Points.AddY(0);
s.Points.AddY(0);
setChartGauge(0);
s.Points[0].Color = Color.Transparent;
s.Points[1].Color = Color.Chartreuse;
s.Points[2].Color = Color.Tomato;
}
and setting a value:
void setChartGauge(double val)
{
Series s = gaugeChart.Series[0];
double range = valMax - valMin;
double aRange = 360 - angle;
double f = aRange / range;
double v1 = val * f;
double v2 = (range - val) * f;
s.Points[1].YValues[0] = v1;
s.Points[2].YValues[0] = v2;
gaugeChart.Titles[0].Text = String.Format(valFmt, val);
gaugeChart.Refresh();
}
I have added minimal styling:
The Chart has a Title docked centered bottom which I also update
I have set a back color
I paint an inner circle in the Paint event like so:
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
Rectangle r = chart1.ClientRectangle;
r.Inflate(-10, -10);
using (SolidBrush brush = new SolidBrush(Color.FromArgb(55, Color.Beige)))
e.Graphics.FillEllipse(brush, r);
Note that Pie and Doughnut charts can have only one series. To show a 2nd one you would need an overlapping 2nd chartarea with the exact same Position.
There are infinite ways to draw stuff, both from scratch or updating the MsChart control. Various gradient brushes come to mind. Adding ticks and a needle will involve rotation code, which basically consists of 3 lines of code..
Update:
Here is an example of drawing a gauge needle.
The code should be called from a Paint event and should pass out a valid Graphics object (read: e.Graphics), a float for the data value, a Rectangle to place the gauge in, a Color and a float for the percentage of the rectangle size to use.
private void drawNeedle(Graphics g, float val, Rectangle r, Color c, float length)
{
Point pc = new Point(r.X + r.Width / 2, r.Y + r.Height / 2);
Point p2 = new Point((int)( pc.X + r.Width / 2 * length / 100f), pc.Y);
using (Pen pen = new Pen(c, 3f)
{ StartCap = LineCap.RoundAnchor, EndCap = LineCap.ArrowAnchor })
{
g.SmoothingMode = SmoothingMode.AntiAlias;
g.TranslateTransform(pc.X, pc.Y);
g.RotateTransform(val - (270 - angle / 2));
g.TranslateTransform(-pc.X, -pc.Y);
g.DrawLine(pen, pc, p2);
g.ResetTransform();
}
}
You can use it in any control that support owner-drawing including the chart..:
drawNeedle(e.Graphics, (float)gaugeChart.Series[0].Points[1].YValues[0], r, Color.White, 70f);
Here is a simple example with a TrackBar:
private Syncfusion.Windows.Forms.Gauge.RadialGauge radialGauge1;
private System.Windows.Forms.TrackBar trackBar1;
private Syncfusion.Windows.Forms.Gauge.Needle needle1;
private void InitializeComponent()
{
this.needle1 = new Syncfusion.Windows.Forms.Gauge.Needle();
this.needle1.Value = 0F;
this.trackBar1 = new System.Windows.Forms.TrackBar();
this.radialGauge1 = new Syncfusion.Windows.Forms.Gauge.RadialGauge();
this.trackBar1.Value = (int) needle1.Value;
this.radialGauge1.EnableCustomNeedles = true;
this.radialGauge1.NeedleCollection.Add(needle1);
this.radialGauge1.Size = new System.Drawing.Size(230, 230);
this.radialGauge1.TabIndex = 0;
this.trackBar1.Scroll += new System.EventHandler(this.trackBar1_Scroll);
}
And a scroll event which sync between gauge and trackBar:
private void trackBar1_Scroll(object sender, EventArgs e)
{
needle1.Value = trackBar1.Value;
}
Related
I've searched and not found this question answered on SO, so I'm asking it here directly.
Does anyone have a clean method to create an infinitely scrolling gradient background? (the gradient shifts, so you can follow the colors from one side/corner to the other)
I've done this in VB like 15 years ago, but it's been so long since I touched VB it's all greek to me.
Assuming someone has done something like this in C# before-- Think demo scene kind of animation.
The VB code snippet is from a working form background I did many years ago, it doesn't scroll so much as bounce back and forth from edge to edge.
Private Sub picCanvas_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Panel1.Paint
Dim rect As New Rectangle(-10, -10, Me.ClientSize.Width + 20, Me.ClientSize.Height + 20)
Dim halfw As Integer = CType(Me.ClientSize.Width, Integer)
Dim br As New LinearGradientBrush(New Point(-120, 500), New Point(Me.ClientSize.Width + 120, 0), Color.Red, Color.Blue)
Dim color_blend As New ColorBlend
color_blend.Colors = New Color() {Color.Black, Color.Purple, Color.Teal, Color.Purple, Color.Black}
m_Theta += m_Delta
color_blend.Positions = New Single() {0, 0.01, m_Theta, 0.99, 1}
br.InterpolationColors = color_blend
e.Graphics.FillRectangle(br, rect)
br.Dispose()
If (m_Theta > 0.75) Or (m_Theta < 0.25) Then m_Delta = -m_Delta
End Sub
I would greatly appreciate any help in getting this kind of thing to work in WinForms using only GDI and brushes, no XML or anything please ^^/
I'm not exactly sure this is what you're trying to do, anyway, from the semi-pseudo code presented here, it appears you want to shift the position of a gradient fill along an axis.
It appears the fill is meant to be inclined, so I've added means to determine a rotation angle.
I've kept the LinearGradientBrush to generate the blended fill, though the combination of GraphicsPath and PathGradientBrush is probably more flexible.
To move the gradient fill, I've used a standard System.Windows.Forms.Timer. It's used to translate the fill, incrementing a value that is then set to the translation components of a Matrix in the OnPaint override of a double-buffered Form used as canvas (of course, you can use a PictureBox instead)
The Matrix is also used to rotate the fill, in case it's needed
The Timer's Tick handler also verifies other conditions (bool Fields), that can be used to alter the fill:
useThetaShift enables semi-dynamic motions of the blend intervals (the Position Property)
useTriangular enables and alternate blending feature, generated by the SetBlendTriangularShape() method, which considers only the starting and ending Colors of the LinearGradientBrush and defines the center point of the Colors' fall-off
The sample Form shown here can also be set to auto-scroll, the blending is extended to the DisplayRectangle
The blend is animated also when a modal Dialog is shown (you mentioned an About Window...)
internal class SomeForm : Form {
private System.Windows.Forms.Timer gradientTimer = null;
public SomeForm() {
InitializeComponent();
if (components is null) components = new Container();
ResizeRedraw = true;
startColor = blendColors[0];
meanColor = blendColors[1];
endColor = blendColors[blendColors.Length - 1];
gradientTimer = new System.Windows.Forms.Timer(components) { Interval = 100 };
gradientTimer.Tick += GradientTimer_Tick;
gradientTimer.Start();
}
float theta = .0f;
float delta = .005f;
float tringularShift = .25f;
float tringularShiftDelta = .015f;
float speed = 7.5f;
float rotation = 0f;
private Color[] blendColors = new[]{
Color.Black, Color.Purple, Color.Teal, Color.Purple, Color.Black
};
Color startColor = Color.Empty;
Color endColor = Color.Empty;
Color meanColor = Color.Empty;
PointF translateMx = PointF.Empty;
bool useThetaShift = false;
bool useTriangular = false;
private void GradientTimer_Tick(object sender, EventArgs e)
{
if (useTriangular) {
tringularShift += tringularShiftDelta;
tringularShift = Math.Max(Math.Min(tringularShift, 1.0f), .35f);
if ((tringularShift >= 1.0f) | (tringularShift <= .35f)) tringularShiftDelta*= -1;
}
if (useThetaShift) {
theta += delta;
theta = Math.Max(Math.Min(theta, .15f), 0f);
if ((theta >= .15f) | (theta <= 0f)) delta*= -1;
}
translateMx = PointF.Add(translateMx, new SizeF(speed, speed));
if (Math.Abs(translateMx.X) >= short.MaxValue) translateMx = PointF.Empty;
Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
var display = DisplayRectangle;
using (var mx = new Matrix(1f, 0f, 0f, 1f, translateMx.X, translateMx.Y))
using (var brush = new LinearGradientBrush(display, startColor, endColor, rotation)) {
var colorBlend = new ColorBlend(blendColors.Length) {
Colors = blendColors,
Positions = new float[] { .0f, .25f + theta, .5f + theta, .75f + theta, 1.0f },
};
brush.InterpolationColors = colorBlend;
mx.Rotate(rotation);
brush.Transform = mx;
if (useTriangular) brush.SetBlendTriangularShape(.5f, tringularShift);
e.Graphics.FillRectangle(brush, display);
}
base.OnPaint(e);
}
protected override void OnFormClosing(FormClosingEventArgs e) {
// Move to OnFormClosed() if this action can be canceled
gradientTimer.Stop();
base.OnFormClosing(e);
}
}
I cannot post an animation here, because of the size. You can see how it work directly on Imgur:
Animated LinearGradientPath
I have a chart on which I want to plot a heat map; the only data I have is humidity and temperature, which represent a point in the chart.
How do I get the rectangular type of heat map on the chart in c#?
What I want is similar to picture below :
What I really want is a rectangular region in the chart which is plotted in different color based on the point that i get from the list of points and form the colorful section in the chart.
You have a choice of at least three ways to create a chart with colored rectangles that make up a heat map.
Here is one example
that uses/abuses a DataGridView. While I would not suggest this, the post contains a useful function that creates nice color lists to use in your task.
Then there is the option to draw the chart using GDI+ methods, namely Graphics.FillRectangle. This not hard at all but once you want to get those nice extras a Chart control offers, like scaling, axes, tooltips etc the work adds up.. See below!
So let's have a look at option three: Using the Chart control from the DataVisualization namespace.
Let's first assume that you have created a list of colors:
List<Color> colorList = new List<Color>();
And that you have managed to project your data onto a 2D array of int indices that point into the color list:
int[,] coloredData = null;
Next you have to pick a ChartType for your Series S1 There really is only one I can think of that will help:
S1.ChartType = SeriesChartType.Point;
Points are displayed by Markers. We want the DataPoints not really displayed as one of the standard MarkerTypes.
Square would be ok, if we wanted to display squares; but for rectangles it will not work well: Even if we let them overlap there will still be points at the borders that have a different size because they don't fully overlap..
So we use a custom marker by setting the MarkerImage of each point to a bitmap of a suitable size and color.
Here is a loop that adds the DataPoints to our Series and sets each to have a MarkerImage:
for (int x = 1; x < coloredData.GetLength(0); x++)
for (int y = 1; y < coloredData.GetLength(1); y++)
{
int pt = S1.Points.AddXY(x, y);
S1.Points[pt].MarkerImage = "NI" + coloredData[x,y];
}
This takes some explaining: To set a MarkerImage that is not at a path on the disk, it has to reside in the Chart's Images collection. This means is needs to be of type NamedImage. Any image will do, but it has to have a unique name string added to identify it in the NamedImagesCollection . I chose the names to be 'NI1', 'NI2'..
Obviously we need to create all those images; here is a function to do that:
void createMarkers(Chart chart, int count)
{
// rough calculation:
int sw = chart.ClientSize.Width / coloredData.GetLength(0);
int sh = chart.ClientSize.Height / coloredData.GetLength(1);
// clean up previous images:
foreach(NamedImage ni in chart1.Images) ni.Dispose();
chart.Images.Clear();
// now create count images:
for (int i = 0; i < count; i++)
{
Bitmap bmp = new Bitmap(sw, sh);
using (Graphics G = Graphics.FromImage(bmp))
G.Clear(colorList[i]);
chart.Images.Add(new NamedImage("NI" + i, bmp));
}
}
We want all markers to have at least roughly the right size; so whenever that size changes we set it again:
void setMarkerSize(Chart chart)
{
int sx = chart1.ClientSize.Width / coloredData.GetLength(0);
int sy = chart1.ClientSize.Height / coloredData.GetLength(1);
chart1.Series["S1"].MarkerSize = (int)Math.Max(sx, sy);
}
This doesn't care much about details like the InnerPlotPosition, i.e. the actual area to draw to; so here is some room for refinement..!
We call this when we set up the chart but also upon resizing:
private void chart1_Resize(object sender, EventArgs e)
{
setMarkerSize(chart1);
createMarkers(chart1, 100);
}
Let's have a look at the result using some cheap testdata:
As you can see resizing works ok..
Here is the full code that set up my example:
private void button6_Click(object sender, EventArgs e)
{
List<Color> stopColors = new List<Color>()
{ Color.Blue, Color.Cyan, Color.YellowGreen, Color.Orange, Color.Red };
colorList = interpolateColors(stopColors, 100);
coloredData = getCData(32, 24);
// basic setup..
chart1.ChartAreas.Clear();
ChartArea CA = chart1.ChartAreas.Add("CA");
chart1.Series.Clear();
Series S1 = chart1.Series.Add("S1");
chart1.Legends.Clear();
// we choose a charttype that lets us add points freely:
S1.ChartType = SeriesChartType.Point;
Size sz = chart1.ClientSize;
// we need to make the markers large enough to fill the area completely:
setMarkerSize(chart1);
createMarkers(chart1, 100);
// now we fill in the datapoints
for (int x = 1; x < coloredData.GetLength(0); x++)
for (int y = 1; y < coloredData.GetLength(1); y++)
{
int pt = S1.Points.AddXY(x, y);
// S1.Points[pt].Color = coloredData[x, y];
S1.Points[pt].MarkerImage = "NI" + coloredData[x,y];
}
}
A few notes on limitations:
The point will always sit on top of any gridlines. If you really needs those you will have to draw them on top in one of the the Paint events.
The labels as shown are referring to the integers indices of the data array. If you want to show the original data, one way would be to add CustomLabels to the axes.. See here for an example!
This should give you an idea of what you can do with a Chart control; to complete your confusion here is how to draw those rectangles in GDI+ using the same colors and data:
Bitmap getChartImg(float[,] data, Size sz, Padding pad)
{
Bitmap bmp = new Bitmap(sz.Width , sz.Height);
using (Graphics G = Graphics.FromImage(bmp))
{
float w = 1f * (sz.Width - pad.Left - pad.Right) / coloredData.GetLength(0);
float h = 1f * (sz.Height - pad.Top - pad.Bottom) / coloredData.GetLength(1);
for (int x = 0; x < coloredData.GetLength(0); x++)
for (int y = 0; y < coloredData.GetLength(1); y++)
{
using (SolidBrush brush = new SolidBrush(colorList[coloredData[x,y]]))
G.FillRectangle(brush, pad.Left + x * w, y * h - pad.Bottom, w, h);
}
}
return bmp;
}
The resulting Bitmap looks familiar:
That was simple; but to add all the extras into the space reserved by the padding will not be so easy..
This is a rubber band selection rectangle drawn on a canvas. My problem is that it is easy to get the correct size of the rectangle provided the canvas contents are not rotated. But as soon as it is rotated the rectangle no longer sizes with the cursor. I need the rubber band to stay parallel with screen
var dragPt = new PointF(e.Position.X - G.ReferenceOffset.X, e.Position.Y - G.ReferenceOffset.Y);
var rotation = ADEEnvironment.RotateAngle;
var width = (dragPt.X - pressPt.X);
var height = (dragPt.Y - pressPt.Y);
The code is pretty trivial. I capture the position of the mouse on mouse down: pressPt. In the mouse move event I get the current mouse position dragPt and calculate the width and height of the rubber band rectangle and use those values to create a rectangle with its origin on pressPt.
This works fine if the camera for the canvas is not rotated. When I rotate the display I need the rubber band to stay aligned with the screen and not the canvas it is drawn on. It I just leave it the rubber band is drawn rotated as well.
If I rotate the rubber band rectangle to return it to alignment with the screen then the rectangle is no longer sizing correctly. So after a lot of messing about I tried a bit of trigonometry:
var width = (float)((dragPt.X - pressPt.X) / Math.Cos(rotation));
var height = (float)((dragPt.Y - pressPt.Y) / Math.Cos(rotation));
Which doesn't work and gets very messy given that the rotation angle can be anything for 0 > 360
I have looked at other code on how to create a selection rectangle including the answers to this question: How to make a resizeable rectangle selection tool?
but I would like to use the basic code I have if possible since it is related to the graphics engine I am using (Piccolo).
I would put up some screenshots but I can't capture the rubber band. I think this is more of a math problem than anything else and it ought to be easy to fix but I just can't work out what math calculations to make to account to the effect of rotating the display.
This code uses the Paint event to draw
One fixed rectangle on a rotated canvas
An unrotated copy of it
An unrotated rubber-band
and checks on the corners of example rectanlge
// one example 'object'
Rectangle R0 = new Rectangle(182,82,31,31);
// a few helpers
Point curMouse = Point.Empty;
Point downMouse = Point.Empty;
Rectangle RM = Rectangle.Empty;
float angle = 30;
Point center = new Point(-55, -22);
private void canvas_Paint(object sender, PaintEventArgs e)
{
// preprare the canvas to rotate around a center point:
e.Graphics.TranslateTransform(center.X , center.Y);
e.Graphics.RotateTransform(angle);
e.Graphics.TranslateTransform(-center.X, -center.Y);
// draw one object and reset
e.Graphics.DrawRectangle(Pens.Green, R0);
e.Graphics.ResetTransform();
// for testing (and hittesting): this is the unrotated obejct:
e.Graphics.DrawRectangle(Pens.LightGray, R0);
// allowing for any way the rubber band is drawn..
// ..should be moved to a helper function!
Size S = new Size( Math.Abs(downMouse.X - curMouse.X),
Math.Abs(downMouse.Y - curMouse.Y));
Point P0 = new Point(Math.Min(downMouse.X, curMouse.X),
Math.Min(downMouse.Y, curMouse.Y));
RM = new Rectangle(P0, S);
// the ruber band
e.Graphics.DrawRectangle(Pens.Red, RM);
}
private void canvas_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
curMouse = e.Location;
canvas.Invalidate();
}
private void canvas_MouseDown(object sender, MouseEventArgs e)
{
downMouse = e.Location;
curMouse = e.Location;
}
IMO, the more interesting part will be to decide which objects are selected. Will any intersection count or should it be completely contained?
I found a nice piece of rotation code in this post and add it with an example to check on the fixed Rectangle.
Of course more complex object will call for more involved lists of points. To get really exact results you may even need to go for GraphicsPaths and the set operations on Regions they support; but maybe a simple convex hull will do..
Of course, you will want to store the rotated points instead of reapeatedly calculating them..
static Point RotatePoint(Point pointToRotate, Point centerPoint, double angleInDegrees)
{
double angleInRadians = angleInDegrees * (Math.PI / 180);
double cosTheta = Math.Cos(angleInRadians);
double sinTheta = Math.Sin(angleInRadians);
return new Point
{
X =
(int)
(cosTheta * (pointToRotate.X - centerPoint.X) -
sinTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.X),
Y =
(int)
(sinTheta * (pointToRotate.X - centerPoint.X) +
cosTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.Y)
};
}
private void canvas_MouseUp(object sender, MouseEventArgs e)
{
List<Point> points = new List<Point>();
points.Add(RotatePoint(new Point(R0.Left, R0.Top), center, angle));
points.Add(RotatePoint(new Point(R0.Right, R0.Top), center, angle) );
points.Add(RotatePoint(new Point(R0.Right, R0.Bottom), center, angle) );
points.Add(RotatePoint(new Point(R0.Left, R0.Bottom), center, angle));
bool ok = true;
foreach (Point pt in points) if (!RM.Contains(pt)) ok = false;
if (ok) this.Text = "HIT"; else this.Text = "no hit";
}
Currently I am using ZedGraph to display my curve. I want to mark the particular regions of the curve over the ZedGraph control and label it like follows.
Note: I need different type of markings in the X and Y axis based on the text size.
Thanks for your help in advance.
You have two options,
1) Use BoxObject to draw at a specific region as follows
and you can use the source code as follows:
private void Form1_Load(object sender, EventArgs e)
{
// Create an instance of Graph Pane
GraphPane myPane = zedGraphControl1.GraphPane;
// Build a PointPairList with points based on Sine wave
PointPairList list = new PointPairList();
for (double i = 0; i < 36; i++)
{
double x = i * 10.0 + 50.0;
double y = Math.Sin(i * Math.PI / 15.0) * 16.0;
list.Add(x, y);
}
// Hide the legend
myPane.Legend.IsVisible = false;
// Add a curve
LineItem curve = myPane.AddCurve("label", list, Color.Red, SymbolType.Circle);
curve.Line.Width = 1.5F;
curve.Symbol.Fill = new Fill(Color.White);
curve.Symbol.Size = 5;
// Make the XAxis start with the first label at 50
myPane.XAxis.Scale.BaseTic = 50;
// Fill the axis background with a gradient
myPane.Chart.Fill = new Fill(Color.White, Color.SteelBlue, 45.0F);
// Draw Region 1
drawRegion(list[0].X, list[10].X,"Positive Cycle");
// Calculate the Axis Scale Ranges
zedGraphControl1.AxisChange();
// Refresh to paint the graph components
Refresh();
}
private void drawRegion(double xMin, double xMax, string regName)
{
GraphPane pane = zedGraphControl1.GraphPane;
BoxObj box = new BoxObj(xMin,20, xMax, 40.0, Color.Empty, Color.LightSteelBlue);// Color.FromArgb(225, 245, 225));
box.Location.CoordinateFrame = CoordType.AxisXYScale;
box.Location.AlignH = AlignH.Left;
box.Location.AlignV = AlignV.Top;
// place the box behind the axis items, so the grid is drawn on top of it
box.ZOrder = ZOrder.E_BehindCurves;//.D_BehindAxis;//.E_BehindAxis;
pane.GraphObjList.Add(box);
// Add Region text inside the box
TextObj myText = new TextObj(regName, 160, -15);
myText.Location.CoordinateFrame = CoordType.AxisXYScale;
myText.Location.AlignH = AlignH.Right;
myText.Location.AlignV = AlignV.Center;
myText.FontSpec.IsItalic = true;
myText.FontSpec.IsBold = false;
myText.FontSpec.FontColor = Color.Red;
myText.FontSpec.Fill.IsVisible = false;
myText.FontSpec.Border.IsVisible = false;
pane.GraphObjList.Add(myText);
zedGraphControl1.Refresh();
}
2) This is a bit difficult but do-able, Draw individual vertical lines discussed here: 1, 2 and add the required text etc.
I suggest you to use the option 1, which is lot easier than 2 !
I have a PictureBox with a picture as a background of an application, having all the Anchors set, so it can resize with the form. On this PictureBox, I am creating many other things, for now only rectangles. I am creating them on some X and Y coordinates, that is fine. Adding a picture to show what I am trying to do. Created rectangle is actually the little light blue square.
But, when i resize the form, for example I maximize it, the rectangle stays at the same coordinates, which of course ar somewhere else at the moment (including only part of image to save space):
My question is - how can i make the rectangle "stick" with the same place as it is, during the resize? Note - they will have to move later, like every 2 seconds or so, so it cant be absolutely static.
EDIT:
here is some of the code creating the rectangle
private void button1_Click(object sender, EventArgs e)
{
spawn = "aircraft";
pictureBox1.Invalidate();
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
switch (spawn)
{
case "aircraft":
Point[] points = new Point[2];
Point bod = new Point(750, 280);
points[0] = bod;
aircraft letadlo = new aircraft(605, 180, "KLM886", 180, e.Graphics);
aircrafts[0] = letadlo;
letadlo.points = points;
break;
...
public aircraft(int x, int y, string csign, int spd, Graphics g)
{
Pen p = new Pen(Color.Turquoise, 2);
Rectangle r = new Rectangle(x, y, 5, 5);
g.DrawRectangle(p, r);
p.Dispose();
One option could be to redraw the rectangle in new coordinates which are proportional to the PictureBox changed size.
For example:
oldX, oldY // old coordinates of the rectangle should be saved
oldPictureBoxWidth, oldPictureBoxHeight // should be saved too
//and on the PictureBox Paint event You have the new:
newPictureBoxWidth and newPictureBoxHeight
//the new coordinates of rectangle: (resize ratio is in brackets)
newX = oldX * (newPictureBoxWidth / oldPictureBoxWidth)
newY = oldY * (newPictureBoxHeight / oldPictureBoxHeight)
i think you have to calculate the % between the distance of your x and y from the top and the bottom , and if the form re-sized just use your % and draw again your rect !
for ex :
x = 100 the width is 200 so 100 is 1/2 so it 50% So if the form resized just calculate the new size and (newsize * 50 ) / 100
Hope that can help you .