How to draw text on picturebox? - c#

I googled for "Drawing text on picturebox C#" ,but I couldnt find anything useful.Then I googled for "Drawing text on form C#" and I found some code,but it doesnt work the way I want it to work.
private void DrawText()
{
Graphics grf = this.CreateGraphics();
try
{
grf.Clear(Color.White);
using (Font myFont = new Font("Arial", 14))
{
grf.DrawString("Hello .NET Guide!", myFont, Brushes.Green, new PointF(2, 2));
}
}
finally
{
grf.Dispose();
}
}
When I call the function,the background color of the form becomes white(it's black by default).
My questions:
1:Will this work on a picturebox?
2:How to fix the problem?

You don't want that call to Clear() - that's why it's turning the background white, and it will cover up your picture.
You want to use the Paint event in the PictureBox. You get the graphics reference from e.Graphics, and then use the DrawString() that you have in your sample.
Here's a sample. Just add a picture box to your form, and add an event handler for the Paint event:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
using (Font myFont = new Font("Arial", 14))
{
e.Graphics.DrawString("Hello .NET Guide!", myFont, Brushes.Green, new Point(2, 2));
}
}
(Note that you won't see the text at design time - you'll have to run the program for it to paint).

Related

Draw ellipse with PaintEventArgs

I have a simple Photoshop-made grid and i would like to use it as progress bar, i need to draw round ellipses from 1 to 100 (then probably about 100 times in x time).
If I use System.Graphic I have not persistent result.
Then I found the code to use the PaintEventArgs method by inserting instructions in the Paint Event of the form.
Unfortunately in my mind this is not a solution because I need to draw only when I need and only where I want.... in other word I need a simple Function able to draw desired ellipses when I need...
I tried also to override the OnPaint-base but I really don't understand how to use it and if may help to reach my goal.
Here some code:
With the paint event:
private void Main_Paint(object sender, PaintEventArgs e)
{
// Create pen.
Pen blackPen = new Pen(Color.Yellow, 3);
// Create rectangle for ellipse.
Rectangle rect = new Rectangle(355, 282, 9, 9);
e.Graphics.DrawEllipse(blackPen, rect);
}
With the Graphic mode:
private void lbl_help_Click(object sender, EventArgs e)
{
//SetStatus("BURNING PROCESS COMPLETED SUCCESSFULLY");
Graphics g = this.CreateGraphics();
// Create pen.
Pen blackPen = new Pen(Color.Yellow, 3);
// Create rectangle for ellipse.
Rectangle rect = new Rectangle(355, 282, 9, 9);
// Draw ellipse to screen.
g.DrawEllipse(blackPen, rect);
System.Threading.Thread.Sleep(3000);
}
And this one I found to override OnPaint(), but I really don't know how to use it, how to override the form-paint event or how to call it only when needed and passing values:
private void lbl_help_Click(object sender, EventArgs e)
{
//SetStatus("BURNING PROCESS COMPLETED SUCCESSFULLY",);
Graphics g = this.CreateGraphics();
// Create pen.
Pen blackPen = new Pen(Color.Yellow, 3);
// Create rectangle for ellipse.
Rectangle rect = new Rectangle(355, 282, 9, 9);
// Draw ellipse to screen.
g.DrawEllipse(blackPen, rect);
System.Threading.Thread.Sleep(3000);
}
Something other other:
I imagine if I use variables to store the percentage and call a paint-refresh of the form (maybe invalidate?) to update the result should work but I will lose any sort of animation, elsewhere I come-back to a non persistent state again... I need to use the grid as a progress bar, adding circles only at desired time, without losing the back drawings...
The grid I need to fill is very simple, here a screenshot:
Sry I should not post image for the reputation (i'm a new user!), here the link
EDIT:
I solved the smoothing problem (at least with the Graphic Mode):
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

PictureBox.Invalidate not re-rendering correctly

I'm trying to build a little test application (and my WinForm skills have rusted somewhat) with an Image and some overlays on top of it.
My image is set to stretch in the PictureBox but my fields on the right hand side I want to be from the origin of the image. Therefore I decided to render directly on the image that the PictureBox is using to ensure that the co-ordinates are always correct. Here's the white box rendering:
private void pbImage_Paint(object sender, PaintEventArgs e)
{
try
{
if (this.rdFront.Checked)
RenderFront(pbImage.Image, true);
else
RenderBack(pbImage.Image, true);
}
catch (ArgumentNullException ex)
{ }
}
public void RenderFront(Image image, bool includeBoxes)
{
// If we have no image then we can't render
if (image == null)
throw new ArgumentNullException("image");
Graphics gfx = Graphics.FromImage(image);
// Get the top label
foreach (MessageConfiguration config in this.config.Values.Where(c => c.Front))
{
if (includeBoxes)
{
// Fill a White rectangle and then surround with a black border
gfx.FillRectangle(Brushes.White, config.X, config.Y, config.Width, config.Height);
gfx.DrawRectangle(Pens.Black, config.X - 1, config.Y - 1, config.Width + 2, config.Height + 2);
}
gfx.DrawString(config.Text, new Font(FontFamily.GenericMonospace, config.FontSize), Brushes.Black, new PointF(config.X, config.Y));
}
}
The problem that I've got is if I do this and always draw on the underlying image then when I move the white overlay, I end up with un-drawn parts of the image. So I decided to clone the image before each re-render (on the basis that I don't care about performance).
I therefore decided to clone the image whenever I need to manually invalidate it, and call this when a setting changes:
public void Refresh()
{
if (this.rdFront.Checked)
pbImage.Image = new Bitmap(front);
else
pbImage.Image = new Bitmap(back);
this.pbImage.Invalidate();
}
Now I'm sure I must be missing something obvious - if I modify one of the values my penguins render with no overlay. However if I force a resize of the application then both the penguins and the overlay suddenly appear.
Can anyone suggest what I might be doing wrong?
Edit
Here's a download link to the project as it's quite small. Paste a path to an image in the 'Front Image' box and try using the controls on the right (set 100x100 height and width). Try re-sizing to see the desired affect. https://dl.dropboxusercontent.com/u/41796243/TemplateTester.zip
Controls and Forms have a Refresh method already. Are you really calling your Refresh method? Aren't you getting a warning that you should use the new keyword? Better give your Refresh method another name (e.g RefreshImage)!
I'm really not sure why you are using a picture box but then decide to do your on painting. I suggest to draw to an image off-screen and then simply assign it to the picture box:
public void RefreshImage()
{
Bitmap bmp;
if (this.rdFront.Checked)
bmp = new Bitmap(front);
else
bmp = new Bitmap(back);
using (Graphics gfx = Graphics.FromImage(bmp)) {
foreach (MessageConfiguration config in this.config.Values.Where(c => c.Front))
{
if (includeBoxes) {
// Fill a White rectangle and then surround with a black border
gfx.FillRectangle(Brushes.White, config.X, config.Y, config.Width, config.Height);
gfx.DrawRectangle(Pens.Black, config.X - 1, config.Y - 1, config.Width + 2, config.Height + 2);
}
gfx.DrawString(config.Text, new Font(FontFamily.GenericMonospace, config.FontSize), Brushes.Black, new PointF(config.X, config.Y));
}
}
pbImage.Image = bmp;
}
and remove the pbImage_Paint method.
Another possibility is to use the pbImage_Paint event handler in another way. Call the base.Paint() handler of the picture box that draws the image but leave the image itself unchanged. Instead draw on top of it by using the Graphics object given by the PaintEventArgs e argument. This Graphics object represents the client area of the picture box. This does not alter the Bitmap assigned to the picture box, but only draws on the screen.
private void pbImage_Paint(object sender, PaintEventArgs e)
{
base.Paint(); // Paints the image
if (this.rdFront.Checked)
RenderFront(e.Graphics, true);
else
RenderBack(e.Graphics, true);
}
public void RenderFront(Graphics g, bool includeBoxes)
{
foreach (MessageConfiguration config in this.config.Values.Where(c => c.Front)) {
if (includeBoxes) {
g.FillRectangle(Brushes.White, config.X, config.Y, config.Width, config.Height);
g.DrawRectangle(Pens.Black, config.X - 1, config.Y - 1, config.Width + 2, config.Height + 2);
}
g.DrawString(config.Text, new Font(FontFamily.GenericMonospace, config.FontSize), Brushes.Black, new PointF(config.X, config.Y));
}
}

