[pickerView reloadAllComponents]; doesn't update UIPickerView component width - components

I have 2 columnes in UIPicerView, and when I call [pickerView reloadAllComponents] it doesn't call
- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component
for updating components widths, but when a switch in program 2=>3 and 3=>2 mthod calling, i must change current columnt count and than call [pickerView reloadAllComponents]?

Your view controller should inherit the UIPickerView protocol. Than implement
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
method

Related

Styling NSOutlineView Rows

I have a Document based Core Data app with an NSTreeController supplying the content to a view based NSOutlineView. I am "styling" (setting text colour, background colour etc.) the rows based on persistent "transformable" NSColor and NSFont attributes in my data model which the end use can modify. When a new row is popped up, it displays things with the colours/fonts set in the data model. Here is the delegate/datasource code that sets the row background colour:
- (void) outlineView:(NSOutlineView *)outlineView
didAddRowView:(NSTableRowView *)rowView
forRow:(NSInteger)row
{
// Get the relevant nodeType which contains the attributes
QVItem *aNode = [[outlineView itemAtRow:row] representedObject];
if (aNode.backColor)
{
rowView.backgroundColor = aNode.backColor;
}
}
However when the style attributes change I want the associated visible rows to be redrawn with the new style values. Each time a "style" attribute is changed, I am using NSNotificationCenter to send a notification to the Outline view delegate, with the model object whose row needs to be redrawn with the changed style. This is the code in the delegate that receives the notification.
-(void) styleHasChanged: (NSNotification *)aNotification
{
NSTreeNode *aTreeNode = [myTreeController treeNodeForModelObject:aNotification.object];
[myOutlineView reloadItem:aTreeNode];
}
My assumption here is that I can navigate the tree controller to find the tree node which is representing my model object and then ask the outline view to redraw the row for that tree node. This is the "additions" code in the tree controller which walks the tree to find the object - not super efficient, but I don't think there is another way.
#implementation NSTreeController (QVAdditions)
- (NSTreeNode *)treeNodeForModelObject:(id)aModelObject
{
return [self treeNodeForModelObject:aModelObject inNodes:[[self arrangedObjects] childNodes]];
}
- (NSTreeNode *)treeNodeForModelObject:(id)aModelObject inNodes:(NSArray*)nodes
{
for(NSTreeNode* node in nodes)
{
if([node representedObject] == aModelObject)
return node;
if([[node childNodes] count])
{
NSTreeNode * treeNode = [self treeNodeForModelObject:aModelObject inNodes:[node childNodes]];
return treeNode;
}
}
return nil;
}
So sometimes this works and the row redraws, and sometimes it doesn't. The delegate method "styleHasChanged:" is always called, and the tree controller always returns a corresponding tree node (Actually of a subclass of NSTreeNode). But more often than not the outline view does not recognise the tree node, and the row is not redrawn. Its like the tree controller has given back a different tree node object to the one it gave the outline view in the past. But weirdly sometimes it does work and the right row is redrawn with the new background colour. If I collapse the row out of view and pop it open again, it is redrawn correctly.
Anyone any idea why it works sometimes and not other times?
It would be nice to be able to bind the colour/font attributes to the row and columns in some way, so that the outline view did this styling automatically with KVO, but I don't think that is possible - is it?
You spend hours/days trying to work out what you've done wrong; You write the question out; Post it; Sleep on it; and think how stupid can you be.
So I asked the NSTableRowView to redraw itself, but I had not set the new background colour. So here is the new improved (and works) version of styleHasChanged:
-(void) styleHasChanged: (NSNotification *)aNotification
{
QVItem *modelItem = aNotification.object;
NSTreeNode *aTreeNode = [myTreeController treeNodeForModelObject:modelItem];
NSInteger rowIndex = [myOutlineView rowForItem:aTreeNode];
if !(rowIndex == -1)
{
NSTableRowView *rowViewToBeUpdated = [myOutlineView rowViewAtRow:rowIndex makeIfNecessary:YES];
rowViewToBeUpdated.backgroundColor = modelItem.backColor;
}
}
Duh!

the selection changed is not rise when I select item in the constructor

I have a view and a viewModel. In my constructor of my viewModel I have this code:
Dgd01.Add(myElement);
Dgd01SelectedIndex = 0;
I am using MVVMLight to implement the selectionChanged event of my dataGrid, but the event is not rised.
I have a button to clean the selection, then I select the element in the dataGrid and the selection event is rised.
I guess that the problem is that I am doing the selection in the constructor, but I don't know if this is the real reason of the problem and I don't know how to solve it.
May be the view model is not associated with the view when the constructor is executed.
Why can't you try the below method
You can have a private method which does the actual task when selectionChanged event fires.
void DoOperationOnSelection(int selectedIndex / object selectedItem)
{
}
So the eventHandler may call this method with selectedIndex/item
Call that method explicitly from the constructor as follows
Dgd01.Add(myElement);
DoOperationOnSelection(0);

coredata override set value for relationship

