UISegmentedControl writing text labels problem - objective-c

Goodday,
I got the following problem with this code:
-(void)textpopup:(UISegmentedControl *)sender {
int nummer = sender.tag;
if (sender.tag) {
if(sender.selectedSegmentIndex == 0 || sender.selectedSegmentIndex == 1){
beoordeling = [[UITextField alloc] init];
beoordeling.frame = CGRectMake(50 , nummer * 117 + 275 , scrollView.frame.size.width - 100 , 35);
beoordeling.autoresizingMask = (UIViewAutoresizingFlexibleWidth);
beoordeling.borderStyle = UITextBorderStyleLine;
beoordeling.tag = nummer;
[scrollView addSubview:beoordeling];
}
if(sender.selectedSegmentIndex == 2 || sender.selectedSegmentIndex == 3){
if (beoordeling.tag == sender.tag) {
[beoordeling removeFromSuperview];
}
}
}
}
i shall explain the scenario. I got some dynamic UISegmentedControls. At the moment there are 12 of them. At the first 2 segments chosen, a textfield needs to popup. This goes well. But after choosing the first 2 segments for a while and when i go to segments 2 and 3, sometimes the textfields won't remove.
I expected that the textfields which are written when i push segment 0 and 1 are removed when segment 2 and 3 are pushed.
Am i missing something?
EDIT:
At first i want to say, that i never know in advance how many UITextFields i got. When segments 0 and 1 are chosen, a UITextField needs to popup to that corresponding UISegmentedControl. And when segments 2 and 3 are chosen, the UITextField needs to stay away. But i got that fixed now in the following way.
-(void)textpopup:(UISegmentedControl *)sender {
int nummer = sender.tag;
if(sender.selectedSegmentIndex == 0 || sender.selectedSegmentIndex == 1){
// Before i add a new UITextField, the old one has to be removed.
UITextField *text = (UITextField *)[beoordeling viewWithTag:sender.tag];
[text removeFromSuperView];
beoordeling = [[UITextField alloc] init];
beoordeling.frame = CGRectMake(50 , nummer * 117 + 275 , scrollView.frame.size.width - 100 , 35);
beoordeling.autoresizingMask = (UIViewAutoresizingFlexibleWidth);
beoordeling.borderStyle = UITextBorderStyleLine;
beoordeling.tag = nummer;
[scrollView addSubview:beoordeling];
}
else if(sender.selectedSegmentIndex == 2 || sender.selectedSegmentIndex == 3) {
UITextField *tf = (UITextField *)[beoordeling viewWithTag:sender.tag];
tf.text = nil;
[tf removeFromSuperview];
}
}

