The question asked to calculate the volume of a swimming pool and display its cross section in a picture box. Width of the pool is fixed at 5 meters and the length is fixed at 20 meters.
The program should have 2 trackbars - one to adjust the depth of the deep end and one to adjust the depth of the shallow end. The minimum depth of each end is one meter, choose suitable maximum and minimum track bar values at design time.
Volume = averageDepth * width * length
The trackbar for the deep end of the pool adjusts the depth perfectly.
The trackbar for the shallow end changes the cross section and does not diplay one of the lines when used.
Could someone please help me correct this and figure it out?
Heres the code:
public partial class Form1 : Form
{
private Graphics paper;
private int averageDepth;
private int answer;
public Form1()
{
InitializeComponent();
paper = pictureBox1.CreateGraphics();
deepEndTrackbar.Minimum = 120;
deepEndTrackbar.Maximum = 180;
deepEndLabel.Text = Convert.ToString(deepEndTrackbar.Value);
shallowEndTrackbar.Minimum = 120;
shallowEndTrackbar.Maximum = 180;
shallowEndLabel.Text = Convert.ToString(shallowEndTrackbar.Value);
}
private void button1_Click(object sender, EventArgs e)
{
Graphics paper;
paper = pictureBox1.CreateGraphics();
Pen pen = new Pen(Color.Black);
paper.DrawLine(pen, 40, 50, 200, 50);
paper.DrawLine(pen, 40, 50, 40, 120);
paper.DrawLine(pen, 200, 50, 200, 90);
paper.DrawLine(pen, 200, 90, 40, 120);
}
private void deepEndTrackbar_Scroll(object sender, EventArgs e)
{
Pen pen = new Pen(Color.Black);
deepEndLabel.Text = Convert.ToString(deepEndTrackbar.Value);
paper.Clear(Color.White);
paper.DrawLine(pen, 40, 50, 200, 50);
paper.DrawLine(pen, 200, 50, 200, 90);
paper.DrawLine(pen, 40, 50, 40, deepEndTrackbar.Value);
paper.DrawLine(pen, 200, 90, 40, deepEndTrackbar.Value);
}
private void shallowEndTrackbar_Scroll(object sender, EventArgs e)
{
Pen pen = new Pen(Color.Black);
shallowEndLabel.Text = Convert.ToString(shallowEndTrackbar.Value);
paper.Clear(Color.White);
paper.DrawLine(pen, 40, 50, 200, shallowEndTrackbar.Value);
paper.DrawLine(pen, 200, 50, 200, shallowEndTrackbar.Value);
}
The deepEndTrackbar_Scroll routine seems to work. But it doesn't really as it does not use the value of the shallowEndTrackbar. In fact both routines should draw the very same lines:
paper.DrawLine(pen, 40, 50, 200, 50);
paper.DrawLine(pen, 200, 50, 200, shallowEndTrackbar.Value);
paper.DrawLine(pen, 40, 50, 40, deepEndTrackbar.Value);
paper.DrawLine(pen, 200, shallowEndTrackbar.Value, 40, deepEndTrackbar.Value);
This is the bare minimum correction.
The next step would be to have this code only once. The direct solution would be to call the same event for both Trackbars.
However all these things are only working on the surface. Minimize the window, restore and look: All Lines are gone! You need to persist the drawing!
The right place for the code is the Paint event of the PictureBox. You could override it, but it is simpler to just code it: Doubleclick it in the properties tab and insert the code.
Prefix this line to the code:
paper = e.Graphics;
And replace all drawing in the two TrackBar scroll events for this:
pictureBox1.Invalidate();
Another error is with initializing the Trackbar. Judging from the initial display one value (90) is not in the allowed range (120-180).
You also don't need the lines
private Graphics paper;
and
paper = pictureBox1.CreateGraphics();
Edit: As requested here is a complete solution.
Note: I have added a LengthTrackbar and moved the drawing down by 100 pixels:
public partial class Form1 : Form
{
Pen pen = Pens.Black;
//private int averageDepth;
//private int answer;
public Form1 ()
{
InitializeComponent();
deepEndTrackbar.Minimum = 120;
deepEndTrackbar.Maximum = 180;
deepEndLabel.Text = Convert.ToString(deepEndTrackbar.Value);
shallowEndTrackbar.Minimum = 120;
shallowEndTrackbar.Maximum = 180;
shallowEndLabel.Text = Convert.ToString(shallowEndTrackbar.Value);
lengthTrackbar.Minimum = 120;
lengthTrackbar.Maximum = 180;
lengthLabel.Text = Convert.ToString(lengthTrackbar.Value);
}
private void button1_Click(object sender, EventArgs e)
{
// reset the trackbar values:
shallowEndTrackbar.Value = 120;
deepEndTrackbar.Value = 120;
lengthTrackbar.Value = 120;
pictureBox1.Invalidate();
}
private void deepEndTrackbar_Scroll(object sender, EventArgs e)
{
deepEndLabel.Text = Convert.ToString(deepEndTrackbar.Value);
pictureBox1.Invalidate();
}
private void shallowEndTrackbar_Scroll(object sender, EventArgs e)
{
shallowEndLabel.Text = Convert.ToString(shallowEndTrackbar.Value);
pictureBox1.Invalidate();
}
private void lengthTrackbar_Scroll(object sender, EventArgs e)
{
lengthLabel.Text = Convert.ToString(lengthTrackbar.Value);
pictureBox1.Invalidate();
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Graphics paper = e.Graphics;
// reset the paper
paper.Clear(Color.White);
// draw the 2D front lines:
paper.DrawLine(pen, 40, 150, 200, 150);
paper.DrawLine(pen, 200, 150, 200, 100 + shallowEndTrackbar.Value);
paper.DrawLine(pen, 40, 150, 40, 100 + deepEndTrackbar.Value);
paper.DrawLine(pen, 200, 100 + shallowEndTrackbar.Value, 40,
100 + deepEndTrackbar.Value);
// perspective 2:3
int lx = lengthTrackbar.Value / 2;
int ly = lengthTrackbar.Value / 3;
// draw the outer 3D lines:
paper.DrawLine(pen, 40, 150, 40 + lx, 150 - ly);
paper.DrawLine(pen, 200, 150, 200 + lx, 150 - ly);
paper.DrawLine(pen, 200, 100 + shallowEndTrackbar.Value,
200 + lx, 100 - ly + shallowEndTrackbar.Value);
paper.DrawLine(pen, 40 + lx, 150 - ly, 40 + lx + 200 - 40, 150 - ly);
paper.DrawLine(pen, 200 + lx, 150 - ly,
200 + lx, 100 -ly + shallowEndTrackbar.Value);
}
}
Related
I created two pictureBoxes on my windows form application. I want to draw in both of them, using FillEllipse(), but for some reason I can only draw in the first pictureBox. I belive the problem is that I don't understand properly how events work. Here is the code:
public Form1()
{
InitializeComponent();
pictureBox1.Paint += new PaintEventHandler(this.pictureBox1_Paint);
pictureBox2.Paint += new PaintEventHandler(this.pictureBox2_Paint);
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Graphics gr = e.Graphics;
Point p1 = pictureBox1.Location;
gr.FillEllipse(new SolidBrush(Color.Red), new Rectangle(p1.X + 40, p1.Y + 40, 20, 20));
gr.FillEllipse(new SolidBrush(Color.Red), new Rectangle(p1.X + 40, p1.Y + 80, 20, 20));
gr.FillEllipse(new SolidBrush(Color.Red), new Rectangle(p1.X + 80, p1.Y + 40, 20, 20));
gr.FillEllipse(new SolidBrush(Color.Red), new Rectangle(p1.X + 80, p1.Y + 80, 20, 20));
}
private void pictureBox2_Paint(object sender, PaintEventArgs e)
{
Graphics br = e.Graphics;
Point p2 = pictureBox2.Location;
br.FillEllipse(new SolidBrush(Color.Red), new Rectangle(p2.X + 40, p2.Y + 40, 20, 20));
br.FillEllipse(new SolidBrush(Color.Red), new Rectangle(p2.X + 40, p2.Y + 80, 20, 20));
br.FillEllipse(new SolidBrush(Color.Red), new Rectangle(p2.X + 80, p2.Y + 40, 20, 20));
br.FillEllipse(new SolidBrush(Color.Red), new Rectangle(p2.X + 80, p2.Y + 80, 20, 20));
}
You are drawing in pictureBox2. Your problem is that you are drawing outside of the viewport, because you are drawing at pictureBox2's location on the form, but within the picturebox. pictureBox2.Location gives to position of the box on the form. If this box is at position x=240, y=240, you are drawing INSIDE the box at those positions. If your box is only w=50, h=50, you will not see what you are drawing because it's waaaay to the right and bottom
So, this is really inefficient you're drawing everything twice resulting in twice the load. What you need to do is draw once into a bitmap and load the bitmap into the two picture boxes.
https://learn.microsoft.com/en-us/dotnet/framework/winforms/advanced/how-to-create-a-bitmap-at-run-time
However, if working with bitmaps won't allow you to achieve whatever it is you're trying to do, write a custom control. While this wont improve performance all that much it will at least stop code duplication.
https://learn.microsoft.com/en-us/dotnet/framework/winforms/controls/creating-a-wf-control-design-time-features
Bitmap img= new Bitmap(100, 100);
Point p1 = pictureBox1.Location;
Graphics gr = Graphics.FromImage(img);
gr.FillEllipse(new SolidBrush(Color.Red), new Rectangle(p1.X + 40, p1.Y + 40, 20, 20));
gr.FillEllipse(new SolidBrush(Color.Red), new Rectangle(p1.X + 40, p1.Y + 80, 20, 20));
gr.FillEllipse(new SolidBrush(Color.Red), new Rectangle(p1.X + 80, p1.Y + 40, 20, 20));
picturebox1.Image = img;
picturebox2.Image = img;
The PaintEventArgs e.Graphics gives you a control's DeviceContext (consider it a reference to the graphics surface of a control) and a set of tools that can be used to perform graphics operations on that context.
When using e.Graphics, all drawings occur inside the underlying surface the graphics object references (a PictureBox ClipRectangle in this case). All coordinates are related to this area.
Thus, you just need to specify the position and size of a drawing using the control's Client Area as the only reference. The drawing area dimensions are also reported by the e.Graphics.ClipBounds (expressed in PageUnits) and the control ClientRectangle property (expressed in Pixels).
The ClientRectangle is the area of a control which excludes non-client elements such as Borders, Menus, ScrollBars, TitleBar etc.; it's "inner-body".
The client area definition can, however, change in relation to a control's internal structure (imagine a ListView or a ComboBox control, for example) .
The Paint() event of a control is raised each time a control needs to repaint itself.
It's always raised after a control is first created.
After that, it could be triggered when, for example, a control is for some reasons "obscured" by another control/window or when the Form that contains it is minimized.
It can be raised "manually" invoking the control's Invalidate() method.
This is probably the prefered way to force a control to repaint itself, because the Invalidate() method allows to specify a defined portion (a Rectangle or a Region) of a control that needs repainting, limiting the painting to this area.
You could modify your code this way:
public Form1()
{
InitializeComponent();
pictureBox1.Paint += new PaintEventHandler(this.pictureBox1_Paint);
pictureBox2.Paint += new PaintEventHandler(this.pictureBox2_Paint);
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.FillEllipse(Brushes.Red, new Rectangle(40, 40, 20, 20));
e.Graphics.FillEllipse(Brushes.Red, new Rectangle(40, 80, 20, 20));
e.Graphics.FillEllipse(Brushes.Red, new Rectangle(80, 40, 20, 20));
e.Graphics.FillEllipse(Brushes.Red, new Rectangle(80, 80, 20, 20));
}
private void pictureBox2_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.FillEllipse(Brushes.Red, new Rectangle(40, 40, 20, 20));
e.Graphics.FillEllipse(Brushes.Red, new Rectangle(40, 80, 20, 20));
e.Graphics.FillEllipse(Brushes.Red, new Rectangle(80, 40, 20, 20));
e.Graphics.FillEllipse(Brushes.Red, new Rectangle(80, 80, 20, 20));
}
SmoothingMode = SmoothingMode.AntiAlias is used to "prettify" the graphics results.
It which will generate smoother borders.
The Drawing Brush used is a stock object (system-provided) which doesn't need to be Disposed(). If you create a Brush using one of the brush related classes, the object you create must be disposed.
using (SolidBrush brush = new SolidBrush(Color.Red))
{
e.Graphics.FillEllipse(brush, new Rectangle(40, 40, 20, 20));
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
Below I've created a program using C# that creates a smiley face. It also moves across the screen. I cannot figure out how to get the smiley face to bounce off the edges and around the screen. Please Help. Thank you.
*/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 HappyFace
{
public partial class HappyFace : Form
{
int xpos = 0;
int ypos = 0;
int width = 0;
int length = 0;
int startAngle = 45;
int sweepAngle = 90;
public HappyFace()
{
InitializeComponent();
}
private void HappyFace_Load(object sender, EventArgs e)
{
}
private void HappyFace_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
Pen myPen = new Pen(Brushes.Red, 7);
Pen myPen2 = new Pen(Brushes.Green, 7);
//g.DrawLine(myPen, 0, 0, 500, 500);
//g.DrawLine(myPen, 0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height);
//g.DrawLine(myPen2, 0, this.ClientRectangle.Height, this.ClientRectangle.Width, 0);
//g.DrawLine(myPen2, this.ClientRectangle.Left, this.ClientRectangle.Bottom, this.ClientRectangle.Right, ClientRectangle.Top);
int endX = this.ClientRectangle.Width;
int endY = this.ClientRectangle.Height;
//string msg = String.Format("endX = {0} endY = {1}", endX, endY);
//MessageBox.Show(msg);
int xCenter = this.ClientRectangle.Left + (this.ClientRectangle.Width / 2);
int yCenter = this.ClientRectangle.Top + (this.ClientRectangle.Height / 2);
Pen circlePen = new Pen(Brushes.Black, 9);
//g.DrawEllipse(circlePen, xCenter - 50, yCenter - 50, 100, 100);
// g.FillEllipse(Brushes.Orange, xCenter -50, yCenter - 50, 100, 100);
Font myFont = new Font("Monotype Corsiva", 43, FontStyle.Bold);
g.DrawString("Happy Face", myFont, Brushes.Aqua, 300, 25);
//g.DrawArc(circlePen, xpos, width, length, startAngle, sweepAngle);
g.DrawEllipse(circlePen, xpos, ypos + 130, 250, 250);
g.FillEllipse(Brushes.PeachPuff, xpos, ypos + 130, 250, 250);
g.DrawEllipse(circlePen, xpos + 65, ypos + 200, 20, 35);
g.FillEllipse(Brushes.Black, xpos + 65, ypos + 200, 20, 35);
g.DrawEllipse(circlePen, xpos + 160, ypos + 200, 20, 35);
g.FillEllipse(Brushes.Black, xpos + 160, ypos + 200, 20, 35);
g.DrawArc(circlePen, xpos + 60, ypos + 215, 130, 120, 35, 115);
}
private void timer1_Tick(object sender, EventArgs e)
{
xpos = xpos + 3;
if(xpos >= this.ClientRectangle.Right - 250)
{
xpos = 0;
}
this.Invalidate();
}
}
}*/
Well, I was a bit bored. I'll assume that the object is going to move in a 45 degrees trajectory,and that when it collides with the bounds it would change by 90ยบ.
What I would do (this is a very simple solution) is, first of all, define the direction in both axes in which i want the "smiley" to move,the step in each timer tick, the position of the center and the size of the object, something like:
int xpos = 0;
int ypos = 130;
int step = 10;
int width = 250;
int height = 250;
int directionX = +1;
int directionY = -1;
The timer would just increase the x and y positions:
private void timer1_Tick(object sender, EventArgs e)
{
xpos += 10*directionX;
ypos += 10*directionY;
checkBounds(); //This would check if the object collides with the bounds
this.Invalidate();
}
The checkBounds method check if the object collides with the bounds:
private void checkBounds()
{
if (ypos < 0 + step || ypos + height+ step > ClientRectangle.Height)
{
directionY *= -1;
}
if (xpos < 0 + step || xpos + width + step > ClientRectangle.Width)
{
directionX *= -1;
}
}
Finally, the Paint method is similar to yours, just adjusting some values:
private void Form2_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
Pen myPen = new Pen(Brushes.Red, 7);
Pen myPen2 = new Pen(Brushes.Green, 7);
int endX = this.ClientRectangle.Width;
int endY = this.ClientRectangle.Height;
int xCenter = this.ClientRectangle.Left + (this.ClientRectangle.Width / 2);
int yCenter = this.ClientRectangle.Top + (this.ClientRectangle.Height / 2);
Pen circlePen = new Pen(Brushes.Black, 9);
Font myFont = new Font("Monotype Corsiva", 43, FontStyle.Bold);
g.DrawString("Happy Face", myFont, Brushes.Aqua, 300, 25);
g.DrawEllipse(circlePen, xpos, ypos, 250, 250);
g.FillEllipse(Brushes.PeachPuff, xpos, ypos, 250, 250);
g.DrawEllipse(circlePen, xpos + 65, ypos -130 + 200, 20, 35);
g.FillEllipse(Brushes.Black, xpos + 65, ypos-130 + 200, 20, 35);
g.DrawEllipse(circlePen, xpos + 160, ypos-130 + 200, 20, 35);
g.FillEllipse(Brushes.Black, xpos + 160, ypos-130 + 200, 20, 35);
g.DrawArc(circlePen, xpos + 60, ypos-130 + 215, 130, 120, 35, 115);
}
This code could be highly improved, but this may help you think how it should be done. Hope it helps.
I'm trying to write a program that, given my choice of variables, depicts a smiley on screen.
I've written the following.
Now my program asks three questions, which I will answer with numbers between 0 and 11. I would like to use these answers in the method 'tekenscherm'. How can I call these variables in that method?
class HalloForm : Form
{
public string a,b,c = ""; //Declare them here.
public HalloForm()
{
this.Text = "Hallo";
this.BackColor = Color.Yellow;
this.Size = new Size(800, 600);
this.Paint += this.tekenScherm;
}
public static void Main()
{
System.Console.WriteLine("Smiley size, on a scale of 1 tot 10?");
string a = System.Console.ReadLine();
Int32.Parse(a);
System.Console.WriteLine("X coordinate of the smiley, on a scale of 1 to 10");
string b = System.Console.ReadLine();
Int32.Parse(b);
System.Console.WriteLine("Y coordinate of the smiley, on a scale of 1 to 10");
string c = System.Console.ReadLine();
Int32.Parse(c);
HalloForm scherm;
scherm = new HalloForm();
Application.Run(scherm);
}
void tekenScherm(object obj, PaintEventArgs pea)
{
SolidBrush blueBrush = new SolidBrush(Color.Blue);
Pen blackBrush = new Pen(Color.Black, 5);
int x = 360;
int y = x + 75;
pea.Graphics.FillEllipse(blueBrush, 300, 200, 200, 200);
pea.Graphics.DrawEllipse(blackBrush, 300, 200, 200, 200);
pea.Graphics.DrawArc(blackBrush, 350, 250, 100, 100, 45, 90);
pea.Graphics.DrawEllipse(blackBrush, a, 250, 5, 5); //I've used it here
pea.Graphics.DrawEllipse(blackBrush, y, 250, 5, 5);
}
}
Declare those variables outside of the method scope as integers.
Int32.Parse returns an integer value, which you are not assigning to those variables, so it's basically doing nothing the way you are using it.
Here is the working code:
class HalloForm : Form
{
public int a, b, c = 0; //Declare them here.
public HalloForm()
{
this.Text = "Hallo";
this.BackColor = Color.Yellow;
this.Size = new Size(800, 600);
this.Paint += this.tekenScherm;
}
public static void Main()
{
System.Console.WriteLine("Smiley size, on a scale of 1 tot 10?");
a = Int32.Parse(System.Console.ReadLine());
System.Console.WriteLine("X coordinate of the smiley, on a scale of 1 to 10");
b = Int32.Parse(System.Console.ReadLine());
System.Console.WriteLine("Y coordinate of the smiley, on a scale of 1 to 10");
c = Int32.Parse(System.Console.ReadLine());
HalloForm scherm;
scherm = new HalloForm();
Application.Run(scherm);
}
void tekenScherm(object obj, PaintEventArgs pea)
{
SolidBrush blueBrush = new SolidBrush(Color.Blue);
Pen blackBrush = new Pen(Color.Black, 5);
int x = 360;
int y = x + 75;
pea.Graphics.FillEllipse(blueBrush, 300, 200, 200, 200);
pea.Graphics.DrawEllipse(blackBrush, 300, 200, 200, 200);
pea.Graphics.DrawArc(blackBrush, 350, 250, 100, 100, 45, 90);
pea.Graphics.DrawEllipse(blackBrush, x, 250, 5, 5);
pea.Graphics.DrawEllipse(blackBrush, y, 250, 5, 5);
}
}
I'm trying to have a rectangle that changes size based on a value, But I cannot get it to update. If I draw the rectangle with set values it shows up, But if I then add a "*" operator to it, it does not show.
I've never used winform graphics before, this is based on other posts i've come across.
The code:
private void Send()
{
int l = 25, r = 20; // Testing values
using (Graphics g = this.MainPanel.CreateGraphics())
{
Brush brush = new SolidBrush(Color.LimeGreen);
g.FillRectangle(brush, 59, 74, 16, 56 * (l / 100));
g.FillRectangle(brush, 81, 74, 16, 56 * (r / 100));
brush.Dispose();
this.Invalidate();
}
string start = l + ":" + r + ".";
char[] end = start.ToCharArray();
port.Write(new string(end));
}
This bit of code runs every 15ms if that matters.
Use RectangleF instead. The height of your calculated rectangle is 0, because the int value is rounded to 0 when you're dividing. Better use float and RectangleF.
Also, in my opinion is better to calculate the rectangle you need to draw in the method Send(), and then invalidate the Form. You paint the rectangles in the method OnPaint() of the form. For example:
private void Send()
{
float l = 25, r = 20; // Testing values
mRectangle1 = new RectangleF(59, 74, 16, 56 * (l / 100));
mRectangle2 = new RectangleF(81, 74, 16, 56 * (r / 100));
Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
using (Brush brush = new SolidBrush(Color.LimeGreen))
{
e.Graphics.FillRectangle(brush, mRectangle1);
e.Graphics.FillRectangle(brush, mRectangle2);
}
}
private RectangleF mRectangle1;
private RectangleF mRectangle2;
And this is the result:
Hope it helps.
I want to draw several figures on the PictureBox. I expected that the following code will draw a rectangle with it's full size diagonal, but it doesn't. Line do not connected with bottom-right corner of rectangle. I'm really curious what may be wrong?
private void onPaint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
Pen p = new Pen(System.Drawing.Color.Black, 2);
g.DrawRectangle(p, 50, 10, 400, 400);
g.DrawLine(p, 50, 10, 400, 400);
}
In DrawRectangle, the last two arguments are width and height. In DrawLine, the last two arguments are final x and final y.
So just add the starting x and starting y to the width and height to get your diagonal line:
g.DrawRectangle(p, 50, 10, 400, 400);
g.DrawLine(p, 50, 10, 450, 410);
Also, if you declare a Rectangle then you can change the values without needing to change the drawing code. Something like:
private void onPaint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
Rectangle rc = new Rectangle(50, 10, 400, 400);
using (Pen p = new Pen(System.Drawing.Color.Black, 2))
{
g.DrawRectangle(p, rc);
g.DrawLine(p, rc.Left, rc.Top, rc.Right, rc.Bottom);
}
}