Loop through all buttons in a QButtonGroup - c++

In my project, I have a QButtonGroup with 256 pushbuttons in it. I also gave each button an id like this:
void MainWindow::AddBlocksToGroup()
{
QButtonGroup* blockGroup = new QButtonGroup(this);
blockGroup->addButton(ui->Oblock_0, 0);
...
blockGroup->addButton(ui->Oblock_255, 255);
}
I am trying to loop through all the buttons in the group and change their text but I keep getting errors when my program reaches the part where I loop through the buttons. This is what I currently have to loop through them:
for(int i = 0; i <= 255; i++)
{
blockGroup->button(i)->setText("Test"); //Read access violation?
}
I always get a read access violation in my loop when my program reaches this point. Why is this?
Thanks for your time.

I would do this for the iteration code:
foreach(QAbstractButton *button, blockGroup->buttons()) {
button->setText("Test");
}
If this still gives you crashes, then there's something else going on in your program that is invalidating those button pointers.

I know it has been a long time, you probably have already solved this. If not, maybe you need to check whether blockGroup->buttons() return value is an empty list or not. If it is an empty list, then your program crashes.

You seem to be creating a local variable called blockGroup in your AddBlocksToGroup() function. Perhaps what you are trying to do is initialize your MainWindow member variable that uses the same name?
So instead of: QButtonGroup* blockGroup = new QButtonGroup(this);
you should do: blockGroup = new QButtonGroup(this);

Related

Everytime I draw list item in SFML it crashes?

So I am having a small issue with creating a list and having it write to my window using the SFML library. Basically what happens is that when I execute the fire() function the game freezes & crashes.
Variable code:
sf::Sprite laser;
The list code is:
std::list<sf::Sprite>laserList;
The fire code is (called when I click button):
bool fire(void)
{
laserList.push_back(laser);
return true;
}
This is the drawing code to window:
//This is code for running through and drawing each sprite in list
for(std::list<sf::Sprite>::iterator it = laserList.begin(); it != laserList.end(); laserList;)
{
app.draw(*it);
}
Your for loop is a bit strange here:
for(std::list<sf::Sprite>::iterator it = laserList.begin(); it != laserList.end(); laserList;)
You'll find that this will form an infinite loop as the value of it never changes. This may be what leads to your crash. To fix it you want to increment the iterator after every loop:
for(std::list<sf::Sprite>::iterator it = laserList.begin(); it != laserList.end(); ++laserList)
There was an edit that suggested the following but was rejected for some reason. I have added it here for completeness
You could avoid any confusion over this syntax by using the Range Based for loop introduced in C++11:
for(sf::Sprite spr : laserList){
app.draw(spr);
}

Unable to get data from list control

I am working with list control in MFC. I have written code to insert elements into list control present in a dialog box as follows:
int nIndex = 0;
for (int count = 0; count < arrResults.GetSize(); count++)
{
nIndex = m_cListCtrl.InsertItem(count, _T(arrResults[count].ElementAt(0)));
m_cListCtrl.SetItemText(nIndex, 1, _T(arrResults[count].ElementAt(1)));
}
However, when I try to retrieve data from m_cListCtrl, it always returns blank. Also, the GetItemCount() method also returns 0 items. Any suggestions are appreciated.
Following is the data retrieve code that I have written:
arrResults.SetSize(1);
arrResults[0].Add("Header1");
arrResults[0].Add("Header2");
TestDialog testDlg;
testDlg.FillControlList(arrResults); // This function has above code to add data to control list
EXPECT_EQ("Header1", queryDlg.m_cListCtrl.GetItemText(0, 0));
EXPECT_EQ("Header2", queryDlg.m_cListCtrl.GetItemText(0, 1));
The GetItemText function is returning blank string.
When you call FillControlList(), you are using testDlg object. But when you call GetItemText() you're using queryDlg object. You have inserted the items in one dialog and you're trying to get data from different object. Please check with that.

One time initialisation of a variable in cocos2d-x