I have a working model in coredata with two entity:
- Customer
- Invoices
Customer has "invoices" property (1 to many) and Invoices has "customer" property (1 to 1).
Everything worked until i override the "setCustomer" method on Invoice class.
I write this code
-(void)setCustomer:(Customer *)customer {
[self willChangeValueForKey:#"Customer"];
[self setPrimitiveValue:customer forKey:#"Customer"];
[self didChangeValueForKey:#"Customer"];
[self recalulatePriceAndDiscounts];
}
where "recalculatePriceAndDiscount" is my own method that i need to call when i select different customer.
When i use this code the inverse relationship (customer->invoices) isn't immediately available, i need to close and reopen my application to see customer's invoices.
There is some other method that i need to call?
thanks
If the property is called "customer" (with a lower-case "c") then you have to use that as key, e.g.
[self willChangeValueForKey:#"customer"];
// ... etc.

Show a UIPopoverController from a DetailDisclosureButton that is added by setting the Cell.Accessory

I have a UITableView that I use in the same way demonstrated in this tutorial at Xamarin.
Per the instructions in the sample, I set the cell.Accessory to a DetailDisclosureButton in the GetCell method, like so:
public override UITableViewCell GetCell (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
{
(Some code to create/style the cell, etc. See tutorial link.)
cell.Accessory = UITableViewCellAccessory.DetailDisclosureButton;
}
I would like to have a UIPopoverController to show when the DetailDisclosureButton is tapped. Its anchor needs to be 'attached' to the button.
In order to do this, I'll need to change the AccessoryButtonTapped method accordingly, like so:
public override void AccessoryButtonTapped (UITableView tableView, NSIndexPath indexPath)
{
uipoc = new UIPopoverController(uivc);
uipoc.PopoverContentSize = new SizeF(200f, 300f);
uipoc.PresentFromRect (tableView.CellAt (indexPath).AccessoryView.Frame, tableView, UIPopoverArrowDirection.Right, true);
}
Uipoc is a class variable, as is the (still empty) UIViewController uivc.
As I understand, PresentFromRect's first parameter determines the UIView the UIPopoverController 'hooks up' to, and it needs the Frame property of that view to do so.
Unfortunately, the way I did it above doesn't work. cell.AccessoryView is always null, even though I have set cell.Accessory to be the DetailDisclosureButton.
The answer listed here indicates setting the cell.Accessory does not affect cell.AccessoryView property (I know it deals with ObjectiveC, but I suppose the same applies to MonoTouch).
Instead, it is suggested to add a DetailDisclosureButton manually by assigning a UIButtonto cell.AccessoryView. However, this would mean I cannot use the AccessoryButtonTapped method from the Xamarin sample, would need to create my own eventhandler, and so on.
As an alternative, I have tried cycling through the cell's Subviews, and hooking up the popovercontroller like this:
uipoc.PresentFromRect (tableView.CellAt(indexPath).Subviews[1].Frame, tableView, UIPopoverArrowDirection.Right, true);
However, using Subviews[0] and Subviews[2], it doesn't work at all, while Subviews[1] gives me strange results - the popup menu always shows right next to the first cell's DetailDisclosureButton in the table, no matter which cell's button was tapped.
My question:
Is there a way to get the DetailDisclosureButton's view (ergo, the accessory's view), if just the cell.Accessory is set to UITableViewCellAccessory.DetailDisclosureButton?
If not, is the latter solution (adding UIButton manually) the only way to achieve what I want? How can I do this in C#/MonoTouch?
Thanks!
After some fiddling I found a somewhat ugly but working workaround:
public override void AccessoryButtonTapped (UITableView tableView, NSIndexPath indexPath)
{
uipoc = new UIPopoverController(uivc);
uipoc.PopoverContentSize = new SizeF(200f, 300f);
uipoc.PresentFromRect (new RectangleF(cell.Frame.Right - 40f, cell.Frame.Y, cell.Frame.Width, cell.Frame.Height), tableView, UIPopoverArrowDirection.Right, true);
}
Instead of needing the position info from the accessory's Frame, I just use the info of the cell itself and subtract 40 from its right side. This will show the UIPopupViewcontroller on the left of the DetailDisclosureButton in that cell, with its arrow pointing to it. Obviously, you need to subtract (or add) 40 for the right dimension, depending on which UIPopoverArrowDirection you choose.
I doubt this is the correct way, though I suppose I'll stick to it unless someone comes up with a better suggestion.

iOS 5 + GLKView: How to access pixel RGB data for colour-based vertex picking?

I've been converting my own personal OGLES 2.0 framework to take advantage of the functionality added by the new iOS 5 framework GLKit.
After pleasing results, I now wish to implement the colour-based picking mechanism described here. For this, you must access the back buffer to retrieve a touched pixel RGBA value, which is then used as a unique identifier for a vertex/primitive/display object. Of course, this requires temporary unique coloring of all vertices/primitives/display objects.
I have two questions, and I'd be very grateful for assistance with either:
I have access to a GLKViewController, GLKView, CAEAGLLayer (of the GLKView) and an EAGLContext. I also have access to all OGLES 2.0
buffer related commands. How do I combine these to identify the color
of a pixel in the EAGLContext I'm tapping on-screen?
Given that I'm using Vertex Buffer Objects to do my rendering, is there a neat way to override the colour provided to my vertex shader
which firstly doesn't involve modifying buffered vertex (colour)
attributes, and secondly doesn't involve the addition of an IF
statement into the vertex shader?
I assume the answer to (2) is "no", but for reasons of performance and non-arduous code revamping I thought it wise to check with someone more experienced.
Any suggestions would be gratefully received. Thank you for your time
UPDATE
Well I now know how to read pixel data from the active frame buffer using glReadPixels. So I guess I just have to do the special "unique colours" render to the back buffer, briefly switch to it and read pixels, then switch back. This will inevitably create a visual flicker, but I guess it's the easiest way; certainly quicker (and more sensible) than creating a CGImageContextRef from a screen snapshot and analyzing that way.
Still, any tips as regards the back buffer would be much appreciated.
Well, I've worked out exactly how to do this as concisely as possible. Below I explain how to achieve this and list all the code required :)
In order to allow touch interaction to select a pixel, first add a UITapGestureRecognizer to your GLKViewController subclass (assuming you want tap-to-select-pixel), with the following target method inside that class. You must make your GLKViewController subclass a UIGestureRecognizerDelegate:
#interface GLViewController : GLKViewController <GLKViewDelegate, UIGestureRecognizerDelegate>
After instantiating your gesture recognizer, add it to the view property (which in GLKViewController is actually a GLKView):
// Inside GLKViewController subclass init/awakeFromNib:
[[self view] addGestureRecognizer:[self tapRecognizer]];
[[self tapRecognizer] setDelegate:self];
Set the target action for your gesture recognizer; you can do this when creating it using a particular init... however I created mine using Storyboard (aka "the new Interface Builder in Xcode 4.2") and wired it up that way.
Anyway, here's my target action for the tap gesture recognizer:
-(IBAction)onTapGesture:(UIGestureRecognizer*)recognizer {
const CGPoint loc = [recognizer locationInView:[self view]];
[self pickAtX:loc.x Y:loc.y];
}
The pick method called in there is one I've defined inside my GLKViewController subclass:
-(void)pickAtX:(GLuint)x Y:(GLuint)y {
GLKView *glkView = (GLKView*)[self view];
UIImage *snapshot = [glkView snapshot];
[snapshot pickPixelAtX:x Y:y];
}
This takes advantage of a handy new method snapshot that Apple kindly included in GLKView to produce a UIImage from the underlying EAGLContext.
What's important to note is a comment in the snapshot API documentation, which states:
This method should be called whenever your application explicitly
needs the contents of the view; never attempt to directly read the
contents of the underlying framebuffer using OpenGL ES functions.
This gave me a clue as to why my earlier attempts to invoke glReadPixels in attempts to access pixel data generated an EXC_BAD_ACCESS, and the indicator that sent me down the right path instead.
You'll notice in my pickAtX:Y: method defined a moment ago I call a pickPixelAtX:Y: on the UIImage. This is a method I added to UIImage in a custom category:
#interface UIImage (NDBExtensions)
-(void)pickPixelAtX:(NSUInteger)x Y:(NSUInteger)y;
#end
Here is the implementation; it's the final code listing required. The code came from this question and has been amended according to the answer received there:
#implementation UIImage (NDBExtensions)
- (void)pickPixelAtX:(NSUInteger)x Y:(NSUInteger)y {
CGImageRef cgImage = [self CGImage];
size_t width = CGImageGetWidth(cgImage);
size_t height = CGImageGetHeight(cgImage);
if ((x < width) && (y < height))
{
CGDataProviderRef provider = CGImageGetDataProvider(cgImage);
CFDataRef bitmapData = CGDataProviderCopyData(provider);
const UInt8* data = CFDataGetBytePtr(bitmapData);
size_t offset = ((width * y) + x) * 4;
UInt8 b = data[offset+0];
UInt8 g = data[offset+1];
UInt8 r = data[offset+2];
UInt8 a = data[offset+3];
CFRelease(bitmapData);
NSLog(#"R:%i G:%i B:%i A:%i",r,g,b,a);
}
}
#end
I originally tried some related code found in an Apple API doc entitled: "Getting the pixel data from a CGImage context" which required 2 method definitions instead of this 1, but much more code is required and there is data of type void * for which I was unable to implement the correct interpretation.
That's it! Add this code to your project, then upon tapping a pixel it will output it in the form:
R:24 G:46 B:244 A:255
Of course, you should write some means of extracting those RGBA int values (which will be in the range 0 - 255) and using them however you want. One approach is to return a UIColor from the above method, instantiated like so:
UIColor *color = [UIColor colorWithRed:red/255.0f green:green/255.0f blue:blue/255.0f alpha:alpha/255.0f];

Resources