I have a picturebox that has an image in it and a top of this image I am drawing some ellipses. However, only some of the ellipses show up. Code looks something like this:
Graphics g = Graphics.FromHwnd(pictureBox1.Handle);
g.FillEllipse(redBrush, rfidNode1.readerPos.X, rfidNode1.readerPos.Y, 15, 15);
EDIT: I'm sorry I copied and pasted the last line twice...so there is only one line that fills the ellipse. Also, x and y are within the range of the picture box.
Could you try something like this? (change the dimensions if needed)
Bitmap bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);
Graphics g = Graphics.FromImage(bmp);
g.FillEllipse(redBrush, rfidNode1.readerPos.X, rfidNode1.readerPos.Y, 15, 15);
pictureBox1.Image = bmp;
Or maybe I missed your intentions?
If the X and Y are same, you are drawing two ellipses one on top another, so only the last is visible. Also, it could be that the X and Y are out of bounds of picture box ?
try to override the paint event and place there your painting code. drawing processes run very often, and then your graphic just gets overdrawn.
Tutorial - Drawing with C#
For drawing on a control, try to register with the paint-event and use the graphics object provided in the paint event args.
Look here for details and an example.
I' m not very sure if it really possible in secure way draw over picture box. Secure I mean: to be sure that all your ellipses are visible when you want. If you want some custom behaviuor, PictureBox is not so good solution, by me.
Like a solution I would suggest to draw an image manually in place where now you have picture box.
Hope this helps.
Regards.
Related
I want to use a PictureBox as a canvas and draw some text on it and save.
I wrote this piece of code but I'm not sure if im doing this the correct way:
Bitmap b = new Bitmap(pictureBox1.Width, pictureBox1.Height);
Graphics g = Graphics.FromImage(b);
g.FillRectangle(new SolidBrush(Color.White), new Rectangle(0, 0, pictureBox1.Width, pictureBox1.Height)); // i used this code to make the background color white
g.DrawString("some text", new Font("Times New Roman", 20), new SolidBrush(Color.Red), new PointF(10, 10));
pictureBox1.Image = b;
This code works well but when I want to change the background color of the image I have to redraw the text.
Is there a way to change the background color without having to redraw the text?
Writing a Paint program is a lot of fun, but you need to plan ahead for all or most of the features you want.
So far you have these:
A background you can change
A way to modify an image by drawing text on it
The need to save it all to a file
Here are a few more things you will need:
Other tools than just text, like lines, rectangles etc..
A choice of colors and pens with widths
A way to undo one or more steps
Here are few thing that are nice to have:
A way to help with drawing and positioning with the mouse
Other type backgrounds like a canvas or pergament paper
The ability to draw with some level of tranparency
A redo feature (*)
Rotation and scaling (***)
Levels (*****)
Some things are harder (*) or a lot harder (***) than others, but all get hard when you decide to patch them on too late..
Do read this post (starting at 'actually') about PictureBoxes, which explain how it is the ideal choice for a Paint program.
Your original piece of code and your question have these problems:
You seem to think that repeating anything, like redrawing the text is wrong. It is not. Windows redraws huge numbers of things all the time..
You have mixed two of the tasks which really should be separate.
You have not parametrizied anything, most notably the drawing of the text should use several variables:
Font
Brush
Position
the text itself
The same will be true once you draw lines or rectangles..
So here are the hints how do get it right:
Use the BackgroundColor and/or the BackgroundImage of the Picturebox to dynamically change the background!
Collect all things to draw in a List<someDrawActionclass>
Combine all drawings by drawing it into he Picturebox's Image
Use the Paint event to draw supporting things like the temporary rectangle or line while moving the mouse. On MouseUp you add it to the list..
So, coming to the end, let's fix your code..:
You set the backgound with a function like this:
void setBackground(Color col, string paperFile)
{
if (paperFile == "") pictureBox1.BackColor = col;
else pictureBox1.BackgroundImage = Image.FromFile(paperFile);
}
you can call it like this: setBackground(Color.White, "");
To draw a piece of text into the Image of the PictureBox, first make sure you have one:
void newCanvas()
{
Bitmap bmp = new Bitmap(pictureBox1.ClientSize.Width, pictureBox1.ClientSize.Height);
pictureBox1.Image = bmp;
}
Now you can write a function to write text. You really should not hard-code any of the settings, let alone the text! This is just a quick and very dirty example..:
void drawText()
{
using (Font font = new Font("Arial", 24f))
using (Graphics G = Graphics.FromImage(pictureBox1.Image))
{
// no anti-aliasing, please
G.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixel;
G.DrawString("Hello World", font, Brushes.Orange, 123f, 234f);
}
pictureBox1.Invalidate();
}
See here and here for a few remarks on how to create a drawAction class to store all the things your drawing is made up from..!
The last point is how to save all layers of the PictureBox:
void saveImage(string filename)
{
using (Bitmap bmp = new Bitmap(pictureBox1.ClientSize.Width,
pictureBox1.ClientSize.Height))
{
pictureBox1.DrawToBitmap(bmp, pictureBox1.ClientRectangle);
bmp.Save("yourFileName.png", ImageFormat.Png);
}
}
I am trying to figure out how to use the picturebox zoom, but I want to be able to keep the hard edges, When I zoom, the picture is blurry and not pixelated. Does anyone know how to do this?
Which is the exact component you are using? This is typically solved by switching the ImageStretch or ImageFit to NearestNeighbour. It's an filtering/interpolation setting that you are looking for.
PictireBox supports only basic zooming algorithms. As long as you have your image stored in memory you can implement your own zooming algorithms and feed the zoomed image to PictireBox and disabling any zooming features of the latter.
You can use this library that implement advanced zooming algorithms.
You would have to custom-draw it using the lowest-possible quality for resizing. To custom-draw a control, you would handle its Paint event some way or another (ideally, you would subclass but I will make it more simple) so in the Paint handler for your PictureBox, place this code:
Graphics g = e.Graphics;
PictureBox picbox = (PictureBox)sender;
g.Clear(picbox.BackColor);
g.InterpolationMode = InterpolationMode.Low;
// Draw the image using g.DrawImage()
Hey everyone, a new guy here in C#.Net.
I'm trying to make an application like Ms Paint, of course much simpler, and I'm stuck.
The problem is this.
In pictureBox, I'm drawing grid lines on the PictureBox, after that I'm reading a .map(A Mapper3 file) and want to draw onto grid lines, but When I draw the map, The grid lines disappers.
I think the problem is because of the PictureBox Image becomes null while I'm drawing the map. How can I overcome this, is there any tricks?
Thanks for the replies from now on, and sorry for my bad English...
My best Regards...
Do you using winforms? If yes, you actually dont need picture box for working area. I think more appropriate would be Graphics class on form or panel. You have lost lines because of form repaint circle, put your drawing code into form paint handler and picture would be repainted when it needed. In some cases you can need to manual trigger repaint circle, for this purposes you should use Invalidate method of your form.
For example, add this code to paint handler:
private void Form1_Paint(object sender, PaintEventArgs e)
{
// Drawing vertical lines
for (int x = 5; x < this.ClientRectangle.Width; x+=5)
{
e.Graphics.DrawLine(Pens.Gray, new Point(x, 0), new Point(x, this.ClientRectangle.Height));
}
// Drawing horisontal lines
for (int y = 5; y < this.ClientRectangle.Width; y += 5)
{
e.Graphics.DrawLine(Pens.Gray, new Point(0, y), new Point(this.ClientRectangle.Width,y));
}
}
You also may use Graphics in button click handler this way:
Graphics g = Graphics.FromHwnd(this.Handle);
g.FillEllipse(Brushes.Beige, new Rectangle(10, 10, 10, 10));
But in this case all you have drawn would be erased during form's repaint circle and you will have to repeint it in form paint handler
[EDIT]
Ok, for example you have pictureBox1 on your form, you can easly draw into it with help of Bitmap class in this way:
// Draw into bitmap
Bitmap bmp = new Bitmap(150, 150);
Graphics g = Graphics.FromImage(bmp);
g.FillRectangle(Brushes.Green, new Rectangle(25, 75, 10, 30));
// Set bitmap into picture box
pictureBox1.Image = bmp;
In this case you have no need to redraw your paintings, picture box would do it for you. Dont forget to set BackColor ot picture box to Transparent if you prefer to show paintings from below of picture box.
You have to draw everything including the grid lines whenever the paint event raised, if you are concerned about performance you may detect the clipping area and only draw that portion.
Good luck.
I have drawn a circle in windows form
Pen pen = new Pen(Color.Black, 3);
Graphics gr = this.CreateGraphics();
gr.DrawEllipse(pen, 5,5,20,20);
How to delete it...
You have to clear your Graphic:
Graphics.Clear();
But all drawn figures will be cleared. Simply, you will then need to redraw all figures except that circle.
Also, you can use the Invalidate method:
Control.Invalidate()
It indicates a region to be redrawn inside your Graphics. But if you have intersecting figures you will have to redraw the figures you want visible inside the region except the circle.
This can become messy, you may want to check out how to design a control graph or use any graph layout library.
You can invalidate the draw region you want to refresh for example:
this.Invalidate();
on the form...
Assuming you're subscribing to the Paint event or overriding the protected OnPaint routine, then you will need to perform something like this:
bool paint = false;
protected override void OnPaint(object sender, PaintEventArgs e)
{
if (paint)
{
// Draw circle.
}
}
Then when you want to stop painting a circle:
paint = false;
this.Invalidate(); // Forces a redraw
You can make a figure of same dimensions using the backColor of your control in which you are drawing
use after your code to clear your figure.
Pen p = new Pen(this.BackColor);
gr.DrawEllipse(p, 5,5,20,20);
In fact, you can delete your circle and nothing but your circle.
Everything you need is something like a screenshot of the "before state" of the area you want to clear, to make a TextureBrush from it. You can achieve that step by something like this:
Bitmap _Background = new Bitmap(this.Width, this.Height);
Graphics.FromImage(_Background).CopyFromScreen(this.Left, this.Top, 0, 0, this.Size);
The first line will give you a bitmap in your windows forms size. The second line will save a screenshot of it in the _Background-bitmap.
Now you create a TextureBrush out of it:
Brush brsBackground = new TextureBrush(_Background);
The next thing you need are the dimensions of your circle, so you should save them into a variable, if they are not a fix value. When you got them at hand, you can clear the specific area like this:
Graphics gr = this.CreateGraphics();
gr.FillEllipse(brsBackground, 5, 5, 20, 20); // values referred to your example
Done!
Even complex figures are able to be deleted by this, like a GraphicsPath for example:
GraphicsPath gp = new GraphicsPath(); // any kind of GraphicsPath
gr.FillRegion(brsBackground, new Region(gp));
You don't "delete" it per se, there's nothing to delete. It's a drawing, you draw something else over it or you can call the Graphics.Clear() method.
If u are using Invalidate() and is not working, make a panel.Refresh().
That will work on you.
just make another control with the attributes etc. that you want, make the visibility to false and set the region of the control to the other control like this:
pen.Region = pen2.Region;
It is very simple to delete a drawn circle from c.
There is only four steps:-
Open turbo app
go to the command where you had drawn the circle
drag the command
click on delete button
This is the high level problem I'm trying to solve...
I have a 3rd party plotting/graphing (IoComp Plot), and I want to embed a high quality (at least 600 dpi) bitmap of the Plot control in reports created by another 3rd party report package (Combit List & Label).
This is the approach that seems most promising so far...
---Edit---:
After trying many other approachs, the only one that I think I can make work is to create a hidden instance of the Plot control, with everything scaled up to printer size (approx 5 times screen size). That includes width and height, font sizes, line widths - every visible component of the control. Yuck!
------
I can get a Graphics object of the proper resolution from the plot control's PrintPage event, but converting it to a Bitmap so the report package will be happy is proving to be the major stumbling block. Several hours of searching has led to other people who asked the same question, but no viable answers.
The only promising lead I've found suggested using one of the Bitmap constructors, which takes a Graphics instance as a parameter.
However, it's not working for me. It creates Bitmap, but with no content from the Plot control - it is a pure black image.
Here's my code (edited to show drawing of red line to Graphics object):
void PrintDocument_PrintPage(object sender, PrintPageEventArgs e)
{
// Draw a red line on the Graphics object. When printed, this
// line is shown as part of the normal Plot graphics.
Pen myPen;
myPen = new Pen(Color.Red);
e.Graphics.DrawLine(myPen, 0, 0, 200, 200);
myPen.Dispose();
// Create a bitmap from the Graphics object
Bitmap bm = new Bitmap(1000, 1000, e.Graphics);
// Save to disk
// DOES NOT WORK - CREATES FILE THAT IS PURE BLACK (VIEWED
// WITH "PAINT" PROGRAM)
bm.Save(#"C:\Bicw_Dev\Bic.Net\FrontEnd\GraphicsToBmp.bmp", ImageFormat.Bmp);
bm.Dispose();
}
Can anyone suggest why this doesn't work? Is this even a valid approach?
Also, please note:
As far as I can determine (and I've spent quite a bit of time looking) there is no way to get a high resolution, print quality Bitmap from the Plot control directly!
I stress this because several others who asked the question got code samples in response that solved the opposite problem - converting a Bitmap to a Graphics.
I need to convert a Graphics object to a Bitmap object.
And if anyone can suggest an alternate approach that allows me to get a print quality image of my plots into my reports, please feel free. (For example, I can get a low quality (72 bpi) Bitmap from the Plot control, and have considered trying to stretch it - but I've never seen that approach work well in other applications).
Thanks,
-Tom Bushell
Edit in response to comment:
As an experiment, I added the following:
Pen myPen;
myPen = new Pen(Color.Red);
e.Graphics.DrawLine(myPen, 0, 0, 200, 200);
myPen.Dispose();
This caused a red line to be drawn over the plot graphics when I printed my plot. But it had no effect on the Bitmap - it's still pure black.
However, it's not working for me. It
creates Bitmap, but with no content
from the Plot control - it is a pure
black image.
Well you never do paint to the graphics, what do you expect?
You are suppose to do the actual drawing for the output in that event.
The constructor you're using does not copy any graphics, only sets the resolution equal to the graphics resolution. See msdn. As Leppie points out, you have to actually draw something to the bitmap. I suggest getting another graphics object for the item you just created.
Graphics g = Graphics.FromImage(bmp);
//Make the background white
g.FillRectangle(Brushes.White, 0, 0, 1000, 1000);
It is not easy to control the DPI in the Print(Preview) system.
But maybe you are going about it the wrong way. What you want is to create a (large) bitmap and then 'trick' the control in to using that bitmap as if it was the screen. See this list of links.
No need for PrintDocument.