I am working on one game in cocos2d-x (iOS). There I have created few scenes and did transitions in between those scenes. During each transition init() of each scene(layer) is called (Also constructor is called each time before init()). My question is, How can I make ONLY ONE time initialisation of my variable inside this init() or constructor, even when init() is called each time? Or any OTHER alternative solution for the same?
CCUserDefault::sharedUserDefault()->setBoolForKey("firstTimeInit", false);
bool firstTimeInit = CCUserDefault::sharedUserDefault()->getBoolForKey("firstTimeInit");
if (!firstTimeInit)
{
for(int i = 0; i < 10; i++)
{
char szName[22] = {0};
sprintf(szName, "Rank%i", i);
CCUserDefault::sharedUserDefault()->setIntegerForKey(szName,0);
CCUserDefault::sharedUserDefault()->flush();
int score = CCUserDefault::sharedUserDefault()->getIntegerForKey(szName);
vScore.push_back(score);
}
CCUserDefault::sharedUserDefault()->setBoolForKey("firstTimeInit",true); }
I wrote this code inside init() method.. and I want that firstTimeInit which I made false, initialise only once.
EDIT #####
In cocos2d-x for every transition init() method is called that is why every time our initialisation takes place. Also I want this one time initialisation even after I quit my game and rerun. I tried it by using CCUserDefault's setBoolForKey() but in vain,as it is also in init().
This will do what you are after
bool val = cocos2d::CCUserDefault::sharedUserDefault()->getBoolForKey("initialized");
if (val != true){
cocos2d::CCUserDefault::sharedUserDefault()->setBoolForKey("initialized", true);
cocos2d::CCLog(" initializing value ");
}
currently whats happening :-
1>game starts you put firstTimeInit=false, which makes the if condition true;
2>then you assign firstTimeInit=true in the end.
3> you quit and game starts again and runs step 1 ,which will override present value in firstTimeInit from true to false,again making the if condition true so you need to remove first statement
CCUserDefault::sharedUserDefault()->setBoolForKey("firstTimeInit", false);
so that once the key is set to true it is never set to false;
Assumption:But I am assuming if a boolean key is not present then getting its value always returns false. Checked several times , and it returned false.

C++ do while loop