User defined painting not visible

I have a Windows Forms application with a GroupBox, and a PictureBox as background image, and several clickable OvalShapes from the PowerPack.
Now I need some labels for the OvalShapes, so I put a EventHandler on my GroupBox that on every repaint, the following should be drawn
this.groupBoxTest.Paint += new System.Windows.Forms.PaintEventHandler(this.groupBoxVirtualView_Paint);
private void groupBoxVirtualView_Paint(object sender, PaintEventArgs e)
{
Graphics g = groupBoxVirtualView.CreateGraphics();//e.Graphics;
g.DrawString("01", new Font("Arial", 12), new SolidBrush(Color.Black), 240, 115);
}
But the string 01 never gets drawn; all I see are the oval shapes that are at the same position - disabling them for testing purpose doesn't do it either.
What's happening to my string?
Any other way to label my PoweredOval?
You have to use
groupBoxVirtualView.Invalidate();
to repaint the groupBox!
The paint event should use the graphic object from the sender:
private void groupBoxVirtualView_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.DrawString("01", new Font("Arial", 12), new SolidBrush(Color.Black), 240, 115);
}
Also, if there is a PictureBox inside the GroupBox, that control will not show any of the GroupBox paintings to come through the control. It will hide it.

How to do Free hand Image Cropping in C# window application?

