How can I remove one drawn object from winform? - c#

I have created a winform and a picturebox, you can draw / place icons on the on the picturebox.
g2.DrawIcon(SystemIcons.Warning, new Rectangle(screenPositionX, screenPositionY, _levelWidth, _levelHeight));
like this
But my problem is I want to be able to remove the warning icons with the press of a button, but I dont know how.
I already tried g2.Clear, but this removes all the icons.
I also tried just drawing over them, but this draws over everything and I can't find the correct background color.
My question is, how do I remove a single drawn object?

You need a field that keeps track if the icons are to be drawn or not. Flip the value as a result of button presses, and when it comes time to draw (paint event) use the value to determine what to draw.
public partial class Form1 : Form
{
bool showIcons = true;
public Form1()
{
InitializeComponent();
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
var wt = pictureBox1.ClientSize.Width;
var ht = pictureBox1.ClientSize.Height;
// draw grid
for (int i = 0; i < wt; i+=32)
{
e.Graphics.DrawLine(Pens.Black, i, 0, i, ht);
}
for (int j = 0; j < ht; j+=32)
{
e.Graphics.DrawLine(Pens.Black, 0, j, wt, j);
}
if (showIcons)
{
// draw icons
e.Graphics.DrawIcon(SystemIcons.Warning, 5*32-1, 2*32-1);
}
}
private void drawButton_Click(object sender, EventArgs e)
{
showIcons = true;
pictureBox1.Refresh();
}
private void clearButton_Click(object sender, EventArgs e)
{
showIcons = false;
pictureBox1.Refresh();
}
}

After you have painted something on a paper, you can't really take it back without either painting it over completely with the correct color, or discarding (clearing) everything and repainting only those objects that should remain. The same goes for a PictureBox.
If this icon is the only one that can be visible sometimes, and not visible other times, you could introduce a bool field in your form class. If that bool is true, you draw the icon, otherwise you don't. Then, when the user clicks the button, you can change the value of that field, and refresh the form.
Since you are showing very little code, I don't know any names of classes or methods in your solution, so consider this pseudo code!
// Pseudo code
class MyForm : Form
{
// The field that decides whether to draw the icon
private bool showWarningIcon = true;
// The button click handler
public void OnButtonClick()
{
showWarningIcon = false;
Invalidate();
}
// The paint handler
public override void OnPaint(PaintEventArgs e)
{
// Draw other things, then:
if (showWarningIcon)
{
g2.DrawIcon(SystemIcons.Warning, new Rectangle(screenPositionX, screenPositionY, _levelWidth, _levelHeight));
}
}
}

Related

How do I make custom buttons in Visual Studio?

I'm trying to make a launcher for a game that fixes some of its bugs.
Right now I'm just working on the interface and I want to make custom buttons, not just those generic squares, but I can't figure out how.
Here's some example images.
I just threw those buttons together quickly, but that's what I want.
I want the button to highlight when I mouse over it, without it being inside of the default square buttons.
This can be done with a custom drawn button. This demo from MSDN shows you how to override OnPaint and swap the bitmaps by responding to OnMouseDown and OnMouseUp. To get the image to change on hover instead, just swap the bitmaps during OnEnter and OnLeave.
Here's a cut-down example from the linked page:
public class PictureButton : Control
{
Image staticImage, hoverImage;
bool pressed = false;
// staticImage is the primary default button image
public Image staticImage
{
get {
return this.staticImage;
}
set {
this.staticImage = value;
}
}
// hoverImage is what appears when the mouse enters
public Image hoverImage
{
get {
return this.hoverImage;
}
set {
this.hoverImage = value;
}
}
protected override void OnEnter(EventArgs e)
{
this.pressed = true;
this.Invalidate();
base.OnEnter(e);
}
protected override void OnLeave(EventArgs e)
{
this.pressed = false;
this.Invalidate();
base.OnLeave(e);
}
protected override void OnPaint(PaintEventArgs e)
{
if (this.pressed && this.hoverImage != null)
e.Graphics.DrawImage(this.hoverImage, 0, 0);
else
e.Graphics.DrawImage(this.staticImage, 0, 0);
base.OnPaint(e);
}
}
I used a picture box, and then added in my button picture with a transparent background. Then added a click event, mouse enter, and mouse leave event.

How do I resize a dynamically created text box by dragging with mouse like in paint programs?

