I made a Tic Tac Toe game and I'm trying to add a few features.
I was used to handle the taken buttons with
button.enabled=false;
The problems is that the text on the buttons turns grey.
So I made a button click for each button:
A1_Click, A2_Click, and so on
This is my code into A1_click, and it's the same for the other buttons, the only thing that changes is "A1", "A2", and so on
Button b = (Button)sender;
if (!A1.Text.Equals(""))
{
MessageBox.Show("Not A Valid Input");
}
I get "not a valid input" when I click a button I've already clicked before, I'd just like to be able to click an another button.
I don't want to lose my turn if I click on an already taken button
Based on what I have read I think I know what you are looking for. You are looking for a way to force the user to lose a turn when they click a button that has already been taken, and you do not want to set the enabled property to false. If that is what you want, then I might have some code that could help. First if you are assigning the same click event to multiple buttons with different functions you should try something like this:
for (int i = 1; i < 10; i++)
{
string currentButtonName = "A" + i;
Control currentButton = this.Controls.Find(currentButtonName, true).FirstOrDefault();
currentButton.Click += OnGameButton_Click;
}
What this is doing is searching your form for a control that has a specified name, and since your buttons have a similar name we can easily search for them. Then we can bind a specific function to all of them so that instead of 9 functions to modify you only have 1, and you can validate that they all work the same. Here is the OnGameButton_Click() event code:
private void OnGameButton_Click(object sender, EventArgs e)
{
if (!hasGameStarted || shouldLoseTurn)
return;
// This is the current button user pressed
Button b = (sender as Button);
if (b.Name.Contains('A') && b.Enabled)
{
if (!b.Text.Equals(""))
{
MessageBox.Show("Not A Valid Input! You have lost your turn.");
shouldLoseTurn = true;
}
else
{
b.Text = currentPlayersLetter;
shouldLoseTurn = false;
}
}
}
As you can see with some flags we can monitor the game, and force the buttons to react accordingly take a look at the beginning of the function. We have to validate that the game is engaged, and that the current user has not lost their turn due to pressing the same button. From there we just need modify what you had so that if they do press the same button twice then we modify the shouldLoseTurn flag as needed.
The other approach is to just simply use the Button.Enabled property to disable the button from use. I know you do not what the button to be grayed out, but if you create your own style guide for the button you could make it how you want. This can be challenging though because you will have to modify the default style template for the button to achieve this. Here is another question that discusses just that here
Related
I have a WinForms application that has a TextBox control (search box) at the top of it. This TextBox is constantly receiving focus during normal application use, and it is very distracting.
I would like the TextBox to only receive the focus if the user explicitly clicks on it.
I can think of a couple rather complicated ways to accomplish this:
Change an image of a text box into a text box when clicked
Keep track of mouse clicks and shift the focus away based on mouse state
Is there something simpler that I can do to accomplish this?
Edit to add better description of problem based on new understanding
Based on the answers that I have received, I now have a bit of a better understanding of what was causing this problem. As the user interacted with my application, various actions would cause controls to either be disabled or to completely disappear. If one of these controls happened to have the focus at the time, then the next control in the tab order would receive the focus.
I don't know what was the "next control" before I added the text box in question. The application has hundreds of controls on screen at any given time, and I'm pretty sure that tab order was never intentionally defined. Whatever it was before, it was innocuous. After adding the search text box, it seemed like that control would always end up with the focus.
Here is a very simple example that demonstrates what was happening:
public class Form1 : Form
{
public Form1()
{
var button = new Button
{
Location = new System.Drawing.Point(159, 67),
Size = new System.Drawing.Size(75, 23),
TabIndex = 0,
Text = #"Click me"
};
button.Click += (sender, args) => button.Enabled = false;
var textBox = new TextBox
{
Location = new System.Drawing.Point(159, 142),
Name = "textBox1",
Size = new System.Drawing.Size(174, 20),
TabIndex = 1
};
SuspendLayout();
ClientSize = new System.Drawing.Size(486, 392);
Controls.Add(textBox);
Controls.Add(_button);
ResumeLayout(false);
PerformLayout();
}
}
After starting the application, clicking on the button will force the text box to get the focus, since it is the next in the tab order. As mentioned by Handbag Crab in the accepted answer, this behavior can be avoided by setting TabStop = false on the text box.
textBox1.TabStop = false;
The above should stop it receiving focus from tabbing.
Subclass the TextBox and over WndProc function to capture the focus message and handle it. Maybe something like this:
if (m.Msg == WM_MOUSEACTIVATE) {
m.Result = (IntPtr)MA_NOACTIVATEANDEAT;
return;
}
base.WndProc(ref m);
I have a form which includes AdobeShockwave player for play some YouTube videos by clicking on the different buttons.
I've set a comboBox (This allow user to choose what events need to show it in the AdobeShockwave) and 3 Radio buttons (for see the rest of the buttons and videos).
I've already put codes in the Visual Studio and compiled and it was true.
But i have a problem.
Just imagine i put some codes which includes : when user choose number one in the combobox (index 1) and then choose the radio button, Set the Text of Buttons.
But now i wanna do something and put some codes which includes, When user choose button 1 , specific video show in the Shockwave and when user click on the button 2, Show the specific video and ... .
I know i have to put this code in the Button event :
if (comboBox1.SelectedIndex == 1)
axShockwaveFlash.Movie = "Video's URL";
But i code above happen if :
1. ComboBox1.SelectedIndex == 1
2. RadioButton1.Checked = true
3.Then when user click in the button 1 Show the video.
I put my image which can help you.
Thanks in advance for your Help.
And these are my codes :
private void radioPage1_CheckedChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex == 1)
{
/* Show/Display the numbers of row in the form*/
lbl1.Show();
btn1.Show();
/* Change the label of the Events*/
lblEvents.Text = "StarCraft II ProLeague 2016 S1 :";
}
Update
There is no one to answer my problem ?
I have a picturebox in my system that displays a thumbnail image from a List<Bitmap> called images. There is a button on either side of the picturebox that allows the user to move to the previous or next image. What I would like to happen is that when the picturebox is on the first image of the List, then the 'previous' button is disabled, and same for the last image and the 'next' button. At any other time, the user should be able to scroll in either direction.
I have written a function called checkFirstLast() to try and implement this, and am testing it with only two elements in the images List. The function is shown below, and is called every time the image on the picturebox is changed:
//Bitmap passed in represents image currently displayed on picbox
public void checkFirstLast(Bitmap displayImage)
{
if (displayImage == images.First())
{
//cant go back
//set prev button as inactive
btnPrevImage.Enabled = false;
btnPrevImage.BackColor = INACTIVECOLOUR;
//can go forward
//set next button as active
btnNextImage.Enabled = true;
btnNextImage.BackColor = ACTIVECOLOUR;
}
else if (displayImage == images.Last())
{
//can go back
//set prev button as active
btnPrevImage.Enabled = true;
btnPrevImage.BackColor = ACTIVECOLOUR;
//cant go forward
//set next button as inactive
btnNextImage.Enabled = false;
btnNextImage.BackColor = INACTIVECOLOUR;
}
else
{
//can go back
//set prev button as active
btnPrevImage.Enabled = true;
btnPrevImage.BackColor = ACTIVECOLOUR;
//can go forward
//set next button as active
btnNextImage.Enabled = true;
btnNextImage.BackColor = ACTIVECOLOUR;
}
}
When the application loads, it loads to the first element in the images, and the checkFirstLast() function is run. This means that at this point, the 'previous' button is disabled while the 'next' button is enabled. However, when the 'next' button is clicked (checkFirstLast() run again) and the picturebox shows the second (last) element in images, neither button changes enabled state as it should.
This means that the system becomes stuck on the last element in the List and can go neither backwards (button not enabled), nor forwards (no more images, although button stays enabled).
I don't really understand what could be going wrong, surely if the function operates as expected first time around then it can't just not work when called again?
Not sure where to go from here, any advice or a point in the direction of where to look would be greatly appreciated.
Thanks in Advance,
Mark
I have a Windows Form that contains only buttons. The final goal is to make a simple logic game I saw but for now the problem is that I want to perform different actions when my New button is clicked, but now it is part from all the buttons in the form so sometimes an action is performed on him too which should not happen. To make myself clear I have two screenshots :
So this is how I want it to be - I have a matrix - 3x3 (in this case, at the end it can be NxN). By clicking New I want to be able to do various things one of which is to make N buttons colored red. What happens now is sometimes my New button also get painted because I go over the buttons like this:
foreach (Control c in this.Controls)
{
if (c is Button)
{
...
and thus sometimes New get selected too, so I end up with this:
What I'm thinking right now is just to perform check whenever I need in the code and exclude my New button explicitly but I don't think it's a good way cause I may end up with a code doing this thing in a lot of places in my program so what is the right solution in this case? If some code is needed please ask.
Quite possibly the easiest solution is to put the Grid in its own Panel (pnlGrid). Put all of the buttons in there, then you could just do the following instead:
foreach (Control ctl in pnlGrid.Controls) {
if (ctl is Button) {
// Do your logic here
}
}
Instead of looping through controls, add all the matrix buttons to a list, and have the new button separated:
private Button[] buttons;
private Button newButton;
Now you can add as many buttons as you'd like to:
for (int i = 0; i < 9; i++)
{
buttons[i] = new Button();
buttons[i].Text = "Button" + i;
Controls.Add(buttons[i])
}
And lastly, your New button will loop through buttons:
private void newButton_Click(object sender, EventArgs e)
{
foreach (Button b in buttons)
{
...
}
}
You could inherit from the button class. Make your own button, use this control (that will have the same functionality that the parent one) for the set, and check for it when you iterate over the controls.
You could also use the Tag property for this pourpose, but I think that inherit will be more clear, adding semantic meaning to your code.
Currently I have some buttons on my Winform that need to be disabled/enabled at various points depending what the user clicks.
The first draft I made was
button1.Enabled = false;
button2.Enabled = false;
To disable 2 buttons, which is obviously a horrible way of doing this, as there are currently a lot more than 2 and possibly more to come as this is still in development. So I need to have a way of easily changing a selection of buttons on the form.
Then I came up with this
private enum Buttons { Button1, Button2 } // etc with all buttons - that are named :)
private void DisableButtons(params Buttons[] buttons)
{
foreach (Buttons button in buttons)
{
switch (button)
{
case Buttons.Button1:
button1.Enabled = false;
break;
case Buttons.Button2:
button2.Enabled = false;
break;
}
}
}
Which I still wasn't overly happy with. I could scrap the switch-case and foreach for
private void DisableButtons(params Buttons[] buttons)
{
button1.Enabled = buttons.Contains(Buttons.Button1) ? false : true;
}
for each button but I just think there must be a better way.
Any ideas on how I could do this more efficiently?
Thanks
You can shorten your last code line to:
button1.Enabled = !buttons.Contains(Buttons.Button1);
Alternative solution
Or you can use the Tag property of each button to set a enum value for each button.
button1.Tag = Buttons.Button1;
button2.Tag = Buttons.Button2;
button3.Tag = Buttons.Button3;
// etc
Than you can do it for all buttons in a for loop:
var buttons = <all buttons, todo>
foreach (var button in buttons) {
button.Enabled = !button.Contains((Buttons)button.Tag));
}
I would suggest that you don't infact want to make a function that flexibly enables and disables any combination of buttons because you don't yet percieve how your Form will work. Granted, this may save you a few lines of code but, it won't impart any contextual information to the next developer that maintians your code. Neither will it run faster than directly setting the state of the controls.
I woud make a single function that is called whenever your Form changes state, that takes all possible parameters that pertain to your Forms state. Then I would decode those parameters and explicitly setup the state of the controls on the form, by name, in a single pass, using tranditional switch and if statments.
This central function will make it clear to you and future developers how the state of you form changes and how controls are expected to behave. It won't slow down the performance of you code with an unecessary level of abstraction.