Images in NSTableView

Ok, I’m having real issues with creating a table with images in. I have an application that I want to select a folder full of images and populate the Table, then once the user selects a image within the table it displays relevant information about that image.

I have searched the forums and have downloaded the “Image Cells” example from http://www.jonn8.com/html/misc_projects.html but I cannot understand how he has created the data source.

Does anybody have a any standard code for adding images into a NSTableView ? Please…

Thanks
Paul.

Hi Paul,

  • open your GUI in the InterfaceBuilder
  • copy the object “ASKDataSource” (fromt the example NIB file) to your NIB file
  • activate your table view
  • click one more time in the table view
  • press the ctrl and hold them down
  • move the cursour to the “ASKDataSource” and connect with them

Now, you can use the table view in your ASS application.

Here some example how it works:

cu

Hi little_pixel,

thanks for the reply, I’ve managed to get that side working (by copying the “ASKDataSource” from the NIB but once the images load in I can’t do much with them. What I want to do is to be able to select a image and have some information come back about that image.

I’ve copied the code below:

on clicked theObject
	if name of theObject = "load" then
		set the_folder to (choose folder with prompt "Choose a folder with JPEG files:") as Unicode text
		set the_images to paragraphs of (do shell script "find " & (quoted form of POSIX path of the_folder) & " -iname '*.jpg' | tr -s '/'")
		set the_table to table view 1 of scroll view 1 of window "main"
		tell data source of table view "1" of scroll view "1" of window "main" to make new data column at end of data columns with properties {name:"image"}
		
		-- add a new row
		tell data source of table view "1" of scroll view "1" of window "main"
			repeat with this_image in the_images
				set newRow to make new data row at end of data rows
				tell newRow
					tell newRow to set contents of data cell "image" to (load image (contents of this_image))
				end tell
			end repeat
		end tell
		tell window "main" to update
	end if
	
	
	
	if name of theObject = "reveal" then
		set theSelectedRow to selected data row of table view 1 of scroll view 1 of window "main"
		set thePath to contents of data cell 1 of theSelectedRow
		display dialog thePath
	end if
end clicked

But when I select the reveal button I get the following error " <> id 18 doesn’t understand the <> message (-1708)

Also is do you know if there is anyway to edit the “ASKDataSource”?

Thanks
PB

Hi Paul,

that isn’t possible on this way. You load the content of the image and so there is no more information. The content of the shown image is buffering in the memory. There is no more “link” to the image.

cu

Bugger, any ideas how to get around this?

Anybody else have any ideas?

Hi,

make a new hidden column in your table view. Write the path to this.
It is very simple and effectly.

cu

As a general rule, whenever someone tells you to create any “hidden” interface element, you should consider that they may not be giving you the right advice or that they are using misleading terminology. Hidden interface elements are a HACK, and should never be used. While the difference between ‘column’ and ‘cell’ may not seem important, I wouldn’t want you to end up trying to add a “hidden column” to your table view. Rather than creating a hidden column, you should store an unused (ie, not displayed in your table view) data cell in your data source that holds the path to the file. When you need to get the image’s path, simply ask the data row for the value of it’s ‘path’ cell. See my ‘double clicked’ handler. And, unless you have a good reason, you do not need to add an ‘ASKDataSource’ object to your nib. It’s actually better (in my opinion) to simply create it in your code programmatically. Otherwise you have to get a reference to it somehow in your code so you can reference it later.

Here’s the code from my test app that displays a table of images…

property tableView : null
property tableViewDataSource : null

on awake from nib theObject
	if name of theObject is "tableView" then
		set tableView to theObject
		set data source of theObject to tableViewDataSource
	end if
end awake from nib

on will finish launching theObject
	set tableViewDataSource to make new data source at end with properties {name:"tableViewDataSource"}
	tell tableViewDataSource
		make new data column at the end of the data columns with properties {name:"icon"}
		make new data column at the end of the data columns with properties {name:"path"}
	end tell
end will finish launching

on clicked theObject
	if name of theObject is "ChooseFolder" then
		set directoryPath to choose folder --> Get a folder

		tell application "System Events" --> Use system events to get a list of all the jpeg files' paths in a folder
			set directoryContents to get (path of (every file of directoryPath whose type identifier is "public.jpeg")) as list
		end tell

		tell tableViewDataSource
			delete every data row --> Delete all old row from the datasource
			
			repeat with newItem in directoryContents --> Add new rows for all the items in the new directory
				set newRow to make new data row at the end of the data rows of tableViewDataSource
				set contents of data cell "path" of newRow to newItem
				set contents of data cell "icon" of newRow to (load image (POSIX path of newItem))
			end repeat
		end tell
	end if
end clicked

on double clicked theObject
	if theObject is tableView then
		try
			set dataRow to selected data row of theObject
			set dataRowPath to (contents of data cell "path" of dataRow) as string
			
			--> Do something with the path
			set dataRowPathInfo to (info for (dataRowPath as alias))
			log (displayed name of dataRowPathInfo)
			
		on error errMsg
			beep
			log errMsg
			
		end try
	end if
end double clicked

Hi jobu,

tell me: What are the difference on your solution?
It is absolutly the same way, only your column is visible.

When he will see more columns then his image, he is going to this. But he won’t this and so it is the only way.
It is no hack, it is the truth.

cu

The first difference, is that I constructed my data source programmatically not in IB. There is no logistical difference between the one you created in IB and the one I created in code. I just prefer to do it this way.

The difference I pointed out with your example (and believe me, I certainly have considered the obvious language barrier) was in telling him to add a hidden column to the table view. A column is an interface element, not a data element. You add data columns to a data source to identify the possible columns in a data source. The purpose for this is to enable automatic key/value matching when assigning the data source to a table. If your table has two columns, i.e. “path” and “icon”, it automatically inserts data from your data source into the appropriate column. In your table’s data source, you add data rows, which in turn contain data cells. These cells associate themselves automatically to the appropriate columns by the same key/value mechanism. So, if you have data source with data rows, all of which have two cells named “path” and “icon”, the data from the respective data cells automatically lines itself up with the corresponding data columns in the data source. Data cells and columns are different things, as are the data source and the table itself. Just because I declare a ‘path’ column in the data source doesn’t mean that I have to have a matching table column in my table. Remember, a data source is just that… an object that stores data as a source for other objects to access. When I set the data source for the table, it goes through the columns for the table and looks for matching data columns in the data source. If it finds one, it uses the values for data cells matching the data column as the source for that column. If it doesn’t it might enter null values or throw an error. But, if there are extra data columns in the data source they are ignored by the table, because it only wants data that matches it’s configuration.

For example, say I have this data source…
data source “DataSourceX”
– data column “Name”
– data column “Age”
– data column “Height”
– data column “Weight”

Then I add some data rows to it, all of which provide the appropriate values in their corresponding data cell values. The beauty of data sources, is that I can now use this data source dynamically with any object compatible with the data source. In fact, I can use the same data source with multiple table views if I want.

I could have one table view that only shows name and height…
table view “TableView1”
– table column “Name”
– table column “Height”

I could have another that shows all available fields, just the name, etc. The only thing I need to do to is add table columns with corresponding names, and then set the data source as the data source for that table, and it will automatically make the appropriate associations. In my example app, my table only has an ‘icon’ column… there is NO path column. But, when you click on the table and get a reference to it’s selected data row, you then have access to all of the other data cells of the data row… including the ones that your table doesn’t implement… thus exploiting the POINT of having a data source.

The biggest difference between my code and yours, is that I gave him working code that uses the correct approach to achieving his goal. You told him to add another column to his table view. If he were to try to add just a column to the table or the data source, it wouldn’t allow him the get the path of the image. He needs to add rows to the data source that include the “hidden” ‘path’ cell, which he can access the value of to get the path. I’m not trying to make my comments personal, I’m just pointing out semantic differences that are important, that might save PaulB a lot of time and keep him from trying to go about things that wrong way. I also provided real, tested code that actually does what he wants. To be an effective contributor, you need to do more than post telling people that “It doesn’t work that way”. You have to tell, and often show, them how it does work. Adding a data column to a data source and it’s corresponding data cells is the right way to create a data source. Adding a table column to a table to hold a path that you don’t want to be visible IS a hack. Either get your facts straight or your wording. Again, nothing personal, your comments are just misleading to people who already don’t understand something.