How to do Free hand Image Cropping in C# window application??
Okay, you provided very small amount of information, but I'll assume that you are using winforms. There are some tasks dealing with freehand-technique such as:
Drawing
Drag-n-dropping
Cropping
Selecting
They all are very similar. Let's assume that you have a PictureBox and want to crop an image inside it.
// Current selection
private Rectangle _cropRectangle;
// Starting point
private Point _cropStart;
// Dragging flag
private bool _isDragging;
private void pBox_MouseDown(object sender, MouseEventArgs e)
{
_cropRectangle = new Rectangle(e.X, e.Y, 0, 0);
_isDragging = true;
}
private void pBox_MouseUp(object sender, MouseEventArgs e)
{
_isDragging = false;
}
private void pBox_MouseMove(object sender, MouseEventArgs e)
{
if (!_isDragging)
return;
_cropRectangle = new Rectangle(Math.Min(_cropStart.X, e.X),
Math.Min(_cropStart.Y, e.Y),
Math.Abs(e.X - _cropStart.X),
Math.Abs(e.Y - _cropStart.Y));
pBox.Invalidate();
}
private void pBox_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawRectangle(Pens.Red, _cropRectangle);
}
What happens: I make use of three mouse events (MouseDown, MouseUp, MoseMove) and the Paint event. Basically, whenever you want to do anything from the above list, you'll have handle these four events.
I tried to keep the code short and self-explanatory. There are four event handlers working with three instance fields. The fields are used to store the current state of dragging process.
Feel free to customize the code, especially the pBox_Paint handler. Mine just draws a thin red rectangle around selected area. You might want to do something more elaborate here.
Whenever you're done with your rectangle, you can call the Crop method:
private Image Crop()
{
Bitmap croppedImage = new Bitmap(_cropRectangle.Width, _cropRectangle.Height);
using (Graphics g = Graphics.FromImage(croppedImage))
{
g.DrawImage(pBox.Image, 0, 0, _cropRectangle, GraphicsUnit.Pixel);
}
return croppedImage;
}
It creates a new Bitmap and put the selected portion of source image into it. The returned Image object might be used in any manner you like.
EDIT: trying to simplify the code I made some mistakes earlier, fixed now.
You can use Graphics.DrawImage to draw a cropped image onto the graphics object from a bitmap.
Rectangle cropRect = new Rectangle(...);
Bitmap src = Image.FromFile(fileName) as Bitmap;
Bitmap target = new Bitmap(cropRect.Width, cropRect.Height);
using(Graphics g = Graphics.FromImage(target))
{
g.DrawImage(src, cropRect,
new Rectangle(0, 0, target.Width, target.Height),
GraphicsUnit.Pixel);
}
You can also refer the full code for this....
Refer this *Link*

Problem with CreateGraphics and drawing strings

The control below draws a string in a rectangle. On mouse move there is a hit test on the string rectangle, and the string is redrawn via CreateGraphics. The irritating problem is that the text is not drawn the same as in the Paint handler; it appears to be displaced by about 1 pixel, and the effect is like a bold font. How can I create a graphics object exactly like the one in the Paint handler so the text is drawn the same way? Ordinarily you would invalidate and redraw everything in the Paint event, but I have potentially hundreds of of other drawing items and only want to draw the string. Should I try to do any drawing outside of the Paint event or is this a mistake?
Example control:
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Test.TestModes
{
public partial class ExampleControl: UserControl
{
private const string testString = "0123456789";
private RectangleF stringRect = new RectangleF(10, 10, 100, 20);
public ExampleControl()
{
InitializeComponent();
}
private void ExampleControl_Paint(object sender, PaintEventArgs e)
{
Font font = new Font("Arial", 12, FontStyle.Regular);
e.Graphics.DrawString(testString, font, Brushes.Black, stringRect);
font.Dispose();
}
private void DrawString(bool hit)
{
Font font = new Font("Arial", 12, FontStyle.Regular);
using(Graphics g = CreateGraphics())
{
g.SetClip(ClientRectangle);
if(hit)
g.DrawString(testString, font, Brushes.Red, stringRect);
else
g.DrawString(testString, font, Brushes.Black, stringRect);
}
font.Dispose();
}
private void ExampleControl_MouseMove(object sender, MouseEventArgs e)
{
if(stringRect.Contains(e.Location))
DrawString(true);
else
DrawString(false);
}
private void button1_Click(object sender, EventArgs e)
{
Invalidate();
}
}
}
It is the CreateGraphics() call that is getting you in trouble, indirectly. The problem is anti-aliasing of the text. A normal painting cycle erases the background before drawing something on top. That doesn't happen in your case, your draw text on top of existing text. The side effect is that the pixels uses to create the aliasing get darker each time your draw. The end result is bold looking, and noticeably jagged text outlines.
The fix is easy: start with a clean slate before you draw:
using (Graphics g = CreateGraphics()) {
g.Clear(this.BackColor); <=== added
g.SetClip(ClientRectangle);
// etc..
}
You'll now also get to encounter a problem in drawing known as "flicker". It might not yet be that noticeable yet, but it will when you do more drawing. Flicker is suppressed with double-buffering. A feature supported by Windows Forms, but only if you use standard drawing techniques. In other words: no CreateGraphics().

Categories

Resources