The second if should be an else if, because it should execute only if the first one doesn't (the selected index can't be both 0 and 2).
What you're trying to do depends on how you've defined beoordeling. I suggest having it as an instance variable, possibly even an IBOutlet. Release in your class's dealloc. Then, in the first if clause, write
if (!beoordeling) {
beoordeling = [[UITextField alloc] init];
// Other setup
}
[scrollView addSubview:beoordeling];
I don't quite understand why you're checking for the tag, but to remove in the second if, just call removeFromSubview.
Do all your segmented controls invoke the same behavior? If you have only one beorrdeling that you're setting the tag on, then you don't need to bother checking for the tag. Just add/remove it, using removeFromSubview. If you have as many of text fields as segmented controls, maybe KVC would be what you want. If your segmented controls' tags go from 0–11, you might have beoordeling0, beoordeling1, beoordeling2, and so on. Then, to get the one you want, use something like this:
beoordeling = (UITextField *)[self valueForKey:[NSString stringWithFormat:#"beoordeling%d", sender.tag]];

Not really sure what you are trying to achieve here, but you do need to release your UITextField object beoordeling or you will leak. AddSubview adds one to the retain count, so should be safe to release straight away:
[scrollView addSubview:beoordeling];
[beoordeling release];

Related

View based NSTableView text field loses focus

After selecting a row, pressing TAB will normally move focus to the next editable text field(s), or in my case, column. However, I have noticed that only sometimes after pressing TAB, the row will turn gray and focus is lost. I must then click on the text field to continue. After days of observations, I still cannot detect a repeatable pattern, and internet searches have not given me enough information. I wonder if my delegate might be the culprit. Some questions come to mind.
Can anyone shed light on why or how focus might be lost? (indirectly answered by Willeke's comment to remove some code)
Is there a proper or deliberate way to force focus on the next text field? (now irrelevant)
The unpredictable behavior prompting the first two questions seemed to be interference between two methods. Resolving one has at least led to predictable behavior and this related question. I included more code below with another method. One column contains a pop-up button. Ordinarily, choosing a value does not select the row (ie, highlighted). I would like the row to be selected and focused (ie, highlighted blue) so that I can immediately TAB to the next field and begin editing. In editPopUps:, selectRowIndexes: will select the row, but the row is gray instead of blue and hence TAB has no effect. How do I select and focus the row?
Update: Here are some pertinent methods. I setup each view based on column because only some columns are editable.
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
NSString *column = tableColumn.identifier;
NSTableCellView *value = [tableView makeViewWithIdentifier:column owner:self];
Foo *foo = self.foos[row];
[self setupView:value column:column foo:foo];
[self populateCellView:value column:column foo:foo object:[foo valueForKey:column]];
return value;
}
- (void)setupCellView:(NSTableCellView *)view column:(NSString *)column foo:(Foo *)foo {
view.textField.alignment = NSRightTextAlignment;
BOOL editable = YES;
if ([attribute isEqualToString:column] || ![foo.x isEqualToNumber:bar.x]) {
editable = NO;
} else {
view.textField.target = self;
view.textField.action = #selector(editTextField:);
}
[view.textField setEditable:editable];
}
- (void)editTextField:(NSTextField *)sender {
if ([self.fooTableView numberOfSelectedRows]) {
NSTableCellView *cellView = (NSTableCellView *)[sender superview];
NSString *column = cellView.identifier;
NSInteger row = [self.fooTableView rowForView:cellView];
Foo *foo = self.foos[row];
NSNumber *amountNumber = [NSNumber numberWithShort:[sender intValue]];
if ([attribute isEqualToString:column]) {
foo.y = amountNumber;
} else {
foo.z = amountNumber;
}
[self.fooTableView reloadDataForRowIndexes:[NSIndexSet indexSetWithIndex:row] columnIndexes:[NSIndexSet indexSetWithIndex:[self.fooTableView columnWithIdentifier:column]]];
[self refreshSelection];
}
}
- (void)editPopUps:(NSPopUpButton *)sender {
GlorpView *glorpView = (GlorpView *)[sender superview];
NSString *column = pokeCellView.identifier;
NSInteger row = [self.fooTableView rowForView:glorpView];
Foo *foo = self.foos[row];
NSNumber *indexValue = [NSNumber numberWithShort:[sender indexOfSelectedItem]];
NSMutableIndexSet *columnIndexes = [NSMutableIndexSet indexSetWithIndex:[self.fooTableView columnWithIdentifier:column]];
if ([attribute isEqualToString:column]) {
foo.Z = indexValue;
}
[self.fooTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
[self refreshSelection];
}

Getting userData from SKNode array in for loop

I am having some trouble getting the userData values from my object. I know the userData is being set for the objects because else where in my code I am able to access it without any problems.
I created a SKNode *column3 to hold all the buttons that are in that column. which was added to scene like so:
column3 = [SKNode node];
[self addChild:column3];
column3.name = #"column3";
when I create the buttons I assign them to the appropriate column like so:
[column3 addChild:newButton];
Later in my code I need to loop through the column3 node group and get the #"buttonRow" userData from each object in that group. For some reason it only gives me "NULL" for the values. The NSLog's are just what I was using to test, they have no real importance to me.
I need to get this userData in order to shift all my buttons down to take up any empty spaces on screen when any button is deleted/removed from that column. Game will shift buttons down and add new ones to top to fill column back up.
I tried changing column3.children to self.children and it game me all the column nodes IE/column1, column2, column3 etc.. so I am not really sure why it does not work. Been reading and trying to figure out for a while now.
for(SKNode * child in column3.children) { //loop through all children in Column3.
SKSpriteNode* sprite = (SKSpriteNode*)child;
NSString* name = sprite.name;
NSLog(#"child name %#", name);
NSString *childRowTmp = [child.userData objectForKey:#"buttonRow"];
NSLog(#"child row %#", childRowTmp);
int childRowNumber = [childRowTmp intValue];
NSLog(#"child row # %i", childRowNumber);
}
Any help or tips would be great, thank you.
UPDATE:
here is how I create the button using my button class file I created.
//Create Blue Button.
NSString *rand = [self genRandStringLength:10];
newButton = [[ButtonNode alloc] initWithButtonType:1 column:3 row:i uniqueID:rand];
newButton.name = rand;
[column3 addChild:newButton]; //add the button to correct column
[column3Array addObject:newButton];
blueTotal++;
totalButtons++;
column3Total++;
here is the custom class file where the Object is created.
-(id)initWithButtonType:(int)buttonType column:(int)buttonColumn row:(int)buttonRow uniqueID:(NSString *)uniqueID {
self = [super init];
uniqueStr = uniqueID;
rowNumber = buttonRow;
columnNumber = 3; //this is just hard coded for testing
buttonNumber = 1;
[self addButtonBlue];
}
here is the part of the class that creates and adds the button
- (void) addButtonBlue {
SKSpriteNode *button;
//button type 1
button = [SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:kBoxSize];
button.name = uniqueStr;
button.physicsBody.categoryBitMask = blueCategory;
button.physicsBody.contactTestBitMask = blueCategory;
button.physicsBody.collisionBitMask = blueCategory | redCategory | yellowCategory | greenCategory | orangeCategory;
NSString *tmpColumn = [NSString stringWithFormat:#"%i",columnNumber];
NSString *tmpType = [NSString stringWithFormat:#"%i",buttonNumber];
NSString *tmpRow = [NSString stringWithFormat:#"%i",rowNumber];
button.userData = [NSMutableDictionary dictionary];
[button.userData setValue:uniqueStr forKey:#"buttonID"];
[button.userData setValue:tmpType forKeyPath:#"buttonType"];
[button.userData setValue:tmpColumn forKeyPath:#"buttonColumn"];
[button.userData setValue:tmpRow forKey:#"buttonRow"];
button.position = CGPointMake(xPos , yPos );
[self addChild:button];
}
I am having the same issue, see below the code which generates a green or red sprite. Attempting to give it the colour value within the SKSpriteNode.userData. In my log output the userData is (null)!
+(SKSpriteNode *)randomSprite {
SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:#"green.png"];
[sprite setUserData:[NSMutableDictionary dictionary]];
if ((arc4random() %(2)-1) == 0){
sprite = [SKSpriteNode spriteNodeWithImageNamed:#"green.png"];
[sprite.userData setValue:#"GREEN" forKey:#"COLOR"];
}else {
sprite = [SKSpriteNode spriteNodeWithImageNamed:#"red.png"];
[sprite.userData setValue:#"RED" forKey:#"COLOR"];
}
NSLog(#"user data = %#",sprite.userData);
sprite.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:sprite.size.width/2];
sprite.physicsBody.dynamic = YES;
return sprite;
}
For a workaround I guess we could create a reference dictionary where the SKSpriteNode instances are the keys and a NSDictionary of data are the values.
//----- * UPDATE ** -------
And theres no wonder, after the userData was initialised, another sprite was being initialised in its place, leaving the userData nil!
+(SKSpriteNode *)randomSprite {
SKSpriteNode *sprite;
if ((arc4random() %(2)-1) == 0){
sprite = [SKSpriteNode spriteNodeWithImageNamed:#"green.png"];
[sprite setUserData:[NSMutableDictionary dictionary]];
[sprite.userData setValue:#"GREEN" forKey:#"COLOR"];
}else {
sprite = [SKSpriteNode spriteNodeWithImageNamed:#"red.png"];
[sprite setUserData:[NSMutableDictionary dictionary]];
[sprite.userData setValue:#"RED" forKey:#"COLOR"];
}
NSLog(#"user data = %#",sprite.userData);
sprite.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:sprite.size.width/2];
sprite.physicsBody.dynamic = YES;
return sprite;
}

Getting button names to string format

I have a lot of custom buttons in my program and I need to use methods to get their names. I've figured out how to get their names through their tag, but I cant seem to follow it through to have the name in a string format.
Heres what I'm using:
-(void)pickRandomToHide {
for (int check = 1; check <=5; check++)
{
int eventNumber = 1 + arc4random() % 43;
UIButton *pick;
pick = (UIButton *)[_mapImageView viewWithTag:eventNumber];
[pick setHidden:YES];
NSString *buttonName;
buttonName = [pick currentTitle];
NSLog(#"%#",buttonName);
}
}
The NSLog just gives 'Null' five times. But 5 buttons are disappearing so the start is working.
The reason you're not seeing any titles is because the buttons are hidden and disabled, whereas the titles are likely only set to appear when the button's control state is "normal" (enabled and visible). Here's more information from Apple on the UIButton control states.
Try doing this:
-(void)pickRandomToHide {
for (int check = 1; check <=5; check++)
{
int eventNumber = 1 + arc4random() % 43;
UIButton *pick = (UIButton *)[_mapImageView viewWithTag:eventNumber];
if(pick)
{
[pick setHidden:YES];
NSString *buttonName = [pick titleForState: UIControlStateNormal];
NSLog(#"%#",buttonName);
} else {
NSLog( #"hmmm, no button with a tag corresponding to event number %d", eventNumber);
}
}
}

Dynamically created textfield validation

I'm trying to validate dynamically created text fields. The total number of textfields may vary.
The idea is to populate the empty fields with string like player 1, player 2 etc.. Here is what I try
-(IBAction)validateTextFields:sender
{
self.howManyPlayers = 3;
int emptyFieldCounter = 1;
NSMutableArray *playersNames = [NSMutableArray arrayWithCapacity:self.howManyPlayers];
while (self.howManyPlayers > 1)
{
self.howManyPlayers--;
UITextField *tmp = (UITextField *) [self.view viewWithTag:self.howManyPlayers];
if (tmp.text == nil)
{
[tmp setText:[NSString stringWithFormat:#"Player %d", emptyFieldCounter]];
emptyFieldCounter++;
}
[playersNames addObject:tmp.text];
}
}
The problems is that if I touch the button which invoke validateTextFields method. The first and the second textfield are populated with text Player 1 and Player 2, but the third field is not populated.
I notice also that if I type a text let's say in the second field touch the button then remove the text and again touch the button that field is not populated with text Player X.
How to make all that things to work correctly ?
change your code for two lines like this:
while (self.howManyPlayers >= 1) //edited line
{
UITextField *tmp = (UITextField *) [self.view viewWithTag:self.howManyPlayers];
if (tmp.text == nil)
{
[tmp setText:[NSString stringWithFormat:#"Player %d", emptyFieldCounter]];
emptyFieldCounter++;
}
[playersNames addObject:tmp.text];
self.howManyPlayers--; // moved line
}
I forgot ur second question, so edited my answer.
For that try with this. Change if (tmp.text == nil) with if (tmp.text == nil || [tmp.txt isEqualToString:#""])
The reason only two fields are populated is that you are only going through the while loop twice. It should be
while (self.howManyPlayers >= 1)
You should also move the decrement to the end of your while loop
while (self.howManyPlayers >= 1)
{
// other code here
self.howManyPlayers--;
}
For the second part of your question, I think when you delete the text from the control, it stops being nil and now becomes an empty string. So you need to check for an empty string as well as nil in your code.
if (tmp.text == nil || [tmp.txt isEqualToString:#""])

Objective C - Random XIB pick

I have already posted another question about this, but no one seemed to know how to do this.
I want my app to pick a random XIB file for me, but dont use the ones that have already been randomly picked.
So heres what i have set up as of right now, it seems to work, but i have to keep pressing the button over and over until it finds one that hasnt be used.
-(IBAction)continueAction:(id)sender{
random = arc4random() % 2;
if (random == 0 && usedQ2 == 0) {
Question_2 *Q2 = [[Question_2 alloc] initWithNibName:#"Question 2" bundle:nil];
Q2.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:Q2 animated:YES];
[Q2 release];
}
else if (random == 1 && usedQ3 == 0) {
Question_3 *Q3 = [[Question_3 alloc] initWithNibName:#"Question 3" bundle:nil];
Q3.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:Q3 animated:YES];
[Q3 release];
}
}
So as you can see i have it pick from a random number, and from their find the one that it matches.
Then you can see i have another part of my if statement that is checking to make sure it hasn't been used before.
each NIB file has its own usedQ(whatever Q it is), and when that Nib file is loaded it puts that usedQ as 1.
I think i could get by doing this, but in order to get rid of the constant button pushing, i will have to put loads of else statements with more else statements in them.
I have also tried running the
random = arc4random() % 2;
in a while statement and a for statement, i hoped that it would keep looking for a number until one that hasn't be used was found with no luck.
Any help? thanks!
Why don't you make a mutable array
and populate it with the names of all
your nibs.
Then read the count of the array and
generate a random number in that
range.
Extract the nib name at that index
and remove it from the array.
repeat steps 2-3.
//Setup your list at an appropriate place
NSMutableArray *nibs
= [[NSMutableArray alloc] initWithObjects: #"One Nib", #"Another
Nib", #"Last Nib", nil];
self.unusedNibs = nibs; //This should be a property you declare in
your header.
[nibs release];
-(IBAction)continueAction:(id)sender{
int random = arc4random() % [self.unusedNibs count];
NSString
*nibName = [self.unusedNibs objectAtIndex: random];
[self.unusedNibs removeObjectAtIndex:
random];
//Load nib here.
}