Run method at application start [duplicate] - c#

I'm drawing up a day schedule and representing timeslots with panels, and appointments are yet more panels on top.
The user is able to scroll up and down so that the range they can see is shifted earlier or later. When an appointment runs off the end of the visible range, I want there to be a zig-zag indicating that the appointment extends beyond the visible bounds.
I've identified the case where this occurs, and I call a private function drawZigZag(Panel p, int direction); to draw it. The day is spread horizontally, and the direction -1 indicates a zigzag on the left and 1 indicates a zigzag on the right.
So far, I'm not up to the zigzag yet, I'm just experimenting with CreateGraphics() and FillPolygon(). So far I have:
private void drawZigZag(Panel p, int direction) // 1 = right, -1 = left
{
Graphics g = p.CreateGraphics();
g.FillRectangle(new SolidBrush(Color.FromArgb(0, Color.Black)), p.DisplayRectangle);
Point[] points = new Point[4];
points[0] = new Point(0, 0);
points[1] = new Point(0, p.Height);
points[2] = new Point(p.Width, p.Height);
points[3] = new Point(p.Width, 0);
Brush brush = new SolidBrush(Color.DarkGreen);
g.FillPolygon(brush, points);
}
The first FillRectangle() I didn't originally have. I only added that when the FillPolygon() didn't work.
Basically, it's not working and I'm not sure why. The panel is the original colour - it hasn't been filled DarkGreen. I've used CreateGraphics() before for other things, and I'm not really sure why it's not working in this instance. Any ideas?
Edit: Sorry, I thought I should mention: There are several Label controls on my Panel which describe the appointment. These shouldn't be covered if possible.

You need to call this method from the paint event handler, not just whenever you like. So in your constructor you might have:
panel1.Paint += new PaintEventHandler(panel1_Paint);
and then the implementation:
private void panel1_Paint( object sender, PaintEventArgs e )
{
var p = sender as Panel;
var g = e.Graphics;
g.FillRectangle( new SolidBrush( Color.FromArgb( 0, Color.Black ) ), p.DisplayRectangle );
Point[] points = new Point[4];
points[0] = new Point( 0, 0 );
points[1] = new Point( 0, p.Height );
points[2] = new Point( p.Width, p.Height);
points[3] = new Point( p.Width, 0 );
Brush brush = new SolidBrush( Color.DarkGreen );
g.FillPolygon( brush, points );
}

For example we have this drawing event which is drawing a text from textBox1:
private void panel1_draw(object sender, PaintEventArgs e)
{
var g = e.Graphics;
Pen myp = new Pen(System.Drawing.Color.Red, 4);
Font fy = new Font("Helvetica", 10, FontStyle.Bold);
Brush br = new SolidBrush(System.Drawing.Color.Red);
g.DrawString(textBox1.Text, fy, br, 0,0);
}
In order to draw on your panel1, you need to write this code in your button event handler:
private void button1_Click(object sender, EventArgs e)
{
panel1.Paint+=new PaintEventHandler(panel1_draw);
panel1.Refresh();
}
The first line draws the text in your panel and if you want the text to appear you must refresh the panel.
The main thing is in using the panel1.Pain += new PaintEventHandler(your void name); and panel1.Refresh();

Related

Adding element to another element win forms

I am adding one panel to another panel it works but circle which is in inspanel not shown. how can i solved this.
I am using below code. It works but not show circle
public static int xTemp = 0;
public static int yTemp = 0;
private void button1_Click(object sender, EventArgs e)
{
Panel insPanel = new Panel();
Random xRandom = new Random();
xTemp= xRandom.Next(20,100);
Random yRandom = new Random();
yTemp = yRandom.Next(20, 100);
insPanel.Location = new Point(xTemp, yTemp);
insPanel.Width=40;
insPanel.Height = 40;
insPanel.Visible = true;
insPanel.BorderStyle = BorderStyle.FixedSingle;
insPanel.Paint += new PaintEventHandler(insPanel_Paint);
panel1.Controls.Add(insPanel);
}
void insPanel_Paint(object sender, PaintEventArgs e)
{
System.Drawing.SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Red);
System.Drawing.Graphics formGraphics =this.CreateGraphics();
formGraphics.FillEllipse(myBrush, new Rectangle(xTemp,yTemp, 10, 10));
myBrush.Dispose();
formGraphics.Dispose();
}
Main issue: you're trying to draw your circle at wrong coordinates.
xTemp and yTemp are coordinates of insPanel relative to panel1. But when you drawing your circle, you should use coordinates relative to panel you're drawing at - insPanel.
Another issue: there is no need to create and dispose graphics each time you're drawing something on your panel. You can use e.Graphics from Paint eventhandler arguments.
Based on above, your code could look like:
void insPanel_Paint(object sender, PaintEventArgs e)
{
using (var myBrush = new SolidBrush(Color.Red))
{
e.Graphics.FillEllipse(myBrush, new Rectangle(0, 0, 10, 10));
}
}
Also note - since paint event can occur very frequently, it could be a good idea not to create and dispose brush every time, but use brush cached in your class private field.
Use e.Graphics instead of this.CreateGraphics:
System.Drawing.Graphics formGraphics = e.Graphics;
One more issue is you're getting coordinates in range of 20 - 100 (xRandom.Next(20,100)) and your panel dimensions are just 40, 40.

