File: pymailgui-products/unzipped/PyMailGui-PP4E/popuputil.py

"""
#############################################################################
utility windows - may be useful in other programs
#############################################################################
"""

from tkinter import *
from PP4E.Gui.Tools.windows import PopupWindow


class HelpPopup(PopupWindow):
    """
    custom Toplevel that shows help text as scrolled text
    source button runs a passed-in callback handler
    3.0 alternative: use HTML file and webbrowser module
    """
    myfont = 'system'  # customizable
    mywidth = 78       # 3.0: start width

    def __init__(self, appname, helptext, iconfile=None, showsource=lambda:0):
        PopupWindow.__init__(self, appname, 'Help', iconfile)
        from tkinter.scrolledtext import ScrolledText    # a nonmodal dialog
        bar  = Frame(self)                               # pack first=clip last
        bar.pack(side=BOTTOM, fill=X)
        code = Button(bar, bg='beige', text="Source", command=showsource)
        quit = Button(bar, bg='beige', text="Cancel", command=self.destroy)
        code.pack(pady=1, side=LEFT)
        quit.pack(pady=1, side=LEFT)
        text = ScrolledText(self)                   # add Text + scrollbar
        text.config(font=self.myfont)
        text.config(width=self.mywidth)             # too big for showinfo
        text.config(bg='steelblue', fg='white')     # erase on btn or return
        text.insert('0.0', helptext)
        text.pack(expand=YES, fill=BOTH)
        self.bind("<Return>", (lambda event: self.destroy()))


def askPasswordWindow(appname, prompt, parent=None):
    """
    modal dialog to input password string     
    getpass.getpass uses stdin, not GUI
    tkSimpleDialog.askstring echoes input
    Dec2015: try to ensure window on-top+focus:
    not in rare cases, but unrelated issues?
    never used if password file configured;
    """
    win = PopupWindow(appname, 'Prompt')               # a configured Toplevel
    Label(win, text=prompt).pack(side=LEFT)
    entvar = StringVar(win)
    ent = Entry(win, textvariable=entvar, show='*')    # display * for input
    ent.pack(side=RIGHT, expand=YES, fill=X)
    ent.bind('<Return>', lambda event: win.destroy())

    if parent != None:
        # [4.0] post popup on parent (else very distant on Linux)
        parentupperleftcorner = (parent.winfo_rootx(), parent.winfo_rooty())
        win.geometry('+%d+%d' % parentupperleftcorner)

    if parent != None and sys.platform.startswith(('linux', 'darwin')):
        # [4.0] ensure window not covered on Linux and Mac OS X (Windows ok)
        win.wait_visibility()
        win.transient(parent)

    # [4.0] are there too many updates here?
    win.update()                                       # Dec2015: ensure on top?
    win.grab_set(); ent.focus_set(); win.wait_window() # Dec2015: try entry 2nd?
    win.update()                                       # update forces redraw
    return entvar.get()                                # ent widget is now gone


class BusyBoxWait(PopupWindow):
    """
    pop up blocking wait message box: thread waits
    main GUI event thread stays alive during wait
    but GUI is inoperable during this wait state;
    uses quit redef here because lower, not leftmost;
    """
    def __init__(self, appname, message, parent=None):
        PopupWindow.__init__(self, appname, 'Busy')
        self.protocol('WM_DELETE_WINDOW', lambda:0)        # ignore deletes
        label = Label(self, text=message + '...')          # win.quit() to erase
        label.config(height=10, width=40, cursor='watch')  # busy cursor
        label.pack()

        if parent != None:
            # [4.0] post popup on parent initially (else very distant on Linux)
            parentupperleftcorner = (parent.winfo_rootx(), parent.winfo_rooty())
            self.geometry('+%d+%d' % parentupperleftcorner)

        self.message, self.label = message, label
        self.makeModal(parent)

    def makeModal(self, parent):
        if parent != None and sys.platform.startswith(('linux', 'darwin')):
            # [4.0] ensure window not covered on Linux and Mac OS X (Windows ok)
            self.wait_visibility()
            self.transient(parent)

        self.focus_set()                                   # grab application
        self.grab_set()                                    # wait for threadexit

    def changeText(self, newtext):
        self.label.config(text=self.message + ': ' + newtext)

    def quit(self):
        self.destroy()                                     # don't verify quit


class BusyBoxNowait(BusyBoxWait):
    """
    pop up nonblocking wait window
    call changeText to show progress, quit to close
    """
    def makeModal(self, parent):
        pass


if __name__ == '__main__':
    HelpPopup('spam', 'See figure 1...\n')
    print(askPasswordWindow('spam', 'enter password'))
    input('Enter to exit')  # pause if clicked



[Home page] Books Code Blog Python Author Train Find ©M.Lutz