# -*- coding: utf-8 -*-
"""
building windows to use a function and specify its parameter based on a python function
:githublink:`%|py|7`
"""
import os
import warnings
import tkinter
import tkinter.tix as ttix # pylint: disable=W0402
from tkinter import TclError
from .tk_window import create_tixtk
from .frame_function import FrameFunction
from .storing_functions import get_icon
[docs]class MainFrame(tkinter.Frame):
"""
Creates a Frame window to select within a list of functions,
:class:`FrameFunction <tkinterquickhelper.funcwin.frame_function.FrameFunction>`.
The class requires to run ``tix.Tk()`` and not ``tkinter.Tk()``.
Otherwise, you will see the following error:
::
_tkinter.TclError: invalid command name "tixComboBox"
It is required by the use of ``ComboBox``.
:func:`main_loop_functions <tkinterquickhelper.funcwin.main_window.main_loop_functions>` to see what the window will look like.
:githublink:`%|py|31`
"""
[docs] def __init__(self, parent, functions, first=None, restore=True, width=100,
raise_exception=False, overwrite=None, hide=False):
"""
:param parent: window parent
:param functions: dictionary with a list of functions { name: function }
:param first: first function to select
:param restore: if True, check if existing saved parameters are present
:param width: number of characters in every Entry field
:param raise_exception: raise an exception instead of catching it
:param overwrite: parameters to overwrite
:param hide: if True, hide the window after clicking on OK
:githublink:`%|py|44`
"""
if overwrite is None:
overwrite = {}
tkinter.Frame.__init__(self, parent)
self.kparent = parent
self.fsel = tkinter.Frame(self)
self.ffun = tkinter.Frame(self)
hline = tkinter.Frame(self, height=10, width=800, bg="blue")
self.fsel.pack()
hline.pack()
self.ffun.pack()
self.parent = parent
self.varcombo = ttix.StringVar()
self.combo = ttix.ComboBox(self.fsel, editable=1, dropdown=1, variable=self.varcombo,
command=self.change_selection,
options="listbox.height %d label.width %d entry.width %d" % (25, 30, 50))
# put the text zone in read only mode
self.combo.entry.config(state='readonly')
for i, k in enumerate(sorted(functions)):
self.combo.insert(i, k)
self.combo.pack()
self.functionsDict = functions
if first is None:
keys = sorted(functions.keys())
first = keys[0]
firstFunction = functions[first]
self.params = {"restore": restore, "width": width,
"raise_exception": raise_exception,
"overwrite": overwrite, "hide": hide}
self.varcombo.set(first)
self.change_frame_function(firstFunction)
[docs] def run_cancel(self, *args):
"""
cancel
:githublink:`%|py|83`
"""
try:
self.kparent.destroy()
except Exception as e:
if "application has been destroyed" in str(e):
return
else:
raise e
if "selected" in self.__dict__ and "server" in self.selected.__name__:
# trick: the server does not close itself
# forcing to close
# sys.exit() can only be used from the main thread
os._exit(0)
[docs] def get_title(self):
"""
Returns the default title.
:return: string
:githublink:`%|py|102`
"""
return self.frameWindow.get_title()
[docs] def change_frame_function(self, function):
"""
Updates the frame :class:`FrameFunction <tkinterquickhelper.funcwin.frame_function.FrameFunction>` to select a new function.
:param function: a function (a pointer)
:githublink:`%|py|110`
"""
if "selected" not in self.__dict__ or function != self.selected:
self.selected = function
if hasattr(self, "frameWindow"):
self.frameWindow.pack_forget()
self.frameWindow = FrameFunction(self.ffun, function,
restore=self.params["restore"],
width=self.params["width"],
raise_exception=self.params[
"raise_exception"],
overwrite=self.params["overwrite"],
hide=self.params["hide"],
command_leave=self.run_cancel)
self.frameWindow.pack()
self.frameWindow.focus_set()
[docs] def change_selection(self, event):
"""
Functions called when the selection changes.
:githublink:`%|py|131`
"""
st = self.varcombo.get()
if "functionsDict" in self.__dict__:
self.change_frame_function(self.functionsDict[st])
[docs]def main_loop_functions(functions, first=None, restore=True, width=100,
raise_exception=False, overwrite=None, hide=False, title=None,
ico=None, init_pos=None, mainloop=True):
"""
Uses :class:`MainFrame <tkinterquickhelper.funcwin.main_window.MainFrame>` as the main window.
:param functions: dictionary with a list of functions { name: function }
:param first: first function to select
:param restore: if True, check if existing saved parameters are present
:param width: number of characters in every Entry field
:param raise_exception: raise an exception instead of catching it
:param overwrite: parameters to overwrite
:param hide: if True, hide the window after clicking on OK
:param title: if not None, overwrite the default title
:param ico: (str) an icon or None
:param init_pos: location of the window *(x,y)* or None
:param mainloop: run the mainloop
:return: main window
.. exref::
:title: Open a window to run a function from a predefined list of functions
::
functions = {"test_regular_expression":test_regular_expression,
"test_edit_distance":file_grep,
"file_head":file_head }
main_loop_functions(functions, title="title: TestMakeWindow2")
.. image:: ../../images/open_functionl.png
:align: center
:githublink:`%|py|167`
"""
if overwrite is None:
overwrite = {}
ico = get_icon() if ico is None else ico
root = create_tixtk()
try:
root.iconbitmap(ico)
except TclError:
warnings.warn("Unable to load icon '{0}'".format(ico))
fr = MainFrame(parent=root, functions=functions, first=first, restore=restore,
width=width, raise_exception=raise_exception, overwrite=overwrite,
hide=hide)
fr.pack()
root.title(fr.get_title() if title is None else title)
if init_pos is not None:
root.geometry('+%d+%d' % init_pos)
if mainloop:
fr.mainloop()
return fr