Printing/PDF'ing the contents of a wxGrid

Hi, I'm just getting started learning how to print/print
preview, and am reviewing the Wiki and the docs as I write
this.

I simply want to know if anyone has a recipe that can take a
grid, with any number of rows and columns, and put it to a PDF
file and/or print it out.

Failing that, perhaps some pointers on what I would need to
construct such a beast:

+ would I actually need to scroll through the grid, getting the
rect's of all the rows, or is there a better way?

+ for preparing the output, is wxPrintDC the class to use?

Thanks!

···

--
Paul

Paul McNett wrote:

Hi, I'm just getting started learning how to print/print preview, and am reviewing the Wiki and the docs as I write this.

I simply want to know if anyone has a recipe that can take a grid, with any number of rows and columns, and put it to a PDF file and/or print it out.

Yeah. Here's a simple way of doing it. Take your grid and convert it to an html table. Then use wxHtmlEasyPrinting to print it out. Otherwise you can launch it in your webbrowser and let that be your printing option.

It's trickier if your grid contains images, you have to save the images as gifs and link them to your html table.

Anyway, here's some code to write a grid to html so that you can use it with wxHtmlEasyPrinting.

def addcell(s):
    return "<TD>%s</TD>"%s

def addrow(ls):
    # adds a list of strings as a row
    return "<TR>%s</TR>"%"\n\t".join([addcell(x) for x in ls])

def gridToHtml(grid):
    docstart = "<HTML><BODY>"
    docend = "</BODY></HTML>"
    out = [docstart, "<TABLE BORDER CELLPADDING=0 CELLSPACING=0>"]

    cols = grid.GetNumberCols()
    # add headers to table
    _row = ["ROW"]
    _row.extend( [grid.GetColLabelValue(x) for x in range(cols)] )
    out.append(addrow(_row))
                         for r in xrange(grid.GetNumberRows()):
        _row = [grid.GetRowLabelValue(r)]
        for c in range(cols):
            _row.append(grid.GetCellValue(r, c))

        out.append(addrow(_row))

    out.append("</TABLE>")
    out.append(docend)
    return "\n".join(out)

Brian Kelley writes:

Paul McNett wrote:

>I simply want to know if anyone has a recipe that can take a
>grid, with any number of rows and columns, and put it to a
> PDF file and/or print it out.

Yeah. Here's a simple way of doing it. Take your grid and
convert it to an html table. Then use wxHtmlEasyPrinting to
print it out. Otherwise you can launch it in your webbrowser
and let that be your printing option.

Thanks for that, I'd forgotten about wxHtmlEasyPrinting even
after learning about it just a couple weeks ago! I took your
code, tweaked it a little, and made it part of my base grid
class, so that my framework can simply ask the grid for it's
current rendition in HTML for whatever reason. I added the
option to not include the HTML and BODY tags, in case the
framework wants to handle it (perhaps the grid's HTML is
just a part of a larger HTML doc). I also made the headers
print in bold, and I added a <TD WIDTH> attribute and
based it off of grid.GetColSize(col). So the user resizes the
grid, and they see their sizing reflected on the printout.

It's trickier if your grid contains images, you have to save
the images as gifs and link them to your html table.

I'll need images... I guess I need to write out the image
files to the temp directory, huh? That's too bad, since they
aren't files at this point (they are BLOBs in a DB) and the
writing out will add overhead and housekeeping. But I
can't complain too much, I suppose... this is just too easy!

Some oddities I noticed on wxGTK:
  + preview shows "Page 1 of 999"
  + zooming will zoom the page size, but not the
    page contents

Anyway, here's some code to write a grid to html so that you
can use it with wxHtmlEasyPrinting.

Thanks for including your code, it was very helpful. Here is my
code, which was based on yours, and is a method in my grid
base class:

    def getHTML(self, justStub=True, tableHeaders=True):
        ''' Get HTML suitable for printing out the data in
            this grid via wxHtmlEasyPrinting.
            
            If justStub is False, make it like a standalone
            HTML file complete with <HTML><HEAD> etc...
        '''
        cols = self.GetNumberCols()
        rows = self.GetNumberRows()
        
        if justStub:
            html = ["<HTML><BODY>"]
        else:
            html =
            
        html.append("<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0>")
        
        if tableHeaders:
            html.append("<TR>")
            for col in range(cols):
                html.append("<TD ALIGN='center' VALIGN='top' WIDTH=%s><B>%s</B></TD>"
                                % (self.GetColSize(col), self.GetColLabelValue(col)))
            html.append("</TR>")
        
        for row in range(rows):
            html.append("<TR>")
            for col in range(cols):
                html.append("<TD ALIGN='left' VALIGN='top'>%s</TD>"
                                % self.GetCellValue(row,col))
            html.append("</TR>")
        
        html.append("</TABLE>")
        return "\n".join(html)

···

--
Paul

I'll need images... I guess I need to write out the image
files to the temp directory, huh?

No, you can use your own tags.

Create a wxFileSystemHandler and return them from that.
I do it for my project (and also allow resizing). For
example in my html I can put:

   bpuserimage:foo.jpg;width=32;height=32

Roger

Paul McNett wrote:

Thanks for that, I'd forgotten about wxHtmlEasyPrinting even after learning about it just a couple weeks ago! I took your code, tweaked it a little, and made it part of my base grid class, so that my framework can simply ask the grid for it's current rendition in HTML for whatever reason. I added the option to not include the HTML and BODY tags, in case the framework wants to handle it (perhaps the grid's HTML is just a part of a larger HTML doc). I also made the headers print in bold, and I added a <TD WIDTH> attribute and based it off of grid.GetColSize(col). So the user resizes the grid, and they see their sizing reflected on the printout.

I would love to make a general purpose exporter. I have a home-grown one that can export grids to HTML and Microsoft Excel. It uses something similar to my grid_MegaExample to determine what cells have images and places them in the appropriate cells in the html widget or the excel spreadsheet.

To make a generic exporter, I need to be able to determine which cells have string values and which cells are images. I'm really not sure that this is possible with the current scheme. If we could distinguish between values that could be represented as strings (numbers, text, etc) and images then we could use the cell renderers.Draw function to generate the appropriate output for printing.

I haven't been able to figure this out though. My workaround has been to explicitly label a cell or row or column as an image column and take it from there.

Alternatively we could introduce a wxPyGridImageRenderer that, if used, would print appropriately for the output.

As long as people are willing to help debug, I'll implement the wxPyGridImageRenderer and submit my code for outputing grids containing images to html/excel etc. Then someone could supply the gnumeric/open office port and the applescript for interfacing with excel on the macintosh. Now, that would be a good trade :slight_smile:

Brian

Roger Binns wrote:

I'll need images... I guess I need to write out the image
files to the temp directory, huh?

No, you can use your own tags.

Create a wxFileSystemHandler and return them from that.
I do it for my project (and also allow resizing). For
example in my html I can put:

   bpuserimage:foo.jpg;width=32;height=32

Or you can put the html doc in the FS too and just use <IMG> tags like normal with a relative link. Then you just need to use the protocol specifier for the FS when loading the page in wxHtmlWindow or in wxHtmlEasyPrinting. For example, if you are using the memory FileSystem something like this should work:

  wxFileSystem_AddHandler(wxMemoryFSHandler())
...

  htmlText = """<img src="aBitmap.jpg">"""

  wxMemoryFSHandler_AddFile("myfile.html", htmlText)
  wxMemoryFSHandler_AddFile("aBitmap.jpg", bitmap, wxBITMAP_TYPE_JPEG)

  htmlwin.LoadPage("memory:myfile.html")

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Brian Kelley wrote:

Paul McNett wrote:

Thanks for that, I'd forgotten about wxHtmlEasyPrinting even after learning about it just a couple weeks ago! I took your code, tweaked it a little, and made it part of my base grid class, so that my framework can simply ask the grid for it's current rendition in HTML for whatever reason. I added the option to not include the HTML and BODY tags, in case the framework wants to handle it (perhaps the grid's HTML is just a part of a larger HTML doc). I also made the headers print in bold, and I added a <TD WIDTH> attribute and based it off of grid.GetColSize(col). So the user resizes the grid, and they see their sizing reflected on the printout.

I would love to make a general purpose exporter. I have a home-grown one that can export grids to HTML and Microsoft Excel. It uses something similar to my grid_MegaExample to determine what cells have images and places them in the appropriate cells in the html widget or the excel spreadsheet.

To make a generic exporter, I need to be able to determine which cells have string values and which cells are images. I'm really not sure that this is possible with the current scheme. If we could distinguish between values that could be represented as strings (numbers, text, etc) and images then we could use the cell renderers.Draw function to generate the appropriate output for printing.

How about

  grid.GetTable().GetTypeName(row, col)

Normally this will only deal with the basic datatypes that wxGrid already knows about, but there is some support for custom datatypes that I've been meaning to turn into arbitrary PyObjects instead.

I haven't been able to figure this out though. My workaround has been to explicitly label a cell or row or column as an image column and take it from there.

Alternatively we could introduce a wxPyGridImageRenderer that, if used, would print appropriately for the output.

As long as people are willing to help debug, I'll implement the wxPyGridImageRenderer and submit my code for outputing grids containing images to html/excel etc. Then someone could supply the gnumeric/open office port and the applescript for interfacing with excel on the macintosh. Now, that would be a good trade :slight_smile:

Sounds good.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!