[Tutor] tkinter code executes before function returned

Alan Gauld alan.gauld at yahoo.co.uk
Sun Apr 15 04:10:27 EDT 2018


On 15/04/18 03:57, Chris Roy-Smith wrote:

> I am trying to get tkinter to return a number from a window, which then 
> sets how many times to print a sign.

I don;t jhave time to look at this in detail just now, maybe later.

But first impressions is that you have a very unorthodox style of
Tkinter programming. Its more traditional to build the entire GUI
up front rather than creating and destroying widgets each time you
execute an event handler. Its less disturbing to the user than
having things appear/disappear etc, as you seem to be doing.

You can make widget hide/show/deactivate themselves without
destroying them just by withdrawing/unpacking them etc or
changing their status, if that's really what you want to do.

> The code does not wait till the function returns a value, resulting in 
> the signcount variable in having a None value, giving an output like 
> below. 

I'll look at this a bit more closely later if nobody else
answers by then...

> Code:
> 
> #!/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

All of the above could be done as part of your GUI initialisation.
Its not needed in the event handler where it gets done every
time the function is called.

>      a=[" " for i in range(rows)]
>      i=0
>      sign=0
>      for line in packages:
>          signcount=getcount(line[1])

This is where you call your function. Looking at it quickly
I think you would be as well using the standard Tkinter
simpledialogs/messagebox modules to get user input.
Have you looked at the simpledialogs?

Or better still having a static entry field on your GUI
and just reading that?


>          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))

I suspect the problem is because you have three callbacks each
inside the other the second returns to your first before the
third has a chance to run. This is all compounded by your
dynamic GUI creation stuff.

You need to restructure the code.
More later.

> def ReturnCount():
>      global gc,e
>      b0=e.get()
>      if b0 == None:
>          b0=0
>      gc.destroy()
>      print('line 64 ###   The required number of signs is {} 
> ###'.format(b0))
>      return b0
> 
> 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()
-- 
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




More information about the Tutor mailing list