I'm looking for possibility to create a live preview of WinForms Form/Control.
My application got two windows - one, where someone can draw on Image (which is in PictureBox), and second window, where someone can see what was been drawn on 1st window. At this moment, I tried to put the same PictureBox with image on second window, and draw the same lines on it like in window 1. Unfortunately preview like this is not live preview, because image on window 2 is refreshed when someone stop drawing on window 1. Below I'm sending a code, which is used to draw on Image.
public void AddNewPoint(int X, int Y)
{
if (_firstPointInStroke)
{
_firstpoint = _mainCustomPictureBox.PointToClient(new System.Drawing.Point(X, Y));
_firstPointInStroke = false;
}
_secondpoint = _mainCustomPictureBox.PointToClient(new System.Drawing.Point(X, Y));
var g = Graphics.FromImage(_mainCustomPictureBox.Image);
var wfactor = (double)_mainCustomPictureBox.Image.Width / _mainCustomPictureBox.Width;
var hfactor = (double)_mainCustomPictureBox.Image.Height / _mainCustomPictureBox.Height;
var resizeFactor = Math.Max(wfactor, hfactor);
System.Windows.Shapes.Line currentLine;
if (hfactor > wfactor)
{
_firstpoint.X = (float)((_firstpoint.X - ((_mainCustomPictureBox.Width - ((double)_mainCustomPictureBox.Image.Width / resizeFactor)) / 2)) * resizeFactor);
_firstpoint.Y = (float)(_firstpoint.Y * resizeFactor);
_secondpoint.X = (float)((_secondpoint.X - ((_mainCustomPictureBox.Width - ((double)_mainCustomPictureBox.Image.Width / resizeFactor)) / 2)) * resizeFactor);
_secondpoint.Y = (float)(_secondpoint.Y * resizeFactor);
}
else
{
_firstpoint.X = (float)(_firstpoint.X * resizeFactor);
_firstpoint.Y = (float)((_firstpoint.Y - ((_mainCustomPictureBox.Height - ((double)_mainCustomPictureBox.Image.Height / resizeFactor)) / 2)) * resizeFactor);
_secondpoint.X = (float)(_secondpoint.X * resizeFactor);
_secondpoint.Y = (float)((_secondpoint.Y - ((_mainCustomPictureBox.Height - ((double)_mainCustomPictureBox.Image.Height / resizeFactor)) / 2)) * resizeFactor);
}
currentLine = new System.Windows.Shapes.Line { X1 = _firstpoint.X, X2 = _secondpoint.X, Y1 = _firstpoint.Y, Y2 = _secondpoint.Y };
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
g.DrawLine(_pen, (float)currentLine.X1, (float)currentLine.Y1, (float)currentLine.X2, (float)currentLine.Y2);
g.Dispose();
_mainCustomPictureBox.Invalidate();
if (_previewCustomPictureBox != null && _previewCustomPictureBox.Image != null)
{
var gg = Graphics.FromImage(_previewCustomPictureBox.Image);
gg.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
gg.DrawLine(_pen, (float)currentLine.X1, (float)currentLine.Y1, (float)currentLine.X2, (float)currentLine.Y2);
gg.Dispose();
_previewCustomPictureBox.Invalidate();
}
_firstpoint = _mainCustomPictureBox.PointToClient(new System.Drawing.Point(X, Y));
}
Have you any idea, how to force UI of second window to refresh after every point?
Hawex
Related
Instantiating the form.
public TwoDPlot()
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true);
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US", true);
InitializeComponent();
DrawCircle();
}
Method to draw the circle.
private void DrawCircle()
{
var radius = 0.5 * ClientRectangle.Width;
var height = ClientRectangle.Height - 0.1 * ClientRectangle.Height;
var width = ClientRectangle.Width - 0.1 * ClientRectangle.Width;
var scaledRadius = width > height ? radius * (height / radius) : radius * (width / radius);
var xlocation = ClientRectangle.Width / 2.0 - scaledRadius * 0.5;
var ylocation = ClientRectangle.Height / 2.0 - scaledRadius * 0.5;
m_Graphics = CreateGraphics();
m_Graphics?.Clear(DefaultBackColor);
m_Graphics?.DrawEllipse(new Pen(Color.Red), new Rectangle((int)xlocation, (int)ylocation, (int)scaledRadius, (int)scaledRadius));
m_Graphics.Dispose();
}
On instance, it shows empty form and upon re-sizing it shows the circle. I expect to show during the first instance.
This is the direct correction:
private void TwoDPlot_Paint(object sender, PaintEventArgs e)
{
DrawCircle(e.Graphics);
}
private void DrawCircle(Graphics m_Graphics)
{
var radius = 0.5 * ClientRectangle.Width;
var height = ClientRectangle.Height - 0.1 * ClientRectangle.Height;
var width = ClientRectangle.Width - 0.1 * ClientRectangle.Width;
var scaledRadius = width > height ? radius * (height / radius) : radius * (width / radius);
var xlocation = ClientRectangle.Width / 2.0 - scaledRadius * 0.5;
var ylocation = ClientRectangle.Height / 2.0 - scaledRadius * 0.5;
m_Graphics.Clear(DefaultBackColor);
m_Graphics.DrawEllipse(new Pen(Color.Red), new Rectangle((int)xlocation, (int)ylocation, (int)scaledRadius, (int)scaledRadius));
}
Note that to be more flexible you will want to move the variables maybe to class level variables or to parameters to the DrawCircle function..
When you have done that and changed the variables values you can trigger the Paint event by calling TwoDPlot.Invalidate().
The system will also call it whenever it needs to, e.g. upon many resize, maximize and other events..
i i am relative new to c# and is trying to draw a curved line in c#. I would like to ask that is there any possible way to create an X and Y axis in order to show the coordinates of each point of the curved line.
Please do help me on this matter as i am stuck on how to execute it.
protected override void OnPaint(PaintEventArgs e)
{
float a = 1, b = 5, c = 1;
double x1, x2, x3,x4,x5,x6, y1, y2, y3,y4,y5, delta;
delta = (b * b) - (4 * a * c);
x1=0;
y1 = a * (x1 * x1) + (b * (x1)) + c;
x2 = 3;
y2 = a * (x2 * x2) + (b * (x2)) + c;
x3 = - 3;
y3 = a * (x3 * x3) + (b * (x3)) + c;
x4 = 5;
y4 = a * (x4 * x4) + (b * (x4)) + c;
x5 = -10;
y5 = a * (x5 * x5) + (b * (x5)) + c;
int cx1 = Convert.ToInt32(x1);
int cx2 = Convert.ToInt32(x2);
int cx3 = Convert.ToInt32(x3);
int cy1 = Convert.ToInt32(y1);
int cy2 = Convert.ToInt32(y2);
int cy3 = Convert.ToInt32(y3);
int cx4 = Convert.ToInt32(x4);
int cy4 = Convert.ToInt32(y4);
int cx5 = Convert.ToInt32(x5);
int cy5 = Convert.ToInt32(y5);
Graphics g = e.Graphics;
int deltaX = 100;
int deltaY = 100;
g.TranslateTransform(deltaX, deltaY);
float factor = 2.5f;
Matrix m = new Matrix();
m.Scale(factor, factor);
g.MultiplyTransform(m);
Pen aPen = new Pen(Color.Blue, 1);
Point point1 = new Point(cx1, cy1);
Point point2 = new Point(cx2, cy2);
Point point3 = new Point(cx3, cy3);
Point point4 = new Point(cx4, cy4);
Point point5 = new Point(cx5, cy5);
Point[] Points = { point5, point3, point1,point2,point4 };
g.DrawCurve(aPen, Points);
Maybe I misunderstand you, but it sounds like you want to make your GDI+ graphics scale with the window size (i.e. you want to scale the X and Y axis with the size of the window), right?
This is pretty simple, you just have to decide how big of a space you want to present in the window -- i.e. if you want to make the axis go from 0,0 on the top left, to 512x512 on the bottom right, then you would just need to scale the X axis by a factor of 512/width, and the Y axis by a factor of 512/height.
So you would do that by performing a ScaleTransform on your Graphics object. You'll need to use your Form's ClientSize to get the width and height. (The regular Form's .Width, and .Height properties, include all the borders and title bars, padding pixels, etc. -- so it's no good for this calculation.)
Then you will need to force an Invalidation during the form's Resize event (it will work without this, when you make the window smaller, but when you make it bigger, this will be required, or else it will only redraw the edges).
Another thing worth considering is turning on the form's DoubleBuffered property, the redraw will be much smoother.
So, let's assume you want to work in a virtual space of 512x512 "pixels" where 0 ,0 is always the top left, and 512,512 is the bottom right. You could add this code to the top of your OnPaint event handler:
float scaleX = 512f / ((float)this.ClientSize.Width);
float scaleY = 512f / ((float)this.ClientSize.Height);
e.Graphics.ScaleTransform(scaleX, scaleY);
Then add a handler for the Form's Resize event and add something like this:
this.Invalidate(true);
That should do the trick.
I'm trying to write a method that scales buttons in any resolution, on full screen without remaining space between them. Button parameters come from a web service. How can I resize them to fill all screen no matter what the parameters are. Or at least to scale their actual size to my new size. My form size is good but my buttons intersect.
private void ResizeButtons()
{
pnlDynamicControls.Height = this.ClientSize.Height
- (pnlDynamicControls.Top + pnlButtons.Height);
pnlDynamicControls.Width = pnlButtons.Width;
float widthRatio =
(float)Screen.PrimaryScreen.Bounds.Width / ClientRectangle.Width;
float heightRatio =
(float)Screen.PrimaryScreen.Bounds.Height / ClientRectangle.Height;
SizeF scale = new SizeF(widthRatio,heightRatio);
this.Scale(scale);
//if ((widthRatio - pnlDynamicControls.Width) < (heightRatio - pnlDynamicControls.Height))
// l_zoomFactor = (float)widthRatio / pnlDynamicControls.Width;
//else
// l_zoomFactor = (float)heightRatio / pnlDynamicControls.Height;
foreach (Control c in pnlDynamicControls.Controls)
{
c.Height = Convert.ToInt16(c.Height * heightRatio);
c.Width = Convert.ToInt16(c.Width * widthRatio);
c.Margin = new Padding(1, 1, 1, 1);
//c.Size = new System.Drawing.Size(
// Convert.ToInt16(c.Width * l_zoomFactor)
// , Convert.ToInt16(c.Height * l_zoomFactor)
// );
}
}
I'm creating a silverlight application where I have to dynamically create buttons. But I need to place them in a circle around the button that I click to generate the other buttons (picture here, the buttons should go on the black line surrounding the 'test project' button)
I don't know how many buttons will be generated each time but I do know the size of each button is static. I'm not quite sure how to do this. Currently my button creation is as follows
foreach (Item a in itemList)
{
Button newButton = new Button();
newButton.Height = 50;
newButton.Width = 50;
newButton.Content = a.getName();
newButton.Click += new RoutedEventHandler(addedClick);
newButton.HorizontalAlignment = HorizontalAlignment.Left;
newButton.VerticalAlignment = VerticalAlignment.Top;
newButton.Margin = new Thickness(0, 0, 0, 0);
newButton.Style = (Style)Application.Current.Resources["RB"];
buttons.Add(newButton);
}
My biggest problem is that I'm not quite sure how to get the center point of the 'test project' button.
EDIT: Okay, now that I have a set of coordinates for each button, how exactly do I go about placing them? I'm not sure how to use a canvas. I tried to set one up but it keeps acting like a stackpanel (no .setLeft/.setTop).
You mean something like the circle equation:
Double distanceFromCenter = 5;
Double angleInDegrees = 90;
Double angleAsRadians = (angleInDegrees* Math.PI) / 180.0;
Double centerX = 100;
Double centerY = 100;
Double x = centerX + Math.Cos(angleAsRadians) * distanceFromCenter;
Double y = centerY + Math.Sin(angleAsRadians) * distanceFromCenter;
that should give you a point that is distanceFromCenter units away from (centerX, center), at an angle of 90-degrees. Note this only works with radians so we have to convert to radians.
var radius = 100;
var angle = 360 / itmeList.Count * Math.PI / 180.0f;
var center = new Point(100, 100);
for (int i = 0; i < itemList.Count; i++)
{
var x = center.X + Math.Cos(angle * i) * radius;
var y = center.Y + Math.Sin(angle * i) * radius;
Button newButton = new Button();
newButton.RenderTransformOrigin = new Point(x, y);
newButton.Height = 50;
newButton.Width = 50;
newButton.Content = a.getName();
newButton.Click += new RoutedEventHandler(addedClick);
newButton.HorizontalAlignment = HorizontalAlignment.Left;
newButton.VerticalAlignment = VerticalAlignment.Top;
newButton.Margin = new Thickness(0, 0, 0, 0);
newButton.Style = (Style)Application.Current.Resources["RB"];
buttons.Add(newButton);
}
Assuming you want your buttons evenly spaced on the circle, you should first generate the list of angles you want them at. E.g.
double eachSection = 2 * Math.PI / count;
var anglesInRadians = Enumerable.Range(0, count).Select(x => x * eachSection);
Then use this formula to find the x/y coordinates of each angle, and use a Canvas or something to position the buttons in those positions
public static Point PointOnCircle(double radius, double angleInRadians, Point origin)
{
double x = radius * Math.Cos(angleInRadians) + origin.X;
double y = radius * Math.Sin(angleInRadians) + origin.Y;
return new Point(x, y);
}
I need to make circle with bar.
Here is my image when someone will still not understand:
Does any existing control work? Or should I create a new control somehow? I used a new control with circle filled with gradient but it isn't the same effect :(
I also tried to draw a circle but when I do in my math cycle with sin and cos it does something what I do not want.
double slice = 2 * Math.PI / 360;
for (int i = 0; i < 360; i++)
{
double angle = slice * i;
int x = (int)(0 + 300 * Math.Cos(angle)); // start x + radius * ...
int y = (int)(0 + 300 * Math.Sin(angle));
Line line = new Line()
{
X1 = 0,
Y1 = 0,
X2 = x,
Y2 = y,
Stroke = new SolidColorBrush(Colors.Red),
StrokeThickness = 1.0
};
canvas.Children.Add(line);
}
EDIT: Metro = Xaml!!!