Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
How can a drawing canvas be realised in managed C++ (C++/CLI). I want to be able to "draw" on a PictureBox object by leftclicking the mouse and simulatneous moving the mouse. The PictureBox is cleared with white color and i want to draw with Black pixels.
First of all, consider this an exception. While it's perfectly fine to ask for help with assignments and homework related stuff here (just make sure to mention it), you should really try to show some code or work you've done already. Don't just go like "I need some code, thanks." because that's not how this site is meant to work.
Please don't just copy and paste this code. Understand it first, then use it or apply what you've learned to your own code.
Back to the actual problem: There are multiple ways to approach this, but the basic concept is always the same (even if you try to create some vector drawing program). The following lines ommit classes and namespaces for readability. If you keep the standard using directives, this shouldn't be an issue for you (most stull will be in System.Drawing). Note that I'll implement everything directly into the form. You could as well create a custom user control for this (which might be the better/cleaner approach).
First you'll need some control to actually display your drawing. Using the standard control PictureBox is perfectly fine for this.
Next you'll need some image to actually draw to. Add a private Bitmap member to your user form.
In this example we'll use the mouse cursor to draw a line. A line is always drawn between the previous position of the cursor and the current position. Due to this we'll have to store the previous position in a Point.
Given the previous two points, you'll need the following two members somewhere in your form (or user control):
private Bitmap bitmap;
private Point oldPosition;
In your form's Load event you'll have to create the Bitmap object. I'm also using Graphics to clear the Bitmap to white and then display it using the PictureBox:
private void Form1_Load(object sender, EventArgs e)
{
bitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height);
using (Graphics g = Graphics.FromImage(bitmap))
g.Clear(Color.White);
pictureBox1.Image = bitmap;
}
Next up, we'll have to reset the previous cursor position, whenever the user clicks somewhere in the PictureBox. For this I add a very simple MouseDown event to it:
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
oldPosition = e.Location;
}
Last but not least, the actual drawing happens in an MouseMove event. For this to work properly, you'll have to do one check and three working steps:
Determine whether the user actually wants to draw (is the left mouse button pressed?).
Draw the line into the bitmap.
Update the previous cursor position to the new position.
Display the results.
The code for this could look like this:
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
using (Graphics g = Graphics.FromImage(bitmap))
g.DrawLine(Pens.Black, oldPosition, e.Location);
oldPosition = e.Location;
pictureBox1.Image = bitmap;
}
}
If everything works as expected, you should be able to draw freehandedly on your PictureBox:
Related
I'm trying to build a simple RPG using the C# Windows Forms (as I had recently stumbled upon a fun tutorial demonstrating this ability. I have two items:
A 'Character' object that has been placed IN game:
In-game character--GUI
I also have a code-generated Draw Object, a tree--built in-game:
public void MainFormPaint(object sender, PaintEventArgs e)
{
//Drawing a tree, to create transparency
Image Tree_2 = Image.FromFile("[Directory to PNG].png");
Tree_2.Tag = "Tree";
e.Graphics.DrawImage(Tree_2,50,50,200,200);
}
...which generates this:
Code-generated Tree Object
Seeing as I cannot detect the object by some means similar to:
Character.Bounds.Intersectswith([insert_my_picture].Bounds);
this leaves me kind of baffled, and I'm not sure what to do. I want to detect this collision, so that I can stop movement. However, I'm not sure how to check for an 'empty spot' next to me or any object for that matter that's code-generated. It's important to note that this image is code-generated to maintain the graphic's transparency (as apparently there are problems placing objects in the form and maintaining transparency with overlaying objects).
Thank you for your help!
As the graphic was drawn at runtime, I was needing to generate a Rectangle:
Rectangle firstTree = new Rectangle();
...in the public variables area, and then created it on paint event.
public void MainFormPaint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(Tree_Obj,50,50,200,200);
firstTree.X = 50;
firstTree.Y = 50;
firstTree.Width = 200;
firstTree.Height=200;
}
The full, encapsulating bounds were only for trial. Problem solved!
C# Beginner here.
I'm making a 2D Tanks game, and everything's working out nicely so far.
Both of my tanks are Picture Boxes, and so is my Missile.
The image of the missile and tanks in the PictureBoxes have transparent BackColour properties. The problem is, the background of the missile & tanks are not transparent while on top of the other picturebox (pbBackground). It looks like this.
I'm aware that using different PB's is an inefficient way of going about it, but I've come pretty far and I don't really know any better. Anyways, as you can see, the Missile and Tank PB backgrounds show the form colour. When I downloaded the images, the backgrounds were transparent, I'm sure of it. How do I go about making the background of my PB's truly transparent? (Matching the background of the Overlapped PB?)
I saw this but it doesn't really match my scenario and I don't understand the solution.
UPDATE: Okay, I followed Tommy's advice, is this the right way to go about moving it along pbBackground in a timer constantly changing MissileX and MissileY? Currently this does nothing.
using (Graphics drawmissile = Graphics.FromImage(pbBackground.Image))
{
drawmissile.DrawImage(pbMissile.Image, new Point(MissileX,Convert.ToInt32(MissileY)));
}
PictureBox is opaque. And PictureBox is not efficient.
For making games, you should study Paint event which directly draws on your form.
Bitmap backgroundBitmap = new Bitmap("background");
Bitmap tankBitmap = new Bitmap("tank");
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(backgroundBitmap, 0, 0);
e.Graphics.DrawImage(tankBitmap, 30, 30);
}
private void timer1_Tick(object sender, EventArgs e)
{
this.Invalidate(); //trigger Form1_Paint to draw next frame
}
Don't layer multiple PictureBox instances on top of each other. It will get very confusing, very quickly.
Instead, use one single PictureBox and use Paint to draw your images to it. In this way, you can have much more control over the graphics operations happening.
Have a look at this
private void DrawIt()
{
System.Drawing.Graphics graphics = this.CreateGraphics();
System.Drawing.Rectangle rectangle = new System.Drawing.Rectangle(
50, 50, 150, 150);
graphics.DrawEllipse(System.Drawing.Pens.Black, rectangle);
graphics.DrawRectangle(System.Drawing.Pens.Red, rectangle);
}
In this example they demonstrate how to draw shapes directly onto a Form. You would use your PictureBox there instead. You can also draw images.
There's lots of ways to draw shapes onto a form using a System.Drawing.Graphics object. Try taking a look at this question for a comparison.
Tommy's answer is right, however, if you're dead set on using pictureboxes (a bad idea), set the overlapping picturebox backgroundcolour to Transparent and the Form's Background to whatever image. TIL the Transparent BackColour just uses the form colour / image. Tommy actually has the right answer here, but this is what I did to fix my problem (the lazy way).
In my setup i have 5 pictureboxes which I am trying to layer.
My code for this is:
pbCoin1.Parent = pbMap;
pbCoin1.BackColor = Color.Transparent;
pbCoin2.Parent = pbMap;
pbCoin2.BackColor = Color.Transparent;
pbCoin3.Parent = pbMap;
pbCoin3.BackColor = Color.Transparent;
pbFlashlight.Parent = pbMap;
pbFlashlight.BackColor = Color.Transparent;`
All 5 pictureboxes contain images. The method I am using works fine, but the problem is that the PbCoin 1,2,3 are glitching trough my pbFLashlight(see image).
Can someone provide a solution such that the coins are only visible when the transparent part of the black layer is over it?
Don't use multiple picture boxes. Use a single PictureBox to represent the game area and handle the .Paint event. Do all of your drawing using GDI calls on the Graphics reference that .Paint sends you in e. You will want to call PictureBox.Invalidate at the end of the Paint event to cause it to queue up the next frame
For better performance, create a new Bitmap instance that you keep a reference to for the life of the game. Clear and do all your drawing to that bitmap every frame, then draw that bitmap to the PictureBox in .Paint.
For even better performance than that, don't use WinForms.
The basic pattern should look like this:
private void Canvas_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(...);
Canvas.Invalidate();
}
I think I'm not clear, but I am practicing doing some pictures on a form. It's very simple code so I think it's not worth it to post it.
I want to draw some semi-transparent rectangles close to the borders of the form, which I have already managed to do. The problem is that when I re-size the form the rectangles just stay at their original positions, and don't "follow" the new position of the borders.
Make sure to do your drawing in the form's Paint event. That way, it will happen each time the control is redrawn: on a resize for example.
Here's a good example: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.paint.aspx
public MyForm()
{
this.Paint += this.PaintRectangles;
}
private void PaintRectangles(object sender, PaintEventArgs e)
{
// use e.Graphics to draw stuff
}
I need to allow to the user to draw lines over an bitmap. Lines should be drawn interactively, I mean something performed using typical code giving to the user a visual feedback about what is drawn:
private void MainPictureBox_MouseDown( object sender, MouseEventArgs e)
{
DrawingInProgress = true ;
Origin = new Point (e.X, e.Y);
}
private void MainPictureBox_MouseUp(object sender, MouseEventArgs e)
{
DrawingInProgress = false ;
}
private void MainPictureBox_MouseMove(object sender, MouseEventArgs e)
{
if (!DrawingInProgress) return ;
End = new Point (e.X, e.Y);
using( Pen OverlayPen = new Pen( Color .Red, 1.0f))
using (Graphics g = MainPictureBox.CreateGraphics())
{
g.DrawLine(OverlayPen, Origin, End);
}
}
Of course I keep track of the points using List.Add within MainPictureBox_MouseUp in order to draw lines in the Paint event (code not shown for the sake of simplicity)
Without the background image things could be done nicely simply overwriting the previous line with the background color, something like:
g.DrawLine(BackgroundColorPen, Origin, PreviousEnd);
g.DrawLine(OverlayPen, Origin, End);
but this is not possible with a not uniform background.
Invalidating the rectangle defined by the points: Origin, PreviousEnd then using Update() makes the rendering quite messy. I am wondering how to perform this task and those are possible ways to do so i am considering:
Draw the lines over a transparent bitmap then draw the bitmap over the Picturebox. I guess that with big images this is simply unfeasible for performances reason.
Using the Picture.BackgroundImage for the bitmap then drawing on the Picture.Image but I unable to figure out how this could really saave the day
Using double buffering? How?
Stacking a different control (a panel?) over the pictureBox, making it transparent (is it possible?) then drawing over it.
Could someone give a hint in the best direction? I am really getting lost.
The solutions working for me has been the following:
Create a transparent panel;
Put it over the bitmap having them overlap completely;
Draw on the panel using proper mouse events;
There is no need to cancel the previous shape, of course: it was a misleading question. It is sufficient to distinguish permanent shapes recorded in proper lists fed to the Paint event from the transient shape previously drawn that will be not drawn again in the next Paint event;
Make absolutely sure that all drawings are performed in the Paint event using the Graphics provided by the PaintEventArgs. Thanks to #HansPassant to have stressed this in a different post.