Re: [Tutor] tkinter code executes before function returned

2018-04-16 Thread Chris Roy-Smith

On 15/04/18 18:10, Alan Gauld via Tutor wrote:

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

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?
Thank you Alan, I didn't know of simpledialogs. That was all I needed to 
search documentation for these. I have


now achieved what I was trying to do, with user interface as I was planning.



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


I'll have to figure out how to achieve that!

Perhaps my intended design is not in line with modern styles?


Regards, Chris Roy-Smith

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] tkinter code executes before function returned

2018-04-15 Thread Mats Wichmann
On 04/15/2018 03:13 PM, Chris Roy-Smith wrote:
> On 15/04/18 23:36, Alan Gauld via Tutor wrote:
>> On 15/04/18 14:24, Alan Gauld via Tutor wrote:
>>
>>> OK, I've had a closet look now and can confirm the
>> A closer look! Not a closet look. Ooops! :-/
>>
>>
> Thank you Alan, I have even more to learn than I thought. I have been
> bashing away at several OOP tutorials, but the penny still hasn't
> dropped on making that work yet, I get the concept, but don't seem to
> understand how to make it work for methods. Events just add to my lack
> of understanding. I'll have to try your tutorial. Hopefully I won't have
> too many questions after that.

By all means work through a tutorial that appeals to you!

If there are OOP examples that aren't working for you, the people at
this list can help: just like you did with the tkinter example, if you
post the code, people have something to explain against. There are
plenty of "lectures" on the Internet, we don't need to reproduce that
role :)

Object-oriented features help make Python more powerful, but you don't
have to use them unless they help solve the problem at hand, unlike
languages like C# and Java, where everything is object-oriented by design.

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] tkinter code executes before function returned

2018-04-15 Thread Chris Roy-Smith

On 15/04/18 23:36, Alan Gauld via Tutor wrote:

On 15/04/18 14:24, Alan Gauld via Tutor wrote:


OK, I've had a closet look now and can confirm the

A closer look! Not a closet look. Ooops! :-/


Thank you Alan, I have even more to learn than I thought. I have been 
bashing away at several OOP tutorials, but the penny still hasn't 
dropped on making that work yet, I get the concept, but don't seem to 
understand how to make it work for methods. Events just add to my lack 
of understanding. I'll have to try your tutorial. Hopefully I won't have 
too many questions after that.


Regards, Chris Roy-Smith

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] tkinter code executes before function returned

2018-04-15 Thread Alan Gauld via Tutor
On 15/04/18 14:24, Alan Gauld via Tutor wrote:

> OK, I've had a closet look now and can confirm the

A closer look! Not a closet look. Ooops! :-/


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


Re: [Tutor] tkinter code executes before function returned

2018-04-15 Thread Alan Gauld via Tutor
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, 

Re: [Tutor] tkinter code executes before function returned

2018-04-15 Thread Alan Gauld via Tutor
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


___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor