I'm attempting to draw a think underline underneith my header about 10-15 px thick. I've tried adding a picture box and then drawing to that, but it's not being drawn to the screen. Is there a better way to do this, or a way to make my method work?
Thanks!
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Graphics g = pictureBox1.CreateGraphics();
Pen selPen = new Pen(Color.Black);
g.DrawRectangle(selPen, 0, 0, 700, 15);
g.Dispose();
}
}
}
The reason your code doesn't work is because you cannon draw in from 1 load event. Place your code into another event or in a button and it will work fine.
Don't use CreateGraphics() as it is a temporary surface that gets erased when the form refreshes.
Instead, handle the Paint() event of your Form/Control and use the supplied e.Graphics to draw with.
A common trick for having thick lines in WinForms is to create a Label with BorderStyle set to FixedSingle (you can experiment with other borders) and Height = 1 (Width as appropriate). You can draw all this in the designer, or try to use some other "degenerate" controls - Panel with appropriate visual settings.
Other options are of course using a custrom UserControl or handling/overriding the OnPaint event and drawing on the graphics provided by the Control.CreateGraphics method (no need to put PictureBox on the form).
Related
WinForms Project
Im trying to draw to an image then draw that to a window that is external to my application using:
using(var g = Graphics.FromHandle(handle))
g.DrawImage(myImage);
to reduce flickering behavior when drawing.
I know that I can use the BufferedGraphics class, but it had a black background so I tried to draw a transparent image to it first and then draw on top of that but it still had a black background when rendering it.
Is there any way to use BufferedGraphics or a way of drawing once to memory so it can be drawn as a whole image at once (to reduce flickering) to screen with a transparent background?
i assume that you are using a timer and drawing the image each time the tick event fires and that's the reason of the flickering
So, first create a winform, i am putting the backColor to red so you can see the transparency of the background better
Add one timer and turn on the tick event
Then choose an image with transparency in png, one like this:
Put it in the directory where you start your application from
Finally this is the code, it's fully functional, i tested already :v
using System;
using System.Collections.Generic;
using System.ComponentModel;
System.Data;
System.Drawing;
System.IO;
System.Linq;
System.Text;
System.Threading.Tasks;
System.Windows.Forms;
namespace so
{
public partial class Form1 : Form
{
Image image;
public Form1()
{
image = Image.FromFile("imagen.png");
InitializeComponent();
}
private void timer1_Tick(object sender, EventArgs e)
{
Graphics gr = this.CreateGraphics();
BufferedGraphicsContext bgc = BufferedGraphicsManager.Current;
BufferedGraphics bg = bgc.Allocate(gr,this.ClientRectangle);
//before drawing the image clean the background with the current form's Backcolor
bg.Graphics.Clear(this.BackColor);
//use any overload of drawImage, the best for your project
bg.Graphics.DrawImage(image,0,0);
bg.Render(gr);
}
}
}
Maybe i didn't understand correctly your answer, but this will avoid the flickering and show one image with transparent background without any problem :)
The task is a simple concept, just not sure about a simple method to do what I'm asking.
Goal
Have a textbox, label, custom User Control, or some other type of control show multiline text and fade it out half way down (as seen in image below). I would like to have it be transparent (as seen in the image) and be editable of course. I was thinking of something like a custom UserControl : label or something similar. Maybe override the label's OnPaint and draw the form contents (everything behind the control) to emulate transparency. Then draw the text but somehow maybe apply some type of gradient filter to it? I honestly have no clue how I would do it but hoping someone else does.
Thanks!
I worked out a solution and it looks perfect, I'll need to spend more time on it later adding support for text align etc. But for now I ended up coming up with this...
Note: Create a new User Control and add this in the code area. Also
keep in mind to make sure the designer of that new control uses the
same namespace "InfinityLabel". And one last thing, don't forget to set your
new label (InfinityLabel) to BackColor=Transparent.
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
namespace InfinityLabel
{
public partial class InfinityLabel : Label
{
public InfinityLabel()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs e)
{
Rectangle rect = new Rectangle(0, 0, Width, Height);
LinearGradientBrush brush =
new LinearGradientBrush(
rect,
Color.FromArgb(255, ForeColor),
Color.FromArgb(60, ForeColor),
90f);
e.Graphics.DrawString(Text, Font, brush, rect);
}
}
}
I am using Visual Studio 2013 to write a Windows Forms C# application. I want to draw game board on Form1_Load and draw pawns on button click. I have written two methods: InitDraw() and Draw(). When both method are in Form1_Load() or button1_Click() it's OK, but if InitDraw() is in Form1_Load() and Draw() is in button1_Click() - it draws only if I press Alt or move windows out of screen and move back to screen. I added Invalidate() but this does not help.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
Bitmap drawBitmap;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
InitDraw();
}
private void button1_Click(object sender, EventArgs e)
{
Draw();
}
private void InitDraw()
{
drawBitmap = new Bitmap(500, 500);
pictureBox1.Image = drawBitmap;
}
private void Draw()
{
Graphics g = Graphics.FromImage(pictureBox1.Image);
Pen myPen = new Pen(Color.Black);
g.DrawLine(myPen, 0, 0, 100, 100);
myPen.Dispose();
g.Dispose();
Invalidate();
}
}
}
Nobody's stopping you from drawing wherever you want, the thing to remember is to do it on a bitmap image instead of trying to force it to screen. By this I mean you need to create your own Bitmap object, and any draw functions you call you call them on this.
To actually get this to show on screen, call the Invalidate function on the host control -- not a PictureBox by the way. Something lightweight like a panel will do. And in that control's Paint event simply draw your image.
You were sort of close, but you calling Invalidate on the form, besides the fact that it's horribly inefficient to redraw everything when you know exactly what needs to be redrawn, simply won't do anything. You don't rely on the Paint event, but on the intrinsic binding a PictureBox has with a Bitmap -- Bitmap who's handle you never change. As far as the PictureBox is concerned, everything is the same so it won't actually paint itself again. When you actually force it to paint itself by dragging the window outside the screen bounds and then back in it will read the bitmap and draw what you expect.
You must draw in the Paint event of the picture box. Windows might trigger the Paint event at any moment, e.g. if a window in front of it is removed or the form containing the picturebox is moved.
What you draw on the screen is volatile; therefore, let Windows decide when to (re-)draw. You can also trigger redrawing with
picturebox1.Invalidate();
or
picturebox1.Refresh();
Difference: Invalidate waits until the window is idle. Refresh draws immediately.
If you only draw in Form_Load or Button_Click, your drawing might get lost, when windows triggers a paint on its own. Try calling picturebox1.Invalidate in these events instead.
I have a panel control that I want to fill up with gradient. I have the following code:
Brush brush = new LinearGradientBrush(pnlBody.ClientRectangle, Color.Black, Color.White, LinearGradientMode.ForwardDiagonal);
pnlBody.CreateGraphics().FillRectangle(brush, pnlBody.ClientRectangle);
But it has no effect. If I replace pnlBody with form, then it colors the form fine, but not panel. Any ideas what I'm doing wrong? Thanks!
A Panel control will paint itself with its Paint event. Which wipes out anything you paint by using CreateGraphics(). You'll need to use its Paint event instead. This will however produce flicker, you'll see it paint its background first. Panel is also optimized to act as a container control with low impact paint overhead, you'll see it not repaint itself when it is resized. An issue when you anchor it to the right or bottom and resize the form.
To fix these issues, you should derive your own class from Panel. Add a new class to your project and paste this code:
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
public class GradientPanel : Panel {
public GradientPanel() {
this.ResizeRedraw = true;
}
protected override void OnPaintBackground(PaintEventArgs e) {
using (var brush = new LinearGradientBrush(this.ClientRectangle,
Color.Black, Color.White, LinearGradientMode.ForwardDiagonal)) {
e.Graphics.FillRectangle(brush, this.ClientRectangle);
}
}
protected override void OnScroll(ScrollEventArgs se) {
this.Invalidate();
base.OnScroll(se);
}
}
Build + Build. Drop the new control from the top of the toolbox onto your form, replacing the original panel. You can get creative by adding properties that select the gradient start and end colors, producing a more generally useful control that can be reused in other projects. Do avoid the panel showing a scrollbar, you cannot make the scrolling look decent because of the Windows "Show window content while dragging" feature. The effect is somewhat similar to the pogo.
I am trying to integrate Winforms with a SharpDX project, in order to use Winforms (and eventually WPF via HostElement) in my 3D app.
I need to create or configure a Control or Form such that I can:
a. Render it to a texture (that I can display as a sprite*)
b. Filter its input to remove mouse/keyboard events when the control is not active.
I have tried subclassing Control and Form, to override the OnPaint and OnPaintBackground but these have no effect on the child controls - or for that matter the forms borders (and even if they did they are not sufficient on their own as I am still left with a white square where I presume the 'parent' has been drawn).
How can I stop a Control or Form painting to the screen and instead draw only to a bitmap? (Is there some way I can override Graphics before the tree is painted, for example?)
*It needs to be done this way (as opposed to letting the control render to the screen) as Winforms doesn't support true transparency, so I need to clip colour coded pixels in my pixel shader.
(To confirm, I don't mean a DirectX texture specifically - I am happy with (in fact would prefer) a simple System.Drawing Bitmap)
Here is one way to start going about it:
Create a derived control class so that we can expose InvokePaint which is protected
Call our custom method to get the Control's image
Test form needs a picture box and an instance of Mybutton
using System;
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1() { InitializeComponent(); }
private void Form1_Load(object sender, EventArgs e)
{
// create image to which we will draw
var img = new Bitmap(100, 100);
// get a Graphics object via which we will draw to the image
var g = Graphics.FromImage(img);
// create event args with the graphics object
var pea = new PaintEventArgs(g, new Rectangle(new Point(0,0), new Size(100,100)));
// call DoPaint method of our inherited object
btnTarget.DoPaint(pea);
// modify the image with algorithms of your choice...
// display the result in a picture box for testing and proof
pictureBox.BackgroundImage = img;
}
}
public class MyButton : Button
{
// wrapping InvokePaint via a public method
public void DoPaint(PaintEventArgs pea)
{
InvokePaint(this, pea);
}
}
}