Drawing lines on a panel

I try to make a graphics.
When I click on my label, I want to draw a line. It works, it draw my line but at the last point there is another line going at the left top corner.. I don't know why.
(It's useless, but it's for another project, I try to understand how works the drawing)
Here's my code :
public partial class Form1 : Form
{
Pen myPen = new Pen(Color.Blue);
Graphics g = null;
int start_x = 0, start_y;
Point[] points = new Point[1000];
int test = 0;
public Form1()
{
InitializeComponent();
start_y = canvas.Height / 2;
points[0] = new Point (start_x,start_y);
myPen.Width = 1;
}
private void drawLine()
{
g.DrawLines(myPen, points);
}
private void incrementation_Click(object sender, EventArgs e)
{
test = test + 1;
incrementation.Text = test.ToString();
if(test == 1)
{
points[1] = new Point(100, start_y);
}
if (test == 2)
{
points[test] = new Point(200, 90),new Point(220, 10);
}
if (test == 3)
{
points[test] = new Point(220, 10);
drawLine();
}
}
private void canvas_Paint(object sender, PaintEventArgs e)
{
g = canvas.CreateGraphics();
}
}
A couple of issues.
You don't assign any values to points after points[3].
Point is a structure and will have a value of [0,0] at all further elements
so your lines go there.. (all 996 of them ;-)
There is more you should change:
Do the drawing in the Paint event or trigger it from there.
Do not store the Paint e.Grahpics object. You can pass it out to use it, but don't try to hold on to it.
After adding or changing the points, write canvas.Invalidate() to trigger the Paint event. This will make your drawing persistent.
To learn about persistent drawing minimize & restore the form!
Also you should use a List<Point> instead of an array. This lets you add Points without having to decide on the number of Points you want to support..
To create a new Point you write something like this:
points.Add(new Point(100, start_y) );
To draw you then use this format in the Paint event::
e.Graphics.DrawLines(myPen, points.toArray());
In the constructor you're filling first point as
points[0] = new Point (start_x,start_y);
At this moment, start_x = 0 (since you're not assigned anything else to it after declaration int start_x = 0).
Then in incrementation_Click you're assigning points[1], points[2] and points[3], but you don't changing anywhere in your code points[0].
So when you calling g.DrawLines - first point will always be (0, canvas.Height / 2)
Aside from this:
You don't need to create graphics explicitly in _Paint event handler since it can accessed as e.Graphics.
It's better to move all paintings into canvas_Paint like:
private void canvas_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawLines(myPen, points);
}
and in your _Click handler instead of calling drawLine you should only call canvas.Refresh()

call Paint event of picturebox from PageLoad in C# causes an error

