问题
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