Can't create an NSImage? - objective-c

Whenever I do:
xxx = [NSImage imageNamed:#"Package.png"];
xxx loads but it's width and height remain 0. And whenever I try loading it into an NSImageCell I get this error:
NSImageCell's object value must be an NSImage.
Can someone help me out? I've never had this problem before.
Edit: Sorry, I've missed this bit out. So when I do it in the data source delegate it does not work and it shows the above error after 'return cell;'.
NSImageCell* cell = [[NSImageCell alloc] init];
[cell setObjectValue:xxx]; // Using imageNamed doesn't help either
Edit 2: This is becoming aggravating. I don't understand what happened but the image loads height and width properly, but it still complains when I add it to an NSImageCell.

I see—so the table view aspect is relevant after all.
As the data source, your job is to return (and receive, in the case of user editing) the object values for the cells in the columns.
But you're not returning such a value; you're returning a cell. Thus, you're trying to set an image cell (created by the data source) as the value of an image cell (the existing one owned by the column).
The log message suggests that you have already set the column's cell as an image cell when you created the column, so all you need to do now is change your data source to always return the object value for the column, not a cell. For an image column, return the image. For a text column, return the string.
Note that NSTableView does not work like UITableView, where UITableViewCells are UIViews and you have as many cells as rows on the screen; in NSTableView, each NSTableColumn gets one and only one data cell, and that one cell is used to draw that column of every row. The cell draws its object value, which you provide to the cell, which you do by returning it (the object value) from your data source method.
The documentation about controls (an NSTableView is a kind of NSControl) and their cells is the Control and Cell Programming Guide.

My guess is it's returning nil, in which case getting the width/height will return 0.
Try:
xxx = [NSImage imageNamed:#"Package"]; // the extension is not needed on the desktop or iOS 4
and make sure the image is actually being copied into your application's Resources folder!

Having established that you are, in fact, receiving an NSImage instance (not nil) whose width and height are zero, the next step is to determine why that happens.
Can you open Package.png in Preview?
If so: What's its width and height in Preview's Info window? Does it have any resolution (DPI or pixels-per-meter) information? If so, what does that say?
If you crack open your application bundle, can you open that copy of Package.png in Preview?
When you log the description of the image, what's the output?
What's the output of logging the image's representations array? (This should be included in the image's own description, but I include it explicitly in case not.)
What happens if you delete your build folder and re-build?

Related

Getting Selected value from NSTableView

I'm trying to build this application where the Column 'Package Name' is populated from Core data. The second column has NSButtonCell added in IB and the idea is each time a checkbox is selected I need to get the name of the corresponding zip file in the 'Package Name' column.
I tried something like this
- (void)tableViewSelectionDidChange:(NSNotification *)notification {
NSTableView * tableView = [notification object];
NSInteger rowIndex = [tableView selectedRow];
NSTableColumn *column = [tableView tableColumnWithIdentifier:#"package-name"];
NSCell *cell = [column dataCellForRow:rowIndex];
NSLog(#"Found Value %#",cell.stringValue);
}
But the Value I get each time is different and inconsistent. For example if I select the 6ht checkbox (as shown in the screenshot), I expect to see 4.zip getting printed, but I get something else. How do I fix this ?
Both my Package Name and Installation Status columns are sortable.
Thanks
Don't consult the cells of the table. Instead, go straight to the data source or, if you're using bindings, the array controller.
First, in NSCell-based table views, there's typically a single cell object for the whole column. It is reused. It is configured for the first row and asked to draw in the appropriate location for that row. Then, it's configured for the second row and asked to draw in the appropriate location for the second row. Etc. So, retrieving the cell does not give you data for any particular row. The cell will have whatever properties it had the last time it was configured for a row, which may have been a completely different row than you're interested in.
(You could work around this by asking for the prepared cell for a row, using -[NSTableView preparedCellAtColumn:row:]. But that's really the roundabout way of doing things. The table view will just have to consult the data source in order to prepare the cell.)
If you're using an array controller, then your window/view controller should have an outlet to the array controller. Then, you can get the appropriate model object for a given row by calling:
object = [self.arrayController.arrangedObjects objectAtIndex:row];
If you're interested in the selected objects and your bindings are set up properly, you can just get the selected model object(s) directly from the array controller:
object = self.arrayController.selectedObjects[0];
Or:
for (object in self.arrayController.selectedObjects)
{
// ...
}
Note, though, that checking the checkbox in the second column is a distinct thing from selecting a row. Depending on how the table is configured, the user may be able to do either without the other. For example, they could select a row by clicking in the first column, which would not check the checkbox in the other column. They could also change the selection with the keyboard (e.g. down arrow).

IB UITableView not defined prototype cells are displayed?

In Interface Builder in a UITableViewController I specified the amount of prototype cells and configred them. In the Code the numberOsSectionsInTableView: and tableView:numberOfRowsInSection: is set accordingly. In this case 5 cells.
Somehow in the Simulator more (empty) prototype cells are displayed.
Interesstingly I have another project where I did the same, but there the correct amount of prototype cells are show.
How do I fix this and just show the wanted amount of prototpye cells?j
I realise this has already been answered but I feel the end to actually explain what is going on here rather than barking out some code.
First thing's first, prototype cells have no baring on how many cells are going to be displayed. When you set the number of static cells, thats how many will show up, dynamic cells are blank slates. You are suppose to use these to create 1 dynamic cell with a place holder for an image and a place holder for a piece of text. Then you tell the tableview how many rows you want and you get a reference to a reusable cell by calling the line:
[tblView dequeueReusableCellWithIdentifier:#" <id> "];
Then you would set the image and the text appropriately on the returned cell.
What you are doing is creating X "Blank slates" with default values and not overwriting these values. The way I have mentioned was designed for performance reasons and memory usage reasons. The way I mentioned effectively has 1 class instance in memory being reused, while yours has X many in memory all being used once.
Secondly the reason that you were seeing blank rows is that in a tableview not using grouped style, the tableView Will display as many rows as fit inside the bounds you have given it. Regardless of how many you tell it to display.
The reason this code:
self.tableView.tableFooterView = [[UIView alloc] init];
removes the blank rows is because a footer will be added after the last row with content, and the tableView will not display any rows, blank or otherwise after this point.
Hope this helps.
Try this code in your viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
*// self.tableView.tableFooterView = [[[UIView alloc] init] autorelease];*
*//Since memory management is controlled by ARC now, so ignore autorelease*
self.tableView.tableFooterView = [[UIView alloc] init] ;
}
Hope this helps!

Array with selectItemAtIndexPath of a UICollectionView

I'm trying to programmatically select cells in a UICollection view. I'm new to Obj-C and I'm not quite sure how to use the selectItemAtIndexPath property. I can grab an array of the images the user has previously selected. It is just an array of numbers corresponding to named images. But I'm not sure how to use that information with selectItemAtIndexPath.
I've looked for examples of someone using
- (void)selectItemAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(UICollectionViewScrollPosition)scrollPosition
But I'm not sure how to use it with my UICollectionView so I can have the right cells selected when the view loads and thus be highlighted. I have multiple selection on.
You should call selectItemAtIndexPath: for each cell you want to highlight, like so:
[self.collectionView selectItemAtIndexPath:path animated:NO scrollPosition:UICollectionViewScrollPositionNone]
Note that for one item (and one only!) you probably want to set the animated property to YES and provide a scroll position (one item only because otherwise you're going to be making a lot of needless animation calls).
You'll first need to get the index paths of the cells you want to select. The index path consists of two numbers: the section the cell is in and the row number (or order, if your collection view doesn't have rows) of the cell inside that section.
If you store the index paths of the cells the user has selected in an array then you can just iterate through. Otherwise you'll need to find the index path out, using a UICollectionView method such as indexPathForCell.

Vary table view cell height based on text

I have a table view with a few cells. The text that fills up the cell is unpredictable (based on the result of an API request). What I want to do is adjust the cell's height based on if the cell's text is too lengthy for the cell (e.g. the cell adds '...' to the text).
That way whatever the result/text and gets presented into a table view cell is always fully shown.
I would prefer not to implement the heightForRowAtIndexPath because I would have to implement a lot of code to do so.
UPDATE:
When I say "I have a lot of code to do so", I mean I literally have a lot of code parsing out requests and checking for conditions and performing algorithms and plus I have many table views. Just moved that stuff to another method and Im off to go!
Could you point me to any resources demoing this, do you know how to do this?
You must implement heightForRowAtIndexPath to vary the height of your table rows, but there isn't necessarily alot of code needed to calculate the height.
Use NSString:sizeWithFont:constrainedToSize to calculate the cell size needed.
//szMaxCell contains the width of your table cell, and the maximum height you want to allow
// strCellContents is an NSString containing the text to display
CGSize szMaxCell = CGSizeMake (tableView.frame.size.width - 20,999);
UIFont *font = [UIFont systemFontOfSize:12]; // whatever font you're using to display
CGSize szCell = [strCellContents sizeWithFont:font constrainedToSize:szMaxCell lineBreakMode:UILineBreakModeWordWrap];
szCell contains the size of the label. You'll use this size both to calculate the frame of your UILabel in your cellForRowAtIndexPath, as well as in your heightForRowAtIndexPath.
Use heightForRowAtIndexPath. It shouldn't be lots of extra code. Just get a reference to the object you are populating your cell with, check out the length of that text value and return the height you need. That is exactly what that delegate method is designed for.

How do you keep text from wrapping in an NSTableView using NSAttributedString

I have an NSTableView that has 2 columns, one for an icon and the other for two lines of text. In the second column, the text column, I have some larger text that is for the name of an item. Then I have a new line and some smaller text that describes the state of the item.
When the name becomes so large that it doesn't fit on one line it wraps (or when you shrink the window down so small that it causes the names to not fit on a single line).
row1===============
| image | some name |
| image | idle |
row2================
| image | some name really long name | <- this gets wrapped pushing 'idle' out of the view
| image | idle |
===================
My question is, how could I keep the text from wrapping and just have the NSTableView display a horizontal scroll-bar once the name is too large to fit?
Scrolling in Cocoa is implemented with the NSScrollView which is a view instead of a cell so if you really want to implement horizontal scrolling for table view cells I think you'd have to subclass the whole NSTableView and implement the feature there. My suggestion (without knowing the specifics of your situation, of course) is that you don't do that, though, since it's nonstandard behaviour and would probably entail quite a bit of work.
Truncate Instead of Wrap
If you're using a standard NSTextFieldCell, just select "Truncates" for its layout value in IB instead of "Wraps".
If you have a custom NSCell where you're doing your own drawing (I assume this is the case here), you should create an NSParagraphStyle, set its line break mode, add it as a value for the NSParagraphStyleAttributeName key in the NSAttributedString's text attributes dictionary.
An example:
NSMutableParagraphStyle *paragraphStyle = [[[NSMutableParagraphStyle alloc] init] autorelease];
[paragraphStyle setLineBreakMode:NSLineBreakByTruncatingTail];
[attributedStr
addAttribute:NSParagraphStyleAttributeName
value:paragraphStyle
range:NSMakeRange(0,[attributedStr length])];
Cell Expansion Frames
If you don't want to wrap your lines of text in the table view cells, the standard method of allowing the user to see the whole text is to use cell expansion frames which are enabled by default:
Cell expansion can occur when the mouse hovers over the specified cell and the cell contents are unable to be fully displayed within the cell.
If they're not working for some reason and you're using a custom NSCell subclass, make sure you implement -drawWithExpansionFrame:inView: and -expansionFrameWithFrame:inView: in your cell. Also make sure you're not returning NO in your NSTableViewDelegate for -tableView:shouldShowCellExpansionForTableColumn:row: (if you have one).
Adjust Width of Whole Table View?
If what you want to do is to adjust the width of a specific column (and thus the whole table view, possibly causing the enclosing scroll view's horizontal scroll bar to appear) such that the text its cells contain would never be truncated or wrapped, you can probably do that in your NSTableViewDelegate, for example, by calling -cellSize for each row's cell in that column and resizing the column to the largest value (you'll want to only do this when the values change, of course).