On 15/04/18 03:57, Chris Roy-Smith wrote: > The code does not wait till the function returns a value,
OK, I've had a closet look now and can confirm the problem lies in your code structure. Its not event based. You need to understand event-driven programming better. In event driven code you initialise your program (including the GUI) and then wait for events - usually from the user. When you receive an event you handle that event - and only that specific event - before returning to the wait state until the user makes the next move. The problem with your code is that you build a basic GUI then wait. But when the user presses a button you create a second set of GUI elements and then *without waiting for the user to do anything* try to process the data in the new elements. That is why you get nothing back, the user hasn't done anything yet. The other, related, problem is that event handlers do NOT return values. You can't assign the value of an event callback method to a variable you have to use a global variable inside the event function. (Note: This is one reason GUIs are often built using objects because you can assign to an window object's attribute rather than a global variable, which makes for slightly cleaner code, easier to maintain.) So what to do? You need to break your data processing code out to a separate function(*) then call that only when you know there is data to be processed. That wont happen until you get the submit action from the user. So you need to call the data processing in your final callback - ReturnCount in your case. (*)Technically, you could just move the code into ReturnCount but that makes the callback code overly complex, better to keep reading and displaying as distinct operations. So the flow of action should be: initialise GUI and wait. on clock -> create extended GUI and wait on click -> create input dialog and wait on click -> read data and if valid -> call data processing function delete input dialog wait else -> reset fields and/or generate error message wait Note how the end of each step waits for the user to initiate the next action? That's the event driven bit. How do we wait? We do nothing, the GUI mainloop handles all that for us. > #!/usr/bin/python3 > from tkinter import * > import os > from reportlab.lib.units import cm > from reportlab.lib.pagesizes import A4 > from reportlab.pdfgen import canvas > from reportlab.lib.utils import ImageReader > > def printSign(): > global gc, packages, rows > myCanvas = canvas.Canvas("Signs.pdf", pagesize=A4) > width, height = A4 #keep for > myCanvas.rotate(90) > myCanvas.setFillColorRGB(0,0,0) > myCanvas.setFont("Helvetica-Bold", 400) > TopMargin=-20 > LeftMargin=1 > Width=14 > Height=19 > VertPos=-15 > Bottom=-1 > a=[" " for i in range(rows)] > i=0 > sign=0 All the stuff below here should go in a function called something like display??? where ??? is whatever your data represents. > for line in packages: > signcount=getcount(line[1]) > print('line 27 ### required sign count for {} is {} > ###'.format(line[1], str(signcount))) > for x in range(signcount): > #draw rectangle > myCanvas.rect(LeftMargin*cm+Width*sign*cm, TopMargin*cm, > Width*cm, Height*cm, stroke=0, fill=1) > myCanvas.drawCentredString((LeftMargin+(0.5*Width))*cm+(Width*sign)*cm, > VertPos*cm, line[0]) > if sign==1: > myCanvas.showPage() > sign=0 > myCanvas.rotate(90) > i+=1 > else: > sign+=1 > i+=1 > > myCanvas.showPage() > myCanvas.save() > if os.name == "posix": > os.popen("evince %s" % ("Signs.pdf")) > if os.name == "nt": > os.startfile('Signs.pdf') > > def getcount(SignText): > global gc,e > gc=Toplevel(master) > MsgText='How many copies of {} do you want to print?'.format(SignText) > Label(gc, text=MsgText).grid(row=0, column=0, sticky=(W,E)) > e = Entry(gc) > e.grid(row=0, column=1) > Button(gc, text='Okay', command=ReturnCount).grid(row=1, column=0, > sticky=(W,E)) > Button(gc, text='Cancel', command=gc.destroy).grid(row=1, column=1, > sticky=(W,E)) > > def ReturnCount(): > global gc,e > b0=e.get() > if b0 == None: > b0=0 call display??? here > gc.destroy() > print('line 64 ### The required number of signs is {} > ###'.format(b0)) > return b0 You need to make b0 (can't you think of a more informative name? count say?) Then you can access b0 from your display??? code > > master = Tk() > master.title("Testing") > packages = [[0,'D','drill'],[1,'J','Jointer'],[2,'B','Bandsaw']] > rows = 3 > b2 = Button(master, text="Print Signs", command=printSign).grid(row=4, > column=0, sticky=(W,E), padx=5, pady=5) > b3 = Button(master, text="Quit", command=master.destroy).grid(row=4, > column=3, sticky=(W,E)) > > master.mainloop() Finally, I still think you would be better creating all of the initial GUI window at the beginning (ie in the code just above this paragraph) And then your printSign() code will be much smaller, basically just a call to getcount() In fact you can probably eliminate all of printSign and make getcount the direct callback function of Button b2. (Please use better names in future it makes it much easier to read and comment on your code! Including for yourself in 6 months if you have to modify it!) For more on event driven programming principles read the event-driven programming and GUO topics in my web tutorial. HTH -- Alan G Author of the Learn to Program web site http://www.alan-g.me.uk/ http://www.amazon.com/author/alan_gauld Follow my photo-blog on Flickr at: http://www.flickr.com/photos/alangauldphotos _______________________________________________ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor