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
Related
Let's take an example from android. Assume you send a message to someone and after message was send you can see (for a few seconds) kind of notification on the screen like Your message was send.
That is exactly what I would like to find in Winform. In my Winform app user click on the button and I would like to make kind of UI response, show him a message for a few sec, like Button clicked.
How to do it?
P.S. Actually I tried to find out how to do it, but everything that I found is kind of notification on the screen at the right bottom corner. It is not actually what I am looking for. I need something like you can see on screenshot. This text should appear in the form, not on the corner of the screen.
P.S 2 Tooltip also not what I am looking for. Tooltip is something that binded close to the button(view). I need kind of general UI response. User click on buttons and instead to show him a dialog that force user to move his mouse and close the dialog, I need kind of softy message that disappear after a few sec.
I need kind of softy message that disappear after a few sec.
I think the tooltips are what you are looking for. The idea is you can programmatically control where to show a tooltip and when to hide it.
Please start a new WinForms project. Add three buttons, ToolTip and Timer to the form. Write the next event handlers (and bind them to the corresponding components):
private void button_Click(object sender, EventArgs e)
{
toolTip1.Show(((Button)sender).Text + " is pressed", this, 300, 300);
timer1.Enabled = true;
}
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Enabled = false;
toolTip1.Hide(this);
}
After demo starting you'll see a tooltip with certain text appearing at the same position for the 1 second.
#Miamy's solution not a bad one, however you have to center text in notification box, and you don't need to use timer. Here the custom tooltip class which centers the tooltip text location and you can see the output below:
Moreover I added some coloring features along with default timer implementation.
class CustomToolTip : ToolTip
{
public int SIZE_X = 500;
public int SIZE_Y = 50;
public CustomToolTip()
{
this.OwnerDraw = true;
this.Popup += new PopupEventHandler(this.OnPopup);
this.Draw += new DrawToolTipEventHandler(this.OnDraw);
}
string m_EndSpecialText;
Color m_EndSpecialTextColor = Color.Black;
public Color EndSpecialTextColor
{
get { return m_EndSpecialTextColor; }
set { m_EndSpecialTextColor = value; }
}
public string EndSpecialText
{
get { return m_EndSpecialText; }
set { m_EndSpecialText = value; }
}
private void OnPopup(object sender, PopupEventArgs e) // use this event to set the size of the tool tip
{
e.ToolTipSize = new Size(SIZE_X, SIZE_Y);
}
private void OnDraw(object sender, DrawToolTipEventArgs e) // use this event to customise the tool tip
{
Graphics g = e.Graphics;
LinearGradientBrush b = new LinearGradientBrush(e.Bounds,
Color.AntiqueWhite, Color.LightCyan, 45f);
g.FillRectangle(b, e.Bounds);
g.DrawRectangle(new Pen(Brushes.Black, 1), new Rectangle(e.Bounds.X, e.Bounds.Y,
e.Bounds.Width - 1, e.Bounds.Height - 1));
System.Drawing.Size toolTipTextSize = TextRenderer.MeasureText(e.ToolTipText, e.Font);
g.DrawString(e.ToolTipText, new Font(e.Font, FontStyle.Bold), Brushes.Black,
new PointF((SIZE_X - toolTipTextSize.Width)/2, (SIZE_Y - toolTipTextSize.Height) / 2));
b.Dispose();
}
}
You can call this tooltip as below code:
CustomToolTip notifyError = new CustomToolTip();
notifyError.Show("Please enter a number.", this, 100, 100, 2000);
Above code creates notification box at 100, 100 location for 2 seconds.
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));
}
}
}
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;
}
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.
I'm trying to create a button in my .NET 4.0 Winforms app in Visual Studio 2010 that is ONLY an image. I have a window that is borderless and has a background image that makes up my custom skin for this application. For the close/minimize buttons in the top right of the window, I wanted to create 2 simple buttons that are images only that look like the typical Windows close/minimize buttons.
I may be going about this design wrong, so if I am please let me know. So far I've determined that I need to create a subclass for Button that only renders the image. The final implementation needs to render different images for each button state (normal, hover, clicked, etc). Here is what I have so far:
public class ImageButton : Button
{
Pen pen = new Pen( Color.Red, 1.0f );
public ImageButton()
{
SetClientSizeCore( BackgroundImage.Width, BackgroundImage.Height );
}
protected override void OnPaint( PaintEventArgs e )
{
e.Graphics.DrawImage( BackgroundImage, 0, 0 );
//e.Graphics.DrawRectangle( pen, ClientRectangle );
//Rectangle bounds = new Rectangle( 0, 0, Width, Height );
//ButtonRenderer.DrawButton( e.Graphics, bounds, PushButtonState.Normal );
//base.OnPaint(pevent);
}
protected override void OnPaintBackground( PaintEventArgs e )
{
// Do nothing
}
}
At this point, assuming this design is appropriate, I need to know how to call SetClientSizeCore() appropriately. Calling it in the constructor raises an exception. I assume this is because the control hasn't had a chance to initialize yet. I'm not sure what function to override that will allow me to change the size of my button to fit the image after it has been initialized by .NET. Any ideas on this?
In the constructor, BackgroundImage is null.
You need to set the size when BackgroundImage is changed by overriding the property.
You should also shadow the Size property and add [DesignerSerializationVisibilty(DesignerSerializationVisibility.Hidden)] to prevent the size from being saved by the designer.
Wait until the BackgroundImage property is assigned so you'll know what size you need. Override the property like this:
public override Image BackgroundImage {
get { return base.BackgroundImage; }
set {
base.BackgroundImage = value;
if (value != null) this.Size = value.Size;
}
}
If you want to use ImageButtons, I'd recommend using BunifuUI as it has ImageButtons.
If you don't want to use BunifuUI, you can use a PictureBox as it also has a click event. Example:
private void pictureBox1_Click(object Sender, EventArgs e) {
webBrowser1.Navigate("https://www.google.com");
}