Can I draw to a panel on a transparent WinForm? - c#

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:

Related

How to create a Windows Form in C# that can be seen only but can not be clicked or brought to focus

I am working on an Accessibility Screen Reader application that will put a rectangle highlighter around the element that is selected on the Focused program. I am able to detect the currently focused AutomationElement, and get its BoundingRectangle property. (How is Spy++ element highlighting working?)
Given a rectangle's topLeftCorner and bottomRightCorner, I am trying to draw a highlighter rectangle using the code below:
internal class HighlighterForm : Form
{
public HighlighterForm(Point topLeftCorner, Point bottomRightCorner, float borderWidth=5){
int length = bottomRightCorner.X - topLeftCorner.X;
int width = bottomRightCorner.Y - topLeftCorner.Y;
this.Text = "Highlighter";
this.FormBorderStyle = FormBorderStyle.None;
this.StartPosition = FormStartPosition.Manual;
this.Location = new Point(topLeftCorner.X, topLeftCorner.Y);
this.TopLevel = true;
this.TopMost = true;
this.Size = new Size(length, width);
// Make the Form background transparent
this.TransparencyKey = Color.Turquoise;
this.BackColor = Color.Turquoise;
this.Paint += (o, e) => {
Graphics g = e.Graphics;
using (Pen selPen = new Pen(Color.Blue, borderWidth*2))
{
g.DrawRectangle(selPen, 0, 0, length, width);
}
};
}
}
And then, I am using the following snippet to create the highlighter:
Point topLeftCorner = new Point(10, 50);
Point bottomRightCorner = new Point(600, 200);
HighlighterForm highlighter = new HighlighterForm(topLeftCorner, bottomRightCorner);
highlighter.ShowDialog();
This can draw a rectangle anywhere on the screen, but the problem is that this form does not let any contents found on an app under the rectangle to be selected. For example, if the currently selected element is a page from Microsoft Word, then the user won't be able to select a paragraph because the rectangle is on top.
How can I make sure the rectangle is there only visually and cannot be interacted with or clicked on?

Styling Windows Form Tab

I am creating windows Tabbed Application. Everything is good but the tabs are quiet faded and borders are very dull. I have tried changing the border style to 3D as well but no effect. Below is the screenshot
There are forums where people have suggested to use third party library to make Google Chrome type tabs. But I want the native way to get beautiful tabs.
You can take control of how the tabs are drawn by setting the DrawMode = TabDrawMode.OwnerDrawFixed. The example below assumes you have a TabControl named tabControl1 on the form, this will add a new tab with a blue box.
private Rectangle myTabRect;
private Rectangle myInsideRect;
private Rectangle myOutsideRect;
public Form1()
{
InitializeComponent();
TabPage tabPage1 = new TabPage();
// Sets the tabs to be drawn by the parent window Form1.
// OwnerDrawFixed allows access to DrawItem.
tabControl1.DrawMode = TabDrawMode.OwnerDrawFixed;
tabControl1.Controls.Add(tabPage1);
tabControl1.Location = new Point(25, 25);
tabControl1.Size = new Size(250, 250);
tabPage1.TabIndex = 0;
myTabRect = tabControl1.GetTabRect(0);
myInsideRect = new Rectangle(tabControl1.DisplayRectangle.X -1, tabControl1.DisplayRectangle.Y -1, tabControl1.DisplayRectangle.Width + 1, tabControl1.DisplayRectangle.Height + 1);
myOutsideRect = tabControl1.ClientRectangle;
myOutsideRect.Width--;
myOutsideRect.Height--;
ClientSize = new Size(300, 500);
Controls.Add(tabControl1);
tabControl1.DrawItem += new DrawItemEventHandler(OnDrawItem);
}
private void OnDrawItem(object sender, DrawItemEventArgs e)
{
// Draw your tab graphics here
Graphics g = e.Graphics;
Pen p = new Pen(Color.Blue);
g.DrawRectangle(p, myTabRect);
p = new Pen(Color.Red);
g.DrawRectangle(p, myInsideRect);
p = new Pen(Color.Green);
g.DrawRectangle(p, myOutsideRect);
}
You can draw whatever style you like into the graphic context, add text, images, etc

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.

Writing a string to panel with Forms Load Event

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.

painting on a pictureBox from another thread

im having some problems... code is below:
delegate void SetCanvasDelegate(PictureBox canvas);
public void SetCanvas(PictureBox canvas)
{
if (this.canvas.InvokeRequired)
this.canvas.Invoke(new SetCanvasDelegate(SetCanvas), new object[] { canvas });
else
this.canvas = canvas;
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
PictureBox canvas = new PictureBox();
Graphics g = Graphics.FromHwnd(canvas.Handle);
RadarElement player = new RadarElement(new Point(150, 150), RadarElementType.Player);
List<Enemy> enemies = new List<Enemy>();
ores.Add(new Enemy(new Point(100, 100)));
g.DrawLine(new Pen(Color.Black), new Point(0, 0), new Point(100, 100));
if (trackEnemies.Checked)
foreach (Enemy e in enemies)
g.DrawImage(Image.FromFile("enemy.png"), e.Position);
SetCanvas(canvas);
Thread.Sleep(500);
}
}
this.canvas is the PictureBox in my Form1.
All of this is within my Form1 class... but the pictureBox in my form is not updated to show enemy.png as above in the code. What is wrong and how do i correct it?
Looks like you're trying to replace the PictureBox of your form with one that's being created within your bw_DoWork method. This won't work the way you expect it to. You need to do your painting on an image object and then stick that painted image into your form's picturebox. If it still doesn't show, use Invalidate as Daren Thomas suggested.
You probably need to do something along the lines of
Bitmap canvas = new Bitmap(width, height);
using(Graphics g = Graphics.FromImage(canvas))
{
// paint here
}
SetCanvas(canvas);
and then modify your SetCanvas method accordingly to accept an Image instead of a PictureBox.
Did you Invalidate the pictureBox?

Categories