#!/usr/bin/python # -*- coding: utf-8 -*- # """ Nome: TkInterface.py Autor: Alessandro dos Santos Ferreira ( santosferreira.alessandro@gmail.com ) Descricão: Classe que implementa os modulos de interface utilizando a biblioteca TkInter. """ import sys if sys.version_info[0] < 3: import Tkinter as Tk else: import tkinter as Tk import tkMessageBox import matplotlib matplotlib.use('TkAgg') from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from matplotlib import pylab as plt from Interface import Interface, InterfaceException as IException from tk_interface import * class TkInterface(Interface): utils = TkUtils.TkUtils title = None __root = None __menus = None __configs = None __im = None __canvas = None __logger = None __dialog = None def __init__(self, title): self.title = title self.__root = Tk.Tk() self.__root.wm_title(self.title) self.__root.geometry('%dx%d+%d+%d' % (800, 600, 0, 0)) self.__menus = [] self.__configs = [] def set_subtitle(self, subtitle): self.__root.wm_title(self.title + ' - ' + subtitle) def add_menu(self, label): self.__menus.append( Menu.Menu(label) ) def add_command(self, label, action, shortcut = None): self.__menus[-1].add_command( label = label, action = lambda *_: self.__apply( action ), shortcut = shortcut ) def add_separator(self): self.__menus[-1].add_separator( ) def render_menu(self): menubar = Tk.Menu(self.__root) shortcuts = [] for menu in self.__menus: menubar = menu.render(menubar) shortcuts += menu.get_shorcuts() self.__root.config(menu=menubar) for sh in shortcuts: self.__root.bind("<Control-Key-" + sh["shortcut"] + ">", sh["action"]) self.__root.bind("<Control-Key-" + sh["shortcut"].lower() + ">", sh["action"]) def show(self): self.__root.protocol("WM_DELETE_WINDOW", self.quit) self.__root.mainloop() def add_image(self, image, title = None, onclick = None): if self.__canvas is None: self.__root.image = image fig = plt.figure(facecolor='white') self.__im = plt.imshow(self.__root.image) # later use a.set_data(new_data) #ax = plt.gca() #ax.set_xticklabels([]) #ax.set_yticklabels([]) # a tk.DrawingArea self.__canvas = FigureCanvasTkAgg(fig, master=self.__root) self.__canvas.show() self.__canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) if onclick is not None: fig.canvas.mpl_connect('button_press_event', func = lambda event, *_: self.__apply( onclick, event )) if title is not None: self.set_subtitle(title) else: self.refresh_image(image, title) def refresh_image(self, image, title = 'None'): if self.__canvas is not None: self.__root.image = image self.__im.set_data(self.__root.image) self.__canvas.draw() def close_image(self): if self.__canvas is not None: if tkMessageBox.askokcancel("Quit", "Do you want to close the image?"): self.__root.image = None #self.__im.set_data(np.zeros((0,0,3), float)) #self.__canvas.draw() self.__canvas.get_tk_widget().pack_forget(); self.__canvas.get_tk_widget().destroy(); self.__im = None self.__canvas = None return True return False def create_logger(self): self.__logger = Tk.Text(self.__root, width=0, height=10, bg="white", fg="black", padx=5, pady=5) self.__logger.insert(Tk.INSERT, "$ Pynovisao is ready!\n") self.__logger.config(state=Tk.DISABLED) self.__logger.pack(side=Tk.BOTTOM, fill=Tk.X, expand=False) def write_logger(self, fmt, *args): self.clean_logger() self.append_logger(fmt % args) def append_logger(self, fmt, *args): self.__logger.config(state=Tk.NORMAL) self.__logger.insert(Tk.END, fmt % args) self.__logger.insert(Tk.END, '\n') self.__logger.config(state=Tk.DISABLED) def clean_logger(self): self.__logger.config(state=Tk.NORMAL) self.__logger.delete('1.0', Tk.END) self.__logger.insert('1.0', '$ ') self.__logger.config(state=Tk.DISABLED) def destroy_logger(self): self.__logger.pack_forget(); self.__logger.destroy(); def popup(self): pass def log_and_popup(self, message): pass def show_error(self, fmt, *args): tkMessageBox.showerror("Error", fmt % args) def show_info(self, fmt, *args): tkMessageBox.showinfo("Info", fmt % args) def show_warning(self, fmt, *args): tkMessageBox.showwarning("Warning", fmt % args) def dialogue_config(self, title, configs, callback): n_configs = len(configs) self.__dialog = Tk.Toplevel(self.__root, padx=10, pady=10) self.__dialog.title(title) row = 0 self.__configs = [] for config in configs: Tk.Label(self.__dialog, text=config.title()).grid(row=row, padx=4, pady=4, sticky=Tk.W) entry = Tk.Entry(self.__dialog) entry.insert(0, str(configs[config].value)) entry.grid(row=row, column=1, padx=4, pady=4, sticky=Tk.W) if row == 0: entry.focus_set() self.__configs.append( TkConfig.TkConfig(config, configs[config].value, c_type=configs[config].c_type, tk_entry=entry) ) row += 1 B1 = Tk.Button(self.__dialog, text="Ok", width=5, command = lambda *_: self.__apply( callback )) B1.grid(row=row, padx=6, pady=6, sticky=Tk.W) self.__dialog.bind("<Return>", lambda *_: self.__apply( callback )) B2 = Tk.Button(self.__dialog, text="Cancel", width=5, command = self.__dialog.destroy) B2.grid(row=row, column=1, padx=6, pady=6, sticky=Tk.W) self.__dialog.bind("<Escape>", lambda *_: self.__dialog.destroy()) self.__dialog.grab_set() self.__dialog.protocol("WM_DELETE_WINDOW", self.__dialog.destroy) self.__dialog.geometry("+%d+%d" % (self.__root.winfo_width()/3, self.__root.winfo_height()/3)) def get_config_and_destroy(self): try: configs = {} for config in self.__configs: config.value = config.get_entry_val() configs[config.label] = config except: self.__dialog.destroy() raise IException("Illegal values, please try again") self.__dialog.destroy() return configs def quit(self): if tkMessageBox.askokcancel("Quit", "Do you want to quit?"): self.__root.quit() self.__root.destroy() def debug(self, event): print("DEBUG") def __apply(self, f, *args): try: f(*args) except IException as exc: self.__log_exception( str(exc), True ) except: self.__log_exception( IException.format_exception() ) def __log_exception(self, message, warning = False): if warning == True: self.show_warning( message ) elif IException.DEBUG == True: self.append_logger( message ) else: self.show_error( message )