I create a PictureBox that get lots of point and draws a map for my application ,so these point is read from database ,so when i move the scroll of my picturebox to see other part of my map ,the paint event is called again ,and my application have to read the points from databse to draw map ,but it doesn't need ,because i read that before ,so reading data from database makes my application to be so slow ,so i try to locate my code in Paint event to Page_load ,because this transfering makes my code to be run just one time ,
So let me explain my code :
private void pictureBoxMetroMap_Paint(object sender, PaintEventArgs e)
{
Pen pLine = new Pen(Color.White, 2);
SolidBrush RedBrush = new SolidBrush(ColorTranslator.FromHtml("#cc0000"));
SolidBrush blueBrush = new SolidBrush(ColorTranslator.FromHtml("#0066ff"));
SolidBrush greenBrush = new SolidBrush(ColorTranslator.FromHtml("#3db300"));
SolidBrush whiteBrush = new SolidBrush(ColorTranslator.FromHtml("#fff"));
SensorRepository objSensorRepository = new SensorRepository();
List<Sensor> lstSensorLeft = objSensorRepository.GetSensorsLine(1, "Left");
List<Point> lstPointLeft = new List<Point>();
foreach (var t in lstSensorLeft)
{
Point objPoint = new Point(t.XLocation, t.YLocation);
lstPointLeft.Add(objPoint);
Rectangle rectSens = new Rectangle(t.XLocation, t.YLocation, 3, 3);
e.Graphics.FillRectangle(whiteBrush, rectSens);
if (t.StationId != null)
{
Rectangle rectEhsansq = new Rectangle(t.XLocation-6, t.YLocation-6, 12, 12);
e.Graphics.FillRectangle(blueBrush, rectEhsansq);
Rectangle rectTrainState = new Rectangle(t.XLocation -3, t.YLocation-3, 7, 7);
e.Graphics.FillRectangle(RedBrush, rectTrainState);
}
}
StationRepository ObjStationRepository = new StationRepository();
List<Sensor> lstSensorRight = objSensorRepository.GetSensorsLine(1, "Right");
List<Point> lstPointRight = new List<Point>();
foreach (var t in lstSensorRight)
{
Point objPoint = new Point(t.XLocation+30, t.YLocation+30);
lstPointRight.Add(objPoint);
Rectangle rectSens = new Rectangle(t.XLocation+30, t.YLocation+30, 3, 3);
e.Graphics.FillRectangle(whiteBrush, rectSens);
if (t.StationId!= null)
{
Rectangle rectPosition= new Rectangle(t.XLocation + 24, t.YLocation + 24, 12, 12);
e.Graphics.FillRectangle(blueBrush, rectPosition);
Rectangle rectTrainState = new Rectangle(t.XLocation + 27, t.YLocation + 27, 7, 7);
e.Graphics.FillRectangle(RedBrush, rectTrainState);
}
}
e.Graphics.DrawLines(pLine, lstPointLeft.ToArray());
e.Graphics.DrawLines(pLine, lstPointRight.ToArray());
}
This is Pain event of my picturebox that after every scroll movement is called .I need to transfer this code to page_Load.I did that but my problem is how can i handle these values :
(object sender, PaintEventArgs e)
Because the page_load doesnt any PaintEventArgs argument.I mean how can i tranfer this code to page_load
My page_load :
private void frmMain_Load(object sender, EventArgs e)
{
FormBorderStyle = FormBorderStyle.None;
}
Best regards
You shouldn't read from a database in OnPaint and you shouldn't draw on the screen in OnLoad.
So divide the work: in OnLoad, fetch and store the data. In OnPaint, draw the cached data.

How to align separator in ContextMenuStrip

