wxPython/ReportLab: How to create and open a .pdf file on button clicked

不羁岁月 提交于 2019-12-24 12:43:50

问题


Good day all, For about 3days I have been trying hardest to get my way around this! I have a perfectly working wxFrame as well as a perfectly working ReportLab pdf script. See the code files below respectively (Note: data1.py is the GUI while data2.py is the running pdf script). My problems are:- 1) I want the pdf script to run only after I press the “Save To PDF” button 2) The value of the name field (as stored in a variable “NameString”) should be added to the generated pdf file.

At the moment, if I run the script (data2.py) it creates but the Frame and the pdf file (without including the “NameString”) at the same time. That is not what I want, I want the pdf to open and include the “NameString” only after I clicked/press the “Save To PDF” button.

Thanks in advance for your time.

data1.py

class MyFrame1 ( wx.Frame ):

    def __init__( self, parent ):
        wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( 250,150 ), style = wx.CAPTION|wx.CLOSE_BOX|wx.MINIMIZE_BOX|wx.SYSTEM_MENU|wx.TAB_TRAVERSAL )

        self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )

        DataBox = wx.BoxSizer( wx.HORIZONTAL )

        gSizer2 = wx.GridSizer( 0, 2, 0, 0 )

        self.NameLabel = wx.StaticText( self, wx.ID_ANY, u"Name", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.NameLabel.Wrap( -1 )
        self.NameLabel.SetFont( wx.Font( 13, 70, 90, 90, False, wx.EmptyString ) )

        gSizer2.Add( self.NameLabel, 0, wx.ALL, 5 )

        self.NameField = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
        gSizer2.Add( self.NameField, 1, wx.ALL, 5 )

        self.SaveToPDF = wx.Button( self, wx.ID_ANY, u"Save To PDF", wx.DefaultPosition, wx.DefaultSize, 0 )
        gSizer2.Add( self.SaveToPDF, 0, wx.ALL, 5 )


        DataBox.Add( gSizer2, 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5 )


        self.SetSizer( DataBox )
        self.Layout()

        self.Centre( wx.BOTH )

        # Connect Events
        self.SaveToPDF.Bind( wx.EVT_BUTTON, self.SaveToPDF_Function )

    def __del__( self ):
        pass


    # Virtual event handlers, overide them in your derived class
    def SaveToPDF_Function( self, event ):
        event.Skip()

data2.py

#!/usr/bin/python
# -*- coding: utf-8 -*- 


import wx
from data1 import MyFrame1

from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A3
from reportlab.lib.pagesizes import landscape

import os
import tempfile
import threading



class MyFrame2(MyFrame1):
    def __init__(self, parent):
        MyFrame1.__init__ (self, parent)



    def SaveToPDF_Function( self, event ):

        NameString = self.NameField.GetValue()
        print NameString




file_not_fount = "Selected file doesn't exist!"


class Launcher(threading.Thread):
    def __init__(self,path):
        threading.Thread.__init__(self)
        self.path = 'myFile.pdf'
    def run(self):
        self.open_file(self.path)



    def open_file(self,path):

        if os.path.exists(path):
            if os.name == 'posix':
                subprocess.call(["xdg-open", path])
                #os.popen("evince %s" % path)
            else:
                os.startfile(path)
        else:
            wx.MessageBox(self.file_not_fount,
                          self.title,
                          wx.OK|wx.ICON_INFORMATION)

# NameString = raw_input("Enter ur text: ")

c = canvas.Canvas("myFile.pdf", pagesize=landscape(A3))

c.drawCentredString(600, 800, 'I want this to open only after I clicked the “Save To PDF” button. Also, the text field value (NameString variable) should appear here =>'  + 'NameString' )

c.save()

Launcher('myFile.pdf').start()






app = wx.App(0)
MyFrame2(None).Show()
app.MainLoop()

回答1:


Here is a simple working solution I came accross to auto open pdf file generated with ReportLab.

Import subprocess and ReportLab modules as usual. Then link this function to your event (the magic part of the code is subprocess.Popen.....)

def SaveToPDF_Function( self, event ):

    NameString = self.NameField.GetValue()

    try:
        c = canvas.Canvas("myFile.pdf", pagesize=landscape(A3))

        c.drawCentredString(600, 800, 'OPENED... Welcome to ReportLab! This is my FIRST App...'  + NameString )

        c.save()

        subprocess.Popen(['myFile.pdf'], shell=True)

    except IOError:
        print 'The file is already OPENED!'

Hope this help someone in future search.




回答2:


First of all, I would create the reportlab module so that you can actually call it. As it is currently implemented, it will immediately create the PDF whenever it is run. You need to put all the reportlab code into a function of some sort. Since this is a really simple reportlab script, I just combined it with the wxPython code and removed the threading portion so you can see one easy way to do it:

import wx

from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A3
from reportlab.lib.pagesizes import landscape

class MyFrame1 ( wx.Frame ):

    def __init__( self ):
        wx.Frame.__init__ ( self, None, 
                            size = wx.Size( 250,150 ), 
                            style = wx.CAPTION|wx.CLOSE_BOX|wx.MINIMIZE_BOX|wx.SYSTEM_MENU|wx.TAB_TRAVERSAL )

        self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )

        DataBox = wx.BoxSizer( wx.HORIZONTAL )

        gSizer2 = wx.GridSizer( 0, 2, 0, 0 )

        self.NameLabel = wx.StaticText( self, wx.ID_ANY, u"Name", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.NameLabel.Wrap( -1 )
        self.NameLabel.SetFont( wx.Font( 13, 70, 90, 90, False, wx.EmptyString ) )

        gSizer2.Add( self.NameLabel, 0, wx.ALL, 5 )

        self.NameField = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
        gSizer2.Add( self.NameField, 1, wx.ALL, 5 )

        self.SaveToPDF = wx.Button( self, wx.ID_ANY, u"Save To PDF", wx.DefaultPosition, wx.DefaultSize, 0 )
        gSizer2.Add( self.SaveToPDF, 0, wx.ALL, 5 )


        DataBox.Add( gSizer2, 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5 )


        self.SetSizer( DataBox )
        self.Layout()

        self.Centre( wx.BOTH )

        # Connect Events
        self.SaveToPDF.Bind( wx.EVT_BUTTON, self.SaveToPDF_Function )

        self.Show()

    #----------------------------------------------------------------------
    def create_pdf(self):
        """"""
        nameString = str(self.NameField.GetValue())
        c = canvas.Canvas("myFile.pdf", pagesize=landscape(A3))

        txt = """'I want this to open only after I clicked the "Save To PDF" 
        button. Also, the text field value (NameString variable) should appear 
        here =>'  + %s """ % nameString
        c.drawCentredString(600, 800, txt)

        c.save()


    # Virtual event handlers, overide them in your derived class
    def SaveToPDF_Function( self, event ):
        self.create_pdf()

if __name__ == "__main__":
    app = wx.App(False)
    frame = MyFrame1()
    app.MainLoop()

I recommend reading the following articles on threads and wxPython:

  • http://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/
  • http://wiki.wxpython.org/LongRunningTasks

To add threading back in, I would create a threading class like your Launcher. However, I would put ALL the reportlab code inside that class and when you instantiate the Thread class, you would pass in the namedString:

class Launcher(threading.Thread):
    def __init__(self,path, namedString):
        threading.Thread.__init__(self)
        self.path = 'myFile.pdf'
        self.namedString = namedString

I hope this helps!



来源:https://stackoverflow.com/questions/24240580/wxpython-reportlab-how-to-create-and-open-a-pdf-file-on-button-clicked

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!