I have a code which spawns a button(gameobject) with presets everytime I press save.
This button is then saved into a List of gameobjects which I then use to select or deselect them.
I tried to make it so that only 1 button in the list can be selected at a time.
It's working to some degree as If i press the button before the current selected one it works. But if i press any button after the currently selected one it is unable to deselect it.
Can anyone help me with this?
public List<GameObject> presetButtons = new List<GameObject>() ;
This is the list of Buttons
void Update () {
for (int i = 0; i < presetButtons.Count; i++) {
if(presetButtons[i].GetComponent<CamUIButtonHandler>().isSelected){
indicator = i;
topView.isSelected = false;
}
}
for (int u = 0; u < presetButtons.Count; u++) {
if(u != indicator)
presetButtons[u].GetComponent<CamUIButtonHandler>().isSelected = false;
}
}
This is supposed to deactivate the other buttons once 1 is selected.
I'm guessing that there is something that causes it to not be able to overwrite the currently selected button however I can't seem to find the issue.
Can anyone help me with this? much thanks
This sounds to me like a good place to use UGUI's Toggle And ToggleGroup features. Put a toggle component on each button. Then set each of those buttons' group properties to be the same ToggleGroup. Of course if you aren't using UGUI then this won't be possible.
Related
I am trying to change the color of all the buttons of a "pagination" when I click on one of them.
So I tagged these buttons PageButton
Usually, I use FindGameObjectsWithTag to get a collection of elements with a certain tag. But even by casting it as Button It doesn't work/show an error and I don't find anything else than FindGameObjectsWithTag in the suggestion nor in the doc
private Button[] buttons;
void Start()
{
//this show me an error telling me I can't convert form UI to gameobject
buttons = GameObject.FindGameObjectsWithTag("PageButton") as Button;
foreach(Button button in buttons)
{
//my code to change every buttons color will go here
}
}
You can't simply cast GameObject to Button. You need to use GetComponent!
You could either do it straight forward and use
var objs = GameObject.FindGameObjectsWithTag("PageButton");
buttons = new Button[objs.Length];
for(var i = 0; i < objs.Length; i++)
{
buttons[i] = objs[i].GetComponent<Button>();
}
or use Linq Select and do
using System.Linq;
...
buttons = GameObject.FindGameObjectsWithTag("PageButton").Select(obj => obj.GetComponent<Button>()).ToArray();
Alternatively you could also go the other way round and find all Buttons in the scene using FindObjectsOfType and then filter by the tag like e.g.
var allButtons = FindObjectsOfType<Button>();
var taggedButtons = new List<Button>();
foreach(var button in allButtons)
{
if(button.CompareTag("PageButton"))
{
taggedButtons.Add(button);
}
}
buttons = taggedbuttons.ToArray();
again you could use Linq Where to shorten this
buttons = FindObjectsOfType<Button>().Where(button => button.CompareTag("PageButton")).ToArray();
This question already has answers here:
Problem with foreach loop giving values to a button in Unity
(2 answers)
Closed 3 years ago.
I'm very new to unity and i was trying to add a button for each level/scene with an event that laods the scene of it.
The code below does add the button and gives it the right text but the onClick event keeps getting stuck on index 2 with the following error message when pressed: 'scene with build index: 2 couldn't be loaded because it has not been added to the build settings.'.
At this moment i have 2 scenes, a menu and one level. I started the loop from index 1 so the menu doesn't get added. But even when i include the menu and click on that button it states the same error message with index 2.
Why does every button try to load the scene with buildindex 2?
All help is appriciated.
//button grid
public Transform grid;
//prefab button
public GameObject button;
//Loop over all scenes starting from the index of the first level
//for each scene make a button, change it's text to the index number
//add onclick event to the new button to start the selected level
private void Start()
{
for (int i = 1; i < SceneManager.sceneCountInBuildSettings; i++)
{
GameObject go = Instantiate(button, grid);
Button btn = go.GetComponent<Button>();
btn.GetComponentInChildren<TextMeshProUGUI>().text = i.ToString();
btn.onClick.AddListener(() => {
SceneManager.LoadScene(i);
});
}
}
You are facing the closure problem. This problem is explained here
for (int i = 1; i < SceneManager.sceneCountInBuildSettings; i++)
{
int index = i;
GameObject go = Instantiate(button, grid);
Button btn = go.GetComponent<Button>();
btn.GetComponentInChildren<TextMeshProUGUI>().text = i.ToString();
btn.onClick.AddListener(() => {
SceneManager.LoadScene(index);
});
}
I have a WPF window with a maintabWindow and several tabitems.
It normally works fine and the layout is this:
but when I BEFORE add the following window:
the result is this:
So the problem is related with the tabControl/tabItem refresh.
This is fairly obvious but even more because if I move the window or pass with the mouse on the a tabItem they get refreshed one by one.
I searched and found that here is a solution: http://geekswithblogs.net/NewThingsILearned/archive/2008/08/25/refresh--update-wpf-controls.aspx
so I added:
this.MainTab.Refresh();
this.tabItem1.Refresh();
this.tabItem2.Refresh();
this.tabItem3.Refresh();
this.tabItem4.Refresh();
this.tabItem5.Refresh();
but that didn't change a thing.
Thanx for any help
Ok so in the end it has a quite a weird behavious. If I do
for (int i = 0; i < tbcMain.Items.Count; i++)
{
tbcMain.SelectedIndex = i;
tbcMain.UpdateLayout();
}
it works. But I have to set the 1st tabitem so if I add
tbcMain.SelectedIndex = 0;
it doesn't.
So the solution was put a sleep and it works again.
for (int i = 0; i < tbcMain.Items.Count; i++)
{
tbcMain.SelectedIndex = i;
tbcMain.UpdateLayout();
}
System.Threading.Thread.Sleep(250);
tbcMain.SelectedIndex = 0;
But that is not elegant at all. If anyone has a better solution pls let me know it.
Btw adding the tbcMain.SelectedIndex = 0; on the loaded event of the mainWindow is of no use.
You should be able to set your SelectedIndex first, and without having to include it in your loop:
tbcMain.SelectedIndex = 0;
Then, basing it off of your response, you should be able to either just do .UpdateLayout() on each of your TabItems:
MainTab.UpdateLayout();
tabItem1.UpdateLayout();
tabItem2.UpdateLayout();
tabItem3.UpdateLayout();
tabItem4.UpdateLayout();
tabItem5.UpdateLayout();
Or you should be able to do something like this in your loop:
MainTab.UpdateLayout();
for (int i = 0; i < tbcMain.Items.Count; i++)
{
TabItem tbi = (TabItem)this.FindControl("tabItem"+i);
tbi.UpdateLayout();
}
Updating/refreshing should have nothing to do with setting the selected one. Including the selection of the tab within the loop to i was your problem - not a race condition. Set the tbcMain.SelectedIndex = 0 outside of your loop and you should be fine. Sometimes, however, this doesn't work and you need to set it with Dispatcher:
Dispatcher.BeginInvoke((Action)(() => this.tbcMain.SelectedIndex = 0));
There's a write up/comments on a separate thread regarding why it needs to be sent to Dispatcher:
How to programmatically select a TabItem in WPF TabControl
Though, unfortunately for me, I had a similar issue where I was trying to refresh a ListView on a subtab. Neither .UpdateLayout(), nor .InvalidateVisual() (as I saw on this thread) worked. I just had to rebind my grid in the button event I was using on my main page, so that when the tab was clicked, it was refreshed manually. I added an x:Name property on the tab so I could call it using "dot" syntax, and it exposed the ListView. I simply added the DataTable of results back to that ListView's DataContext.
What I want to do is creating a menu with several buttons and when the user clicks on one of them, the selected button tag gets stored in a variable and the background color of that button gets highlighted. When the user clicks another button, the previous stored variable gets compared with the new variable and if it is different, it changes the background color of the earlier pressed button back to normal. This is what I have so far:
if (!isSelected)
{
b.BackColor = Color.FromArgb(28, 145, 162);
previousPress = (int)b.Tag;
isSelected = true;
if(previousPress != currentPress)
{
b(previousPress).BackColor = Color.FromArgb(12, 34, 567); // Obviously this wont work, but hopefully it clears up on what I want to reach.
isSelected = false;
currentPress = (int)b.Tag;
}
}
The .Tag idea of B is ranging from 1 till 7, as that is how many buttons are created in the constructor method.
That is what I tried to use, but someone suggested I shouldn't be using tags for this, as it should only cause bugs and errors. He suggested the following:
Button previousButton = b;
if (previousButton != currentButton)
...
I understand the logic behind this, but sadly before he went away before I could ask where and how the currentButton variable is declared/used. Could someone shine some light upon this? Thank you!
Assuming that all the buttons are assigned the same Click event, this code would do exactly what you want:
Color _activeColor = Color.Red;
private void buttons_Click(object sender, EventArgs e)
{
foreach (Button btn in this.Controls.OfType<Button>()
.Where(b => b.BackColor == _activeColor))
{
btn.BackColor = SystemColors.Control;
}
((Button)sender).BackColor = _activeColor;
}
It clears out the button who previously had _activeColor and sets the color to the current one.
This is pretty common approach to what (I believe) you need. Try to understand this code before trying it, it's relying on Linq.
I have added buttons to a grid layout I created. Here is the code for that.
int nodeIndex = 0;
for (i = 0; i < usedRows; i++)
{
for (j = 0; j < cols; j++)
{
this.tableLayoutPanel1.Controls.Add(nodes[nodeIndex++], j, i);
}
}
Later on in the application I want to be able to change the color of a button at a specified position. Basically change the back round color of the button at position i,j. How would I get access to that specific button? I am using winforms. Is there something like
button = this.tableLayoutPanel1.Controls.GetChildAtPosition(j, i)
You can use something along these lines.
button = this.tableLayoutPanel1.GetControlFromPosition(j, i);
button.BackColor = Color.BLACK;
So first you want to able to find the control and conveniently there is a method called FindControl() that can do just that
MSDN link for reference: http://msdn.microsoft.com/en-us/library/system.web.ui.control.findcontrol(v=vs.110).aspx
Second you want to be able to change the color of the button once you find it.
For buttons you probably want to use the BackColor property.
Again MSDN link for reference:
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.backcolor(v=vs.110).aspx
The trick is going to be finding the control and then working with that control as an object to change the color. Don't forget that you can cast the control to a button type once you find it, which should give you access to the BackColor property.