I am trying to draw a string using DrawString() method on a panel(panel1). I want this to happen when the form(Form1) loads. But that doesn't happen. But the string is drawn, if I use the same code(given below) in the click event handler for panel1. Where am I doing it wrong?
private void Form1_Load(object sender, EventArgs e)
{
/*string rand = getRandomString();
textBox1.Text = rand;*/
string rand = "Hello";
SolidBrush sbr = new SolidBrush(Color.Black);
Graphics g = panel1.CreateGraphics();
FontFamily fam = new FontFamily("Magneto");
Font font = new System.Drawing.Font(fam, 24, FontStyle.Bold);
g.DrawString(rand, font, sbr, new Point(20, 20));
}
The code you posted only gets executed once - when the form has a redraw triggered (such as getting another form over it, etc) it will dissapear. The same goes for your method in the button click event.
The way to draw onto the panel is as follows:
private void Panel1_Paint(object sender, PaintEventArgs e)
{
var g = e.Graphics;
/*string rand = getRandomString();
textBox1.Text = rand;*/
string rand = "Hello";
using (var sbr = new SolidBrush(Color.Black))
{
FontFamily fam = new FontFamily("Magneto");
Font font = new System.Drawing.Font(fam, 24, FontStyle.Bold);
g.DrawString(rand, font, sbr, new Point(20, 20));
}
}
The paint event for a control fires each time a redraw is required, so whatever you draw will not disappear unexpectedly.
This event happens before the form is displayed. So after you draw the text on the panel, panel is repainted and your changes are lost.
Even the text drawn later during Click event will disappear if the form is repainted, so you need to handle Panel control's Paint event and do your drawing there.
Related
I made an user control and I draw a rectangle directly in the window, like this (this is a simplified version):
private int rec_len = 200;
private void Draw_()
{
Pen pn = new Pen( Color.Black, WIDTH_LINE );
Graphics graph = this.CreateGraphics();
graph.Clear( Color.Transparent );
this.Refresh();
graph.DrawRectangle( pn, 20, 10, rec_len, 40 );
this.Refresh();
graph.Dispose();
}
public void button_Build_Click( object sender, EventArgs e )
{ rec_len += 10; Draw_(); }
The strange thing is that the second refresh actually poses a problem: if I comment it out, the rectangle is visible, if I let it in the code, the rectangle is not visible. In the real code I have to draw more than a rectangle and I want the refresh at the end, otherwise the background is visible between the moment I erase old drawing and the moment the new one is ready.
The surface of a control is not stored: When you paint on a control, the drawing is not saved and need to be redrawn each time the control is repainted (After a refresh for example). To create a persistante graphic, you can create a bitmap, draw on the bitmap and assign this bitmap to the BackgroundImage property.
Bitmap bmp = new Bitmap(WIDTH, HEIGHT);
void Initialize()
{
this.BackgroundImage = bmp;
}
private int rec_len = 200;
private void Draw_()
{
Pen pn = new Pen(Color.Black, WIDTH_LINE);
using (Graphics graph = Graphics.FromImage(bmp))
{
graph.Clear(Color.Transparent);
this.Refresh();
graph.DrawRectangle(pn, 20, 10, rec_len, 40);
this.Refresh();
}
}
public void button_Build_Click(object sender, EventArgs e) { rec_len += 10; Draw_(); }
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.
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.
After seeing that drawing to the desktop is extremely messy, I decided just to research around. I figured out that many people suggest creating a transparent WinForm that is the size of the screen and smacking a panel on there and using that to draw graphics. So I tested it out but ran into many errors. At first, my second form (Form2) wouldn't show, so I had to put it into another thread and put Form2.ShowDialog(); on that thread. After I got that problem out of the way, I actually drew to the panel. Now my form will never show, but I can see it running on my taskbar. Everytime I try to make it the focused window, it never works, and whenever I hover the task I can see the graphics being created. My question is, is it possible to draw to a panel on a transparent WinForm and make it visible? Here's the code I used, it's mostly for looking for errors (drawing the states and stuff).
void Draw()
{
while (true)
{
SolidBrush redpen = new SolidBrush(Color.Red);
Font font = new Font("Arial", 16);
PointF point = new PointF(700, 150);
Graphics g = panel1.CreateGraphics();
g.DrawString(Main.state.ToString(), font, redpen, point);
Main.beginTime.Stop();
Main.TimeRan = Main.beginTime.Elapsed;
string amountOfTime = string.Format("{0:00}:{1:00}:{2:00}.{3:00}", Main.TimeRan.Hours, Main.TimeRan.Minutes, Main.TimeRan.Seconds, Main.TimeRan.Milliseconds / 10);
point = new PointF(700, 200);
g.DrawString(amountOfTime, font, redpen, point);
Thread.Sleep(10);
panel1.Refresh();
}
}
private void Form2_Shown(object sender, EventArgs e)
{
Draw();
}
Somewhere in my main class
// In a method
Thread F2T = new Thread(FormHandlers);
F2T.Start();
private void FormHandlers()
{
Form2 Form2 = new Form2();
Form2.Opacity = 0.00;
Form2.ShowDialog();
}
Edit: After some testing, I noticed that with the decrease of opacity the letter's opacity decreases as well, can I make it so the panel is transparent but the string I'm drawing to draw inside of it is not?
I guess you want to draw a message on a transparent child form? if that, I think you could do as follow: because the form.Opacity =0.00 makes all the controls in it be transparent, so we can't see anything. Another way, we use form.TransparencyKey to get that. code like this:
public Form2()
{
InitializeComponent();
//hide the border of form
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.BackColor = Color.White;
//set the TransparencyKey the same as the back color
this.TransparencyKey = this.BackColor;
}
protected override void OnPaint(PaintEventArgs e)
{
SolidBrush redpen = new SolidBrush(Color.Red);
Font font = new Font("Arial", 16);
PointF point = new PointF(400, 150);
Graphics g = e.Graphics;
string state = "running";
g.DrawString(state, font, redpen, point);
string amountOfTime = string.Format("{0:00}:{1:00}:{2:00}.{3:00}", 1, 2, 3, 11111 / 10);
PointF point2 = new PointF(500, 150);
g.DrawString(amountOfTime, font, redpen, point2);
//base.OnPaint(e);
}
by the way, you want to show message in a child form, I don't prefer to use multi-threading, you just invoke the Form2 in Show() not in ShowDialog(), and set Form2.TopMost=True, than you can operate your main form as well. try it.
my result is bellow:
I use the below code to set a gradient to a button in a windows form. It works but it's Text is not showing. What should I do to fix it?
Thank you.
private void Form1_Load(object sender, EventArgs e)
{
button2.Paint += new PaintEventHandler(this.Button2_Paint);
}
private void Button2_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.FillRectangle(new System.Drawing.Drawing2D.LinearGradientBrush(PointF.Empty, new PointF(button2.Width, button2.Height), Color.Pink, Color.Red), new RectangleF(PointF.Empty, button2.Size));
}
It's because you never actually drawing that text. Currently you only filling button's client rectangle with gradient, but there is no any text within. To show the string with button's text you need to add some more lines to Paint method:
private void Button2_Paint(object sender, PaintEventArgs e)
{
Button btn= (Button)sender;
Graphics g = e.Graphics;
g.FillRectangle(new System.Drawing.Drawing2D.LinearGradientBrush(PointF.Empty, new PointF(button2.Width, button2.Height), Color.Pink, Color.Red), new RectangleF(PointF.Empty, button2.Size));
SizeF size = g.MeasureString(btn.Text, btn.Font);
PointF topLeft = new PointF(btn.Width / 2 - size.Width / 2, btn.Height / 2 - size.Height / 2);
g.DrawString(btn.Text, btn.Font, Brushes.Black, topLeft);
}
Here Graphics.MeasureString gives you the width and height of a button's Text property, these values are used to position text right in the middle of a button. And Graphics.DrawString just draws the string with supplied color, font and position.