My Approach to printing NSTableView

Discussion in 'Mac Programming' started by DavidCar, Jan 24, 2007.

  1. DavidCar macrumors 6502a

    Jan 19, 2004
    This is actually my answer to this question on Cocoa-Dev, but I couldn't see how to post a reply there. The existing replies mostly used HTML, and I didn't like that approach. I also couldn't find an answer I liked elsewhere on the internet.

    I didn't want to learn HTML to print tabular data. This is the approach I took.

    Essentially, I have a separate invisible window with a copy of the displayed NSTableView nested inside a custom NSView called MyPrintableBox. When MyPrintableBox is asked if it knowsPageRange, it calculates the needed pages from the number of rows in the table. When asked for RectForPage it returns the bounds rect but saves the page number for use in the dataSource methods. The dataSource method calls to MyPrintableBox use the dataSource methods of the displayed table to obtain the required data. Some NSTextFields associated with the displayed table needed to be duplicated near the invisible printed table, and these were updated at the time MyPrintableBox was passed to the print method. Some code here was only used while I was testing the approach with the printable window set as being visible. Of course, an NSView could be used instead of an NSBox,

    I like this approach because I can initially use the same IB NSTableView and the dataSource methods used for the displayed table. I can later customize the appearance of the printed table to optimize it's printed appearance.

    // Try box size w:600 h:760
    @interface MyPrintableBox : NSBox {
    	int rows, pages, pageNum;
    	IBOutlet NSTextField *pageDisplay;
    	IBOutlet NSWindowController *dataSourceWindow;
    	IBOutlet NSTableView *PrintedTable;
    	BOOL doingPages;
    @implementation MyPrintableBox
    // The print method in MyDocument requests a printable NSView from MyWindow.
    // MyWindow Nib contains an extra invisible window with a copy of the displayed table nested
    // within an NSBox of this custom class, MyPrintableBox.  MyWindow returns MyPrintableBox
    // as the printable NSView requested by MyDocument.  MyWindow updates some duplicate
    // NSTextFields in myPrintableBox before filling the request.
    // The dataSource for the invisible table is MyPrintableBox.
    // The dataSource for the displayed table is MyWindow, connected here to dataSourceWindow
    int rowsPerPage = 35;
    - (id) initWithCoder:(NSCoder *)decoder {
    	[super initWithCoder:decoder];
    	rows = 0;
    	pages = 1;
    	pageNum = 1;
    	doingPages = NO;  // not needed, used for testing
    	return self;
    - (void) calculatePages {
    	rows = [dataSourceWindow numberOfRowsInTableView:nil];  // nil is ok in my case
    	pages = (rows / rowsPerPage) + 1; 
    	if (pages > 1)
    		if ((pages - 1) * rowsPerPage == rows)
    			pages = pages - 1;	
    - (BOOL) knowsPageRange:(NSRangePointer)range {
    	[pageDisplay setStringValue:@"Starting Pages"];
    	[self calculatePages];
    	range->location = 1;
    	range->length = pages;
    	doingPages = YES;
        return YES;
    - (NSRect) rectForPage:(int)page {
    	pageNum = page;
    	[pageDisplay setStringValue:[NSString stringWithFormat:@"Page %i of %i", page, pages]];
    	if (page == pages)
    		[PrintedTable reloadData];  // otherwise doesn't recall numberOfRowsInTableView
    	return [self bounds];	
    - (void) endDocument {  // not needed, used for testing
    	[super endDocument];
    	doingPages = NO; 
    	pageNum = 1;
    	[PrintedTable reloadData];  // otherwise doesn't recall numberOfRowsInTableView
    	[pageDisplay setStringValue:@"Finished Doing Pages"];
    - (int) numberOfRowsInTableView:(NSTableView *)aTableView { 
    	if (!doingPages) {
    		[self calculatePages];
    		pageNum = 1;
    		if (pageNum < pages) {
    			return rowsPerPage;
    		} else {
    			return (rows - ((pageNum - 1) * rowsPerPage));
    	} else if (pageNum < pages) {
    		return rowsPerPage;
    	} else 
    		return (rows - ((pageNum - 1) * rowsPerPage));
    - (id) tableView:(NSTableView *)aTableView 
    		objectValueForTableColumn:(NSTableColumn *)aTableColumn 
    			 row:(int)rowIndex { 
    	return [dataSourceWindow tableView:aTableView
    								   row:(((pageNum - 1) * rowsPerPage) + rowIndex)];
  2. kainjow Moderator emeritus


    Jun 15, 2000
    Several comments:

    1) is a wiki. They don't use HTML formatting for pages. Go read up on how to format your text: TextFormattingRules

    2) Didn't want to learn HTML? I don't know a single programmer who doesn't know HTML. You don't have to be a proficient XHTML 1.1 and CSS 3.0 scripter, but at least know basic HTML.

    3) Please use the BBCode "code" tag if you're posting code samples on here (or on any forum). And while I'm at it, if you're posting code at CocoaDev, use %%BEGINCODE%% and %%ENDCODE%% around the code.

    4) And finally, regarding your topic, I don't know why you'd ever want to print an actual NSTableView. NSTableView is a Mac OS X control that displays columned data. It isn't meant to be printed (although it can be). The printer != the screen. If you want printer functionality, format your data so it is made to fit on a page. Cocoa's documentation covers this. Yes, it may be a pain, but that's life ;)
  3. DavidCar thread starter macrumors 6502a

    Jan 19, 2004
    Thanks for the suggestions. I've added the BBCode "code" tag, and corrected the initialization. In this case, it was a simple project that wasn't worth the pain of a greater effort.
  4. sudhansusingh22 macrumors newbie

    Aug 9, 2012
    Not able to prinnt table data

    Hi David,
    I am still not able to print table view data following your approach. It is still printing only the part of table view to page size. Can you please send me project snippets.
  5. DavidCar thread starter macrumors 6502a

    Jan 19, 2004
    I wouldn't know where to find it now, in a 2007 project. sorry.

Share This Page