Here is my code for ContextMenuStrip:
ContextMenuStrip _menuStrip = new ContextMenuStrip();
Image image = new Bitmap("icon_main.ico");
_menuStrip.Items.Add("First item", image);
ToolStripSeparator stripSeparator1 = new ToolStripSeparator();
stripSeparator1.Alignment = ToolStripItemAlignment.Right;//right alignment
_menuStrip.Items.Add(stripSeparator1);
_menuStrip.Items.Add("Second item", image);
ToolStripSeparator stripSeparator = new ToolStripSeparator();
stripSeparator.Alignment = ToolStripItemAlignment.Left;//left alignment
_menuStrip.Items.Add(stripSeparator);
_menuStrip.Items.Add("Exit", image, OnClickExit);
_mainIcon.ContextMenuStrip = _menuStrip;
Strange thing is that separators are not aligned - I have a little space between edge of ContextMenuStrip and separator, even if I try to align the separator (I've tried both - left and right alignment):
It's not a big graphical failure, but I'm asking myself how this can be aligned perfectly:
Any ideas what should I do?
You should use Paint event (msdn):
...
ToolStripSeparator stripSeparator = new ToolStripSeparator();
stripSeparator.Paint += stripSeparator_Paint;
_menuStrip.Items.Add(stripSeparator);
...
Paint event handler:
void stripSeparator_Paint(object sender, PaintEventArgs e)
{
ToolStripSeparator stripSeparator = sender as ToolStripSeparator;
ContextMenuStrip menuStrip = stripSeparator.Owner as ContextMenuStrip;
e.Graphics.FillRectangle(new SolidBrush(Color.Transparent), new Rectangle(0, 0, stripSeparator.Width, stripSeparator.Height));
using (Pen pen = new Pen(Color.LightGray, 1))
{
e.Graphics.DrawLine(pen, new Point(23, stripSeparator.Height / 2), new Point(menuStrip.Width, stripSeparator.Height / 2));
}
}

C# Winforms - Owner-drawn listbox with multiple colors in the same line

I found an article that does exactly what I need. It draws multiple colors on the same line on a text box. But the problem is that it was written in VB.NET and I'm writing my program in C#. Any good soul can convert this to C# if it is possible and if it isn't can you give me other options? Thanks.
This is the article: http://www.vbrad.com/article.aspx?id=34.
here is the conversion of what you posted Nicolas
if you need to change / get anything else working you will need to test it on your end..
Happy coding
private void MeasureItemHandler(object sender, MeasureItemEventArgs e)
{
Graphics g = Graphics.FromHwnd(lstColor.Handle);
StringFormat sf = new StringFormat(StringFormat.GenericTypographic);
SizeF size = default(SizeF);
float height = 0;
Font oFont = new Font("Arial", 10);
//measure the height of what you are about to draw
//and let the listbox know this
size = g.MeasureString(data(e.Index), oFont, 500, sf);
height = size.Height + 5;
e.ItemHeight = height;
}
private void DrawItemHandler(object sender, DrawItemEventArgs e)
{
Graphics g = Graphics.FromHwnd(lstColor.Handle);
StringFormat sf = new StringFormat(StringFormat.GenericTypographic);
SizeF size = default(SizeF);
float width = 0;
Font oFont = new Font("Arial", 10);
//get the width of the string you are about to write
//this info is needed so that we can offset the next
//string that will be drawn in a different color.
size = g.MeasureString(data(e.Index), oFont, 500, sf);
width = size.Width + 16;
//prepare the list for drawing
e.DrawBackground();
e.DrawFocusRectangle();
//draw the first string in a certain color
e.Graphics.DrawString(data(e.Index), oFont, new SolidBrush(color(e.Index)), e.Bounds.X, e.Bounds.Y);
//draw the second string in a different color
e.Graphics.DrawString(data(data.Length - 1 - e.Index), oFont, new SolidBrush(color(color.Length - 1 - e.Index)), width, e.Bounds.Y);
}
First of all, they aren't using a Textbox in this article, they are using a Listbox but what follows is a conversion of the code from VB.Net to C# like you asked. It needs tidied up a bit but it does the job.
Just create a new Windows Form, place a Listbox called lstColor onto this form, change the DrawMode property to OwnerDrawFixed inside the properties window, then add event handlers for DrawItem and MeasureItem (you can add event handlers by clicking on the lightning bolt in the Properties window, and double clicking the whitespace beside these two words in the list).
In the DrawItem event handler, add the following:
private void lstColor_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e)
{
var size = g.MeasureString(data[e.Index], oFont, 500, sf);
var width = size.Width + 16;
e.DrawBackground();
e.DrawFocusRectangle();
e.Graphics.DrawString(data[e.Index], oFont, new SolidBrush(color[e.Index]), e.Bounds.X, e.Bounds.Y);
e.Graphics.DrawString(data[data.Length - 1 - e.Index], oFont, new SolidBrush(color[color.Length - 1 - e.Index]), width, e.Bounds.Y);
}
In the MeasureItem event handler, add this:
private void lstColor_MeasureItem(object sender, MeasureItemEventArgs e)
{
var size = g.MeasureString(data[e.Index], oFont, 500, sf);
var height = size.Height;
e.ItemHeight = Convert.ToInt32(height);
}
Add five private fields outside the scope of any methods but inside your Form1 (or whatever you've called your form) class like so:
private string[] data;
private Color[] color;
private Font oFont;
private Graphics g;
private StringFormat sf;
Put the following three lines inside your Form1_Load event:
private void Form1_Load(object sender, EventArgs e)
{
oFont = new Font("Arial", 10);
data = new string[] { "This is Red", "This is Blue", "This is Green", "This is Yellow", "This is Black", "This is Aqua", "This is Brown", "This is Cyan", "This is Gray", "This is Pink" };
color = new Color[] {Color.Red, Color.Blue, Color.Green, Color.Yellow, Color.Black, Color.Aqua, Color.Brown, Color.Cyan, Color.Gray,Color.Pink};
lstColor.DataSource = data;
g = Graphics.FromHwnd(lstColor.Handle);
sf = new StringFormat(StringFormat.GenericTypographic);
}
And you are all set.
Hope this helps
Check out http://converter.telerik.com/ It converts code from VB.NET to C# and C# to VB.NET. It wont work on complex code, but could prove useful to you.

Categories