Hola, soy nuevo en Python pero me defiendo. He relizado un proyecto, pero quiero hacerlo con una estructura MVC (Modelo, Vista, Controlador). El tema es que quiero sacar un TreeView donde mostrar datos y cuando pulsen en una fila(row) realizar tareas, pero me casca el programa cuando hago click en una cualquier fila y da el siguiente error:
AttributeError: 'Controlador' object has no attribute 'master'
He quitado del proyecto todo y he dejado solo lo que nos interesa, los 3 archivos(clases) Modelo.py, Vista.py y Controlador.py y el TreeView en Vista.
También os dejo un archivo test con un TreeView donde sí que medio funciona.
El tema es recuperar la fila, o el indice de la fila. En cualquier caso un dato de la fila que permita saber cual ha sido seleccionada.
Os paso también todo en .zip
Saludos y Gracias de antemano.
Enrique
AttributeError: 'Controlador' object has no attribute 'master'
He quitado del proyecto todo y he dejado solo lo que nos interesa, los 3 archivos(clases) Modelo.py, Vista.py y Controlador.py y el TreeView en Vista.
También os dejo un archivo test con un TreeView donde sí que medio funciona.
El tema es recuperar la fila, o el indice de la fila. En cualquier caso un dato de la fila que permita saber cual ha sido seleccionada.
Os paso también todo en .zip
Saludos y Gracias de antemano.
Enrique
Código:
# MODELO (modelo.py)
class Modelo:
datos = [1, 'ES', 'España', 34,
2, 'FR', 'Francia', 33,
3, 'GR', 'Alemania', 49,
4, 'IT', 'Italia', 39,
5, 'GB', 'Reino Unido', 44]
def __init__(self):
self.datos.append(5)
self.datos.append('PT')
self.datos.append('Portugal')
self.datos.append(351)
def set_datos(self, dato, i):
self.datos[i] = dato[i]
def get_datos(self, i):
return self.datos[i]
Código:
# CONTROLADOR (controlador.py)
##############################################################
# APLICACION PYTHON 3 #
# Pograma principal #
##############################################################
import sys
from modelo import Modelo
from vista import Vista
class Controlador:
def __init__(self):
self.modelo = Modelo()
self.vista = Vista(self)
def update_treeview_paises(self):
for i in range(6):
print(i)
self.vista.treeview_paises.insert('', 'end', text=str(self.modelo.get_datos((i*4)+0)),
values=(self.modelo.get_datos((i*4)+1),
self.modelo.get_datos((i*4)+2),
self.modelo.get_datos((i*4)+3)),
tags=("item",))
def main(self):
self.update_treeview_paises()
self.vista.main()
def salir(self):
sys.exit(0)
if __name__ == '__main__':
controlador = Controlador()
controlador.main()
Código:
# VISTA (vista.py)
import os
import sys
import tkinter as tk
import tkinter.ttk as ttk
from tkinter import scrolledtext, NSEW, W
from typing import re
class Vista(tk.Tk):
PAD = 5
def __init__(self, master):
super().__init__()
self.master = master
self.title("Menú Principal")
self.config(bg='lightgrey', borderwidth=1)
# Frame Principal
self.frm_main = ttk.Frame(self, relief='ridge')
self.frm_main.pack(padx=self.PAD, pady=self.PAD, fill="both", expand='yes')
sw = self.winfo_screenwidth()
sh = self.winfo_screenheight()
w = sw * 0.7
h = sh * 0.7
x = (sw - w) / 2
y = (sh - h) / 2
self.geometry("%dx%d+%d+%d" % (w, h, x, y))
self.state('zoomed') # Maximizada
# Dibujamos la Barra de Menú
self.menubar = tk.Menu(self)
self.config(menu=self.menubar, bg="lightgrey", highlightcolor="white", highlightthickness="1")
self.filemenu = tk.Menu(self.menubar, tearoff=0)
self.filemenu.add_command(label="Nuevo")
self.filemenu.add_command(label="Abrir")
self.filemenu.add_command(label="Bandeja")
self.filemenu.add_separator()
self.filemenu.add_command(label="Salir", command=self.salir)
self.editmenu = tk.Menu(self.menubar, tearoff=0)
self.editmenu.add_command(label="Cortar")
self.editmenu.add_command(label="Copiar")
self.editmenu.add_command(label="Pegar")
self.datosmenu = tk.Menu(self.menubar, tearoff=0)
self.subdatos = tk.Menu(self.datosmenu, tearoff=0)
self.subdatos.add_command(label="Datos")
self.datosmenu.add_cascade(label='Recoger Datos',underline=0)
self.helpmenu = tk.Menu(self.menubar, tearoff=0)
self.helpmenu.add_command(label="Ayuda")
self.helpmenu.add_separator()
self.helpmenu.add_command(label="Acerca de...")
self.menubar.add_cascade(label="Archivo", menu=self.filemenu)
self.menubar.add_cascade(label="Editar", menu=self.editmenu)
self.menubar.add_cascade(label="Datos", menu=self.datosmenu)
self.menubar.add_cascade(label="Ayuda", menu=self.helpmenu)
# Titulo
self.lbl_tit = tk.Label(self.frm_main, fg='black', bg='lightgrey', text="Main Menu")
self.lbl_tit.pack()
# Frame de arriba
self.frm_up = ttk.Frame(self.frm_main)
self.frm_up.pack(fill='x', padx=self.PAD, pady=self.PAD)
# Database
self.frm_dat = tk.LabelFrame(self.frm_up, text="Database")
self.frm_dat.pack(side='right')
self.lbl_dat = tk.Label(self.frm_dat, text='')
self.lbl_dat.pack()
# Frame de arriba y central
self.frm_upc = ttk.Frame(self.frm_up)
self.frm_upc.pack(anchor='center', padx=self.PAD, pady=self.PAD)
# IA
self.frm_ia = tk.LabelFrame(self.frm_upc, text="Inteligencia
Artificial")
self.frm_ia.pack(side='left')
self.lbl_ia = tk.Label(self.frm_ia, fg='red', text="OFF")
self.lbl_ia.pack()
# Frame Cuadro Datos
self.frm_cpa = ttk.Frame(self.frm_main)
self.frm_cpa.pack(fill='x', padx=self.PAD, pady=self.PAD)
# TREEVIEW PAISES
self.frm_cpf = tk.LabelFrame(self.frm_cpa, text="Paises")
self.frm_cpf.pack(fill='x', expand='yes', side='left')
estilo = ttk.Style()
estilo.configure("Treeview", highlightthickness=0, bd=0, font=('Calibri', 10))
estilo.configure("Treeview.Heading", font=('Calibri', 10, 'bold'), foreground='#3790D5')
self.treeview_paises = ttk.Treeview(self.frm_cpf, style="Treeview", columns=('Nº', 'ISO', 'País', 'Codigo'))
self.treeview_paises.heading('#0', text='Nº')
self.treeview_paises.heading('#1', text='ISO')
self.treeview_paises.heading('#2', text='País')
self.treeview_paises.heading('#3', text='Código')
self.treeview_paises.column('#0', minwidth=80, width=80, stretch=True, anchor="c")
self.treeview_paises.column('#1', minwidth=80, width=80, stretch=True, anchor="c")
self.treeview_paises.column('#2', minwidth=80, width=80, stretch=True, anchor="c")
self.treeview_paises.column('#3', minwidth=100, width=100, stretch=True, anchor="c")
self.treeview_paises.tag_bind("item", '<<TreeviewSelect>>', self.selecciono_carrera)
self.treeview_paises.tag_bind('item', "<Double-Button-1>", self.selecciono_carrera)
self.treeview_paises.grid(row=0, column=0, sticky=NSEW)
vsb_a = ttk.Scrollbar(self.frm_cpf, orient="vertical", command=self.treeview_paises.yview)
vsb_a.grid(row=0, column=1, sticky=NSEW)
hsb_a = ttk.Scrollbar(self.frm_cpf, orient="horizontal", command=self.treeview_paises.xview)
hsb_a.grid(row=1, column=0, sticky=NSEW)
self.treeview_paises.configure(xscrollcommand=hsb_a.set, yscrollcommand=vsb_a.set)
# Boton x de cerrar ventana la oculta
self.protocol("WM_DELETE_WINDOW", self.on_closing)
def main(self):
self.mainloop()
def salir(self):
self.master.salir()
self.destroy()
os._exit(0)
sys.exit(0)
def on_closing(self):
self.withdraw()
def selecciono_carrera(self, event):
print('Seleccionada Carrera')
#item = self.treeview_paises.identify('item', event.x, event.y)
#print("you clicked on", self.treeview_paises.item(item, "text"))
def filter(self, tree, col, descending):
print ('Row: {} & Column: {} '.format(
re.sub('I00', '', str(tree.identify_row(tree.winfo_pointerxy()[1] - tree.winfo_rooty()))),
re.sub(r'#', '', str(tree.identify_column(tree.winfo_pointerxy()[0] - tree.winfo_rootx())))))
Código:
# TEST (test.py)
import tkinter as tk
from tkinter import ttk
class Application(ttk.Frame):
def __init__(self, main_window):
super().__init__(main_window)
main_window.title("Vista de árbol en Tkinter")
self.treeview = ttk.Treeview(self)
# Crear una nueva etiqueta.
self.treeview.tag_bind("mytag", "<<TreeviewSelect>>", self.item_selected)
self.treeview.tag_bind("mytag", "<<TreeviewOpen>>",
self.item_opened)
self.treeview.tag_bind("mytag", "<<TreeviewClose>>",
self.item_closed)
# Añadir dos elementos indicando la etiqueta anterior para
# que respondan a los eventos.
item = self.treeview.insert("", tk.END, text="Elemento 1", tags=("mytag",))
item = self.treeview.insert("", tk.END, text="Elemento 2", tags=("mytag",))
self.treeview.insert(item, tk.END, text="Subelemento 1", tags=("mytag",))
self.treeview.pack()
self.pack()
def item_selected(self, event):
"""Item seleccionado."""
print("Seleccionado.")
#item = self.treeview.identify('mytag', event.x, event.y)
#print("you clicked on", self.treeview.item(item, "mytag"))
def item_opened(self, event):
"""Item abierto."""
print("Abierto.")
def item_closed(self, event):
"""Item cerrado."""
print("Cerrado.")
main_window = tk.Tk()
app = Application(main_window)
app.mainloop()