I have created a text box, inside a PictureBox, on mouse click at run time. Now I want to resize it using mouse drag. Is there some simple way to do this ?
Here is the code I have so far:
public partial class Form1 : Form
{
public static TextBox PTB; //declaring text box to be created
public static bool textOption; //stores the state of button , i.e whether or not text box button is clicked before or not
public Form1()
{
InitializeComponent();
this.pictureBox1.Click += new System.EventHandler(this.pictureBox1_Click);
}
private void pictureBox1_Click(object sender, EventArgs e)
{
if (textOption == true)//if user selected option to draw text box
{
MouseEventArgs eM = (MouseEventArgs)e; //create an instance of mouse event
PTB = new TextBox();//dynamically creating text box
PTB.Location = new System.Drawing.Point(eM.X, eM.Y);//settign position of textbox where mouse was clicked
PTB.Name = "textBox1";
PTB.Size = new System.Drawing.Size(100, 20);//size of text box
this.pictureBox1.Controls.Add(PTB);//adding the textbox to the picture box
}
}
Update
I'm sorry I have totally misread your question.
The reason is probably that you seem to be under the impression that Paint programs have TextBoxes sitting on their canvas. They don't. They draw text the same way as they draw lines or circles etc..
Also: Resizing the TextBox will not change the Font size, in case that's is what you want.
Finally: A TextBox will never be transparent, it will always sit on the PictureBox and look, well, like a TextBox. Not like anything in a Paint programm..
But: If you actually do want to resize the TextBox here are a few hints:
You need some way to show the user they are on the right spot by changing the cursor to the right icon
You need to store the mouse down point (attention: it will be inside the TextBox!) and keep track of the increments in the MouseMove. As long as the Button is down all rported e.Location will still be in the TextBox coordinates.
Use the increments (not the absolute values) to increase the size of the TextBox.
It is really hard to get the resizing right on the top and left sides. (Because it will involve moving at the same time), so better don't try!
Do include moving, which is easy and will suffice for all you need.
No, this is a good deal harder than increasing font size. 200-300 lines of code, the last time I did it..
But you may find another somewhat simpler answer; look for "Resize Control with Mouse winforms c#" on Google..
I leave the old answer in place, even if it not what you were looking for..
Old answer about changing font size while placing text:
It is not very hard but you need to get it right; it is basically the same as drawing a Rectangle
with a live preview. You need these things: four events, a Point or two, a Size and a font variable..
The events are:
MouseDown
MouseMove
MouseUp
Paint
You need to store a point for the placement (in the MouseDown event) and a size you update in the MouseMove.
From that size you can calculate the maximum Font size you can fit in the Rectangle.
On MouseUp you finalize things.
In the Paint event you draw string at the down Point with the current Font size.
In the MouseMove you call Invalidate on the PictureBox to trigger the Paint event.
in the MouseMouve you should check the Button to be the left one.
For extra good UI you can also check the keyboard for space and use it to move the DownPoint..
The Click event is rather useless, btw..
Here is a minimal code example to get you started:
Point mDown = Point.Empty;
float fSize = 12f;
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
using (Font font = new Font("Consolas", fSize))
e.Graphics.DrawString("Hello World", font, Brushes.Black, mDown);
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
mDown = e.Location;
pictureBox1.Invalidate();
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
fSize = Math.Abs(e.Y - mDown.Y) / 2f + 1;
pictureBox1.Invalidate();
}
I left out the MouseUp. Here you would store the final state (font, location..) of the drawn string somewhere or persist it by drawing into a Bitmap etc..
I also didn't do a full Rectangle calculation but determined the font size by simply scaling the y-movement down a little.. You could improve with a little pythagoras ;-)
The ability to resize a window is innate behavior, provided by the default window procedure built into Windows. All you have to do is give the control a resizable border. Everything else is for free, you'll get the correct cursor and dragging a corner or edge resizes the control.
using System;
using System.Windows.Forms;
class ResizeableTextBox : TextBox {
protected override CreateParams CreateParams {
get {
var cp = base.CreateParams;
cp.Style |= 0x840000; // Turn on WS_BORDER + WS_THICKFRAME
return cp;
}
}
}
This sample will create the TextBox on the MouseDown event and start resizing, the final size of the TextBox will be where the mouse button is released on the MouseUp event. It will let you create multiple textboxes as well.
I realize this might not be exactly what you want but it might be a start.
private int _textBoxCounter;
private TextBox _textBoxCurrentResizing;
public Form1()
{
InitializeComponent();
pictureBox1.MouseDown += PictureBox1OnMouseDown;
pictureBox1.MouseUp += PictureBox1OnMouseUp;
pictureBox1.MouseMove += PictureBox1OnMouseMove;
}
public Point RelativeMousePosition { get { return PointToClient(MousePosition); } }
private void PictureBox1OnMouseMove(object sender, MouseEventArgs mouseEventArgs)
{
ResizeTextBox();
}
private void PictureBox1OnMouseUp(object sender, MouseEventArgs mouseEventArgs)
{
EndResizeTextBox();
}
private void PictureBox1OnMouseDown(object sender, MouseEventArgs mouseEventArgs)
{
var tb = CreateTextBox();
StartResizeTextBox(tb);
}
private TextBox CreateTextBox()
{
var tb = new TextBox
{
Location = RelativeMousePosition,
Size = new Size(100, 20),
Multiline = true,
Name = "textBox" + _textBoxCounter++,
};
pictureBox1.Controls.Add(tb);
return tb;
}
private void StartResizeTextBox(TextBox tb)
{
_textBoxCurrentResizing = tb;
}
private void ResizeTextBox()
{
if (_textBoxCurrentResizing == null) return;
var width = Math.Abs(_textBoxCurrentResizing.Left - RelativeMousePosition.X);
var height = Math.Abs(_textBoxCurrentResizing.Top - RelativeMousePosition.Y);
_textBoxCurrentResizing.Size = new Size(width, height);
}
private void EndResizeTextBox()
{
_textBoxCurrentResizing = null;
}