I have a vector holding 10 items (all of the same class for simplicity call it 'a'). What I want to do is to check that 'A' isn't either a) hiding the walls or b) hiding another 'A'. I have a collisions function that does this.
The idea is simply to have this looping class go though and move 'A' to the next position, if that potion is causing a collision then it needs to give itself a new random position on the screen. Because the screen is small, there is a good chance that the element will be put onto of another one (or on top of the wall etc). The logic of the code works well in my head - but debugging the code the object just gets stuck in the loop, and stay in the same position. 'A' is supposed to move about the screen, but it stays still!
When I comment out the Do while loop, and move the 'MoveObject()' Function up the code works perfectly the 'A's are moving about the screen. It is just when I try and add the extra functionality to it is when it doesn't work.
void Board::Loop(void){
//Display the postion of that Element.
for (unsigned int i = 0; i <= 10; ++i){
do {
if (checkCollisions(i)==true){
moveObject(i);
}
else{
objects[i]->ResetPostion();
}
}
while (checkCollisions(i) == false);
objects[i]->SetPosition(objects[i]->getXDir(),objects[i]->getYDir());
}
}
The class below is the collision detection. This I will expand later.
bool Board::checkCollisions(int index){
char boundry = map[objects[index]->getXDir()][objects[index]->getYDir()];
//There has been no collisions - therefore don't change anything
if(boundry == SYMBOL_EMPTY){
return false;
}
else{
return true;
}
}
Any help would be much appreciated. I will buy you a virtual beer :-)
Thanks
Edit:
ResetPostion -> this will give the element A a random position on the screen
moveObject -> this will look at the direction of the object and adjust the x and Y cord's appropriately.
I guess you need: do { ...
... } while (checkCollisions(i));
Also, if you have 10 elements, then i = 0; i < 10; i++
And btw. don't write if (something == true), simply if (something) or if (!something)
for (unsigned int i = 0; i <= 10; ++i){
is wrong because that's a loop for eleven items, use
for (unsigned int i = 0; i < 10; ++i){
instead.
You don't define what 'doesn't work' means, so that's all the help I can give for now.
There seems to be a lot of confusion here over basic language structure and logic flow. Writing a few very simple test apps that exercise different language features will probably help you a lot. (So will a step-thru debugger, if you have one)
do/while() is a fairly advanced feature that some people spend whole careers never using, see: do...while vs while
I recommend getting a solid foundation with while and if/else before even using for. Your first look at do should be when you've just finished a while or for loop and realize you could save a mountain of duplicate initialization code if you just changed the order of execution a bit. (Personally I don't even use do for that any more, I just use an iterator with while(true)/break since it lets me pre and post code all within a single loop)
I think this simplifies what you're trying to accomplish:
void Board::Loop(void) {
//Display the postion of that Element.
for (unsigned int i = 0; i < 10; ++i) {
while(IsGoingToCollide(i)) //check is first, do while doesn't make sense
objects[i]->ResetPosition();
moveObject(i); //same as ->SetPosition(XDir, YDir)?
//either explain difference or remove one or the other
}
}
This function name seems ambiguous to me:
bool Board::checkCollisions(int index) {
I'd recommend changing it to:
// returns true if moving to next position (based on inertia) will
// cause overlap with any other object's or structure's current location
bool Board::IsGoingToCollide(int index) {
In contrast checkCollisions() could also mean:
// returns true if there is no overlap between this object's
// current location and any other object's or structure's current location
bool Board::DidntCollide(int index) {
Final note: Double check that ->ResetPosition() puts things inside the boundaries.

Convert i of For Loop to QString

Edited-
Here's where I'm getting thrown down:
for(int i=0, a=bugModel->rowCount(); i<a; i++){
qDebug() << i;
QString *BugName = new QString(QString::number(i));
setting.beginGroup(BugName->toAscii());
bugModel->setData(bugModel->index(i,0), setting.value("theBugName", "A Bug!").toString());
setting.endGroup();
delete BugName;
}
I'm trying to load a Name from the setting group and set it to a list model, for which the name will equal to i. But everytime I load the model, the information of the group '0' only shows up, because i is 0 in here. For example:
I have two setting group named '0' and '1'. I want the for loop to run 2 times so that it loads the value from these groups and set it in the QListView. But I tested it out and everytime it loads only the value of the '0' group, and when I change it to for(int i=1..) it loads the value of the group '1'.
To fix the first case, you can (*BugName) = QString::number(i) or BugName->setNum(i);, but the bigger question is what are you trying to achieve and how do you check if it stays zero? What do you expect to change? Maybe give more context?
Based on the weird use of 'a', I'm guessing that there's a bunch of other code that you didn't post. As it stands now, the loop is equivalent to for (int i = 0; i < 2; ++i), and thus only iterates through i=0 and i=1. On the first pass, it creates a new QString, assigns the address to the bugname pointer, then attempts (incorrectly) to assign a string to it. You can change the second line to *BugName = QString::number(i); and it should work. Even better, you can use one of the QString constructors and change the first line to QString* BugName = new QString(QString::number(i)) and eliminate the second line altogether.
Now for the second problem, your memory leak. After the first pass, the loop resets and you create a second qstring, overwritting bugname with the new address. Unfortunately, this orphans the first qstring you made causing a leak. Add the line delete BugName; just before the end of the loop to fix. If you're actually trying to create an array of 'BugNames' for use after the loop, you probably want to use an array instead: Put QString BugNames[2] before the loop, then use the loop to iterate through and initialize them individually via BugNames[i] = QString::number[i]. Since arrays are automatic variables, you won't need the delete part for this latter case.
Edit
Looking at your revised code, I would do it this way (old way still valid though):
for(int i=0; i < bugModel->rowCount(); i++){
qDebug() << i;
QString BugName = QString::number(i);
setting.beginGroup(BugName.toAscii());
bugModel->setData(bugModel->index(i,0), setting.value("theBugName", "A Bug!").toString());
setting.endGroup();
}
Note that your use of 'a' is redundant, since it (and indeed the loop itself) would likely be removed by the compiler. Now that I see what you're doing, I'd ditch the pointer-strings altogether and just go with a single automatic variable. As for the problem of it not working, qDebug should be outputting "0 1", yes? You can try qDebug() << BugName; after the ::number assignment, but I suspect that will output "0 1" as well. That would mean that your real issue lies somewhere in the begin/endGroup() functions, and not in this loop. If the argument to beginGroup gets assigned to something static, you might be overwritting a value with the second pass.