How to prevent panel content from being erased upon scroll

I have a question regarding how I can prevent some content drawn on a panel control from being erased when a scroll action brings it out of view.
What I am trying to do is create a 2D tile-map editor. Whenever a mouse click event happens on the panel, a tile should get drawn onto the panel. I have this working fine. But if I place the object on the panel and scroll to one side, and scroll back, the object I had placed is gone.
I have done some research and I have seen suggestions on implementing the paint event. The problem is that I do not understand what to implement here. I think most of my struggles is coming from not fully understanding the Graphics object.
Here is some of my code:
private void canvas_MouseClick(object sender, MouseEventArgs e)
{
Graphics g = canvas.CreateGraphics();
float x1 = CommonUtils.GetClosestXTile(e.X);
float y1 = CommonUtils.GetClosestYTile(e.Y);
if (currentTile != null)
{
g.DrawImage(currentTile, x1, y1);
me.AddTile((int)currX, (int)currY, (int)x1, (int)y1, "C:\\DemoAssets\\tileb.png");
}
else
{
// dont do anything
}
g.Dispose();
}
private void canvas_Paint(object sender, PaintEventArgs e)
{
// update here?
}
To hold multiple Tiles, you'd need a List to hold each clicked location along with its associated tile:
List<Tuple<Image, PointF>> Tiles = new List<Tuple<Image, PointF>>();
private void canvas_MouseClick(object sender, MouseEventArgs e)
{
if (currentTile != null)
{
float x1 = CommonUtils.GetClosestXTile(e.X);
float y1 = CommonUtils.GetClosestYTile(e.Y);
Tiles.Add(new Tuple<Image, PointF>(currentTile, new PointF(x1, y1)));
canvas.Refresh();
me.AddTile((int)currX, (int)currY, (int)x1, (int)y1, "C:\\DemoAssets\\tileb.png");
}
}
private void canvas_Paint(object sender, PaintEventArgs e)
{
foreach (Tuple<Image, PointF> tile in Tiles)
{
e.Graphics.DrawImage(tile.Item1, tile.Item2);
}
}

Draw a Clickable Square?

I am new to C# but I have a lot of Java experience so I've been told that C# is fairly easy to comprehend based on that.
So far it is. At the moment though, I want to make a simple TicTacToe as part of an exercise. However what I want to do, is draw clickable squares that I can reference so I can check if the box is already clicked or not.
I am currently using Visual Studio Express 2012. I am making a Windows Form Application for Desktop usage.
I looked around for solutions but I can't seem to find something that does this.
How would I go about doing this?
internal sealed class Box : Control
{
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.DrawRectangle(Pens.Black, new Rectangle(Point.Empty, new Size(Width - 1, Height - 1)));
}
protected override void OnClick(EventArgs e)
{
MessageBox.Show("You Clicked The Box!");
}
}
Create a class that derives from Control. From here you can override a whole bunch of virtual members including the OnPaint method where you can perform all of your drawing logic. It's all very intuitive with the assistance of IntelliSense (DrawRectangle, Draw Line etc).
If you want you can override OnClick like I did here but otherwise you can subscribe to an the controls' Click event just as you would a standard control.
You can also derive from ContainerControl for your 'grid' which will behave similarly to a Panel or GroupBox control.
Here's a quick example I just put together to get you started. The border is a tiny bit bugged at some resolutions, I'll leave that down to my abysmal mathematics skills.
internal sealed class GameGrid : ContainerControl
{
protected override void OnCreateControl()
{
for (int y = 0; y < 3; y++)
{
for (int x = 0; x < 3; x++)
{
GameButton button = new GameButton
{
Width = Width/3,
Height = Height/3,
};
button.Location = new Point(x*button.Width++, y*button.Height++);
Controls.Add(button);
button.Click += button_Click;
}
}
}
static void button_Click(object sender, EventArgs e)
{
GameButton gameButton = (GameButton)sender;
gameButton.CircleCheck = true;
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
e.Graphics.DrawRectangle(Pens.Black, new Rectangle(ClientRectangle.Location, new Size(Width - 1, Height - 1)));
}
}
internal sealed class GameButton : Control
{
private bool _cricleCheck;
public bool CircleCheck
{
get
{
return _cricleCheck;
}
set
{
_cricleCheck = value;
Invalidate();
}
}
private readonly Pen circlePen = new Pen(Brushes.Black, 2.0f);
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
e.Graphics.DrawRectangle(Pens.Black, new Rectangle(ClientRectangle.Location, new Size(Width - 1, Height - 1)));
if (CircleCheck)
{
e.Graphics.DrawEllipse(circlePen, new Rectangle(ClientRectangle.Location.X + 10, ClientRectangle.Location.Y + 10, Width - 30, Height - 30));
}
}
}
The most common clickable square is a button.
If the button is clickable in the current gamestate and what icon should be presented there if it was clicked sounds like a job for your background logic.
Try this:
Create a new Form
Drop a PictureBox control inside the form in order to render the Tic Tac Toe board
Handle the Paint event to do the graphics rendering
Handle the MouseClick event to detect if the user has clicked inside the board and use the event arguments to determine on which of the 9 squares of the board the user has clicked
Hope this helps.
I did a similar exercise 2days ago,
Just check this tutorial, it will be enough I guess:
http://www.codeproject.com/Articles/2400/Tic-Tac-Toe-in-C
And for the Square you can either use buttons or you could use PictureBox like this tutorial (although they used vb.net not c# but it's easy to translate):
http://vbprogramming.8k.com/tutorials/tic-tac-toe.htm
I think the easiest solution is using simple buttons with background color or image.
Have a variable for currently playing user and change
button.Text
on click event.
Set all button texts for "" at the beginning- that way you can check if the button was clicked:
if (button.Text!="")
//it was already clicked

C# WinForms add a name to rectangles?

So, I'm building a little app that has 118 buttons for clicking. It is a seat-chooser for an airplane. Instead of adding 118 buttons, i added an image and included 118 rectangles on it, positioning them correctly.
When the user clicks a rectangle, I can't seem to find a way to identify which seat was clicked... Is there a way to add a name field to the Rectangle class or any other way to solve this?
The Rectangle structure is sealed, so you can't inherit it.
But you can try just making your own class:
public class Seat {
private string _SeatKey;
private Rectangle _SeatRectangle;
public Seat(string seatKey, Rectangle seatRectangle) {
_SeatKey = seatKey;
_SeatRectangle = seatRectangle;
}
public string SeatKey {
get { return _SeatKey; }
}
public Rectangle SeatRectangle {
get { return _SeatRectangle; }
set { _SeatRectangle = value; }
}
}
Example:
private List<Seat> _Seats = new List<Seat>();
public Form1() {
InitializeComponent();
_Seats.Add(new Seat("1a", new Rectangle(10, 10, 10, 10)));
_Seats.Add(new Seat("2b", new Rectangle(20, 20, 10, 10)));
}
private void Form1_Paint(object sender, PaintEventArgs e) {
foreach (Seat seat in _Seats)
e.Graphics.FillRectangle(Brushes.Red, seat.SeatRectangle);
}
private void Form1_MouseDown(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
foreach (Seat seat in _Seats) {
if (seat.SeatRectangle.Contains(e.Location))
MessageBox.Show("Clicked on seat " + seat.SeatKey);
}
}
}
Since airplanes can change and have a different number of seats, you can make your program more generic using just labels or buttons.
200 labels or button are not so much in reality, and it work with performances similar to draw text over an image or a panel in the Paint event.
However for your specific problem, you should get the MouseDown event and use X and Y coordinates to understand where the user clicked.
Bit dirty but you can use Cursor.X and Cursor.Y to get the mouse click location. If its going to run in fullscreen you could check the location of the rectangles.

Categories

Resources