Форум сайта python.su
Помогите написать функцию обновления отображаемых данных в treeview, из БД, после добавления в неё новых данных.
from tkinter import * from tkinter import ttk import sqlite3 conn = sqlite3.connect('finance.db') c = conn.cursor() c.execute( '''CREATE TABLE IF NOT EXISTS finance (id integer primary key, description text, costs text, total real, date current_timestamp)''') c.execute('''select * from finance''') class Main: def __init__(self, master): self.master = master self.master.title('Домашние финансы') self.master.geometry('650x450+300+200') self.master.resizable(False, False) toolbar = Frame(master) toolbar.pack(side=TOP, fill=X) toolbar.config(bg='#d7d8e0', bd=2) self.add_img = PhotoImage(file="add.gif") self.btnOpenDialog = Button(toolbar, text='Добавить позицию', command=self.openDialog, image=self.add_img) self.btnOpenDialog.pack(side=LEFT) self.btnOpenDialog.config(bg='#d7d8e0', bd=0, compound=TOP) self.tree = ttk.Treeview(self.master, columns=('ID', 'description', 'costs', 'total', 'date'), height=15, show='headings') self.tree.column("ID", width=30, anchor=CENTER) self.tree.column("description", width=250, anchor=CENTER) self.tree.column("costs", width=150, anchor=CENTER) self.tree.column("total", width=100, anchor=CENTER) self.tree.column("date", width=100, anchor=CENTER) self.tree.heading("ID", text='ID') self.tree.heading("description", text='Наименование') self.tree.heading("costs", text='Статья дохода/расхода') self.tree.heading("total", text='Сумма') self.tree.heading("date", text='Дата') for row in c.fetchall(): self.tree.insert('', 'end', values=row) self.tree.yview() self.tree.pack(side=TOP, fill=X) self.master.mainloop() def openDialog(self): Child(self.master) class Child: def __init__(self, master): self.slave = Toplevel(master) self.slave.title('Добавить доходы/расходы') self.slave.geometry('400x220+400+300') self.slave.resizable(False, False) self.labelDescription = Label(self.slave, text='Наименование:') self.labelDescription.place(x=50, y=50) self.labelSelect = Label(self.slave, text='Статья дохода/расхода:') self.labelSelect.place(x=50, y=80) self.labelSum = Label(self.slave, text='Сумма:') self.labelSum.place(x=50, y=110) self.entryDescription = ttk.Entry(self.slave) self.entryDescription.place(x=200, y=50) self.entryMoney = ttk.Entry(self.slave) self.entryMoney.place(x=200, y=110) self.combobox = ttk.Combobox(self.slave, values=[u"Доход", u"Расход"]) self.combobox.current(0) self.combobox.place(x=200, y=80) self.btnCancel = ttk.Button(self.slave, text='Отмена', command=self.slave.destroy) self.btnCancel.place(x=300, y=170) self.btnOk = ttk.Button(self.slave, text='OK') self.btnOk.place(x=220, y=170) self.btnOk.bind('<Button-1>', lambda event: self.insertData(str(self.entryDescription.get()), str(self.combobox.get()), float(self.entryMoney.get()))) self.slave.grab_set() self.slave.focus_set() self.slave.wait_window() def insertData(self, description, costs, total): c.execute('''INSERT INTO finance(description, costs, sum) VALUES (?, ?, ?)''', (description, costs, total)) conn.commit() '''conn.close()''' self.slave.destroy() root = Tk() Main(root)
Прикреплённый файлы:
test.zip (2,1 KБ)
Офлайн
Нее. Так не пойдет. Давайте конкретный вопрос.
Офлайн
Кликаю по кнопке “добавить позицию”, далее попадаю в дочернее окно. Ввожу необходимые данные, жму “ОК” окно закрывается, но при этом только что введённые данные не отображаются в treeview. Только после перезапуска приложения данные отображаются, соответственно необходима помощь в реализации фукции динамического добавления в treeview новых данных. Чтоб после нажатия кнопки “ОК” вновь введённые данные отобразились.
Офлайн
Понял. Вам нужно выбрать из двух паттернов: обзервер или Описание их есть в книге М. Самерфилд. Питон на практике.
Если же делать просто, то нужно или перересовывать каждый раз дерево или используя его методы вставлять данные в нужные места.
Офлайн
Фактически после нажатия на клавишу Вы должны вызвать обработчик (метод) внутри класса Main, который добавит данные в treeview.
Для того, чтобы передать он должен их связать.
Просмотрел код. Могу написать вызовы, но обработку напишите сами. Так годиться?
Отредактировано 4kpt_V (Март 14, 2017 22:20:45)
Офлайн
4kpt_VДа годится. Спасибо!
Могу написать вызовы, но обработку напишите сами. Так годиться?
Офлайн
Держите.
Но много неудачных моментов по ООП для tkinter. Но начало положено, а это гуд.
# from tkinter import * from tkinter import ttk import sqlite3 conn = sqlite3.connect('finance.db') c = conn.cursor() c.execute("""CREATE TABLE IF NOT EXISTS finance (id integer primary key, description text, costs text, total real, date current_timestamp)""") c.execute('''select * from finance''') class Main: def __init__(self, master): self.master = master self.master.title('Домашние финансы') self.master.geometry('650x450+300+200') self.master.resizable(False, False) toolbar = Frame(master) toolbar.pack(side=TOP, fill=X) toolbar.config(bg='#d7d8e0', bd=2) self.add_img = PhotoImage(file="add.gif") self.btnOpenDialog = Button(toolbar, text='Добавить позицию', command=self.openDialog, image=self.add_img) self.btnOpenDialog.pack(side=LEFT) self.btnOpenDialog.config(bg='#d7d8e0', bd=0, compound=TOP) self.tree = ttk.Treeview(self.master, columns=('ID', 'description', 'costs', 'total', 'date'), height=15, show='headings') self.tree.column("ID", width=30, anchor=CENTER) self.tree.column("description", width=250, anchor=CENTER) self.tree.column("costs", width=150, anchor=CENTER) self.tree.column("total", width=100, anchor=CENTER) self.tree.column("date", width=100, anchor=CENTER) self.tree.heading("ID", text='ID') self.tree.heading("description", text='Наименование') self.tree.heading("costs", text='Статья дохода/расхода') self.tree.heading("total", text='Сумма') self.tree.heading("date", text='Дата') for row in c.fetchall(): self.tree.insert('', 'end', values=row) self.tree.yview() self.tree.pack(side=TOP, fill=X) self.master.mainloop() def add_data(self, data): """""" print(data) # insert here self.tree.insert("") def open_dialog(self): """""" # inject main to child Child(self.master, main=self) class Child: def __init__(self, master, main): self.main = main self.slave = Toplevel(master) self.slave.title('Добавить доходы/расходы') self.slave.geometry('400x220+400+300') self.slave.resizable(False, False) self.labelDescription = Label(self.slave, text='Наименование:') self.labelDescription.place(x=50, y=50) self.labelSelect = Label(self.slave, text='Статья дохода/расхода:') self.labelSelect.place(x=50, y=80) self.labelSum = Label(self.slave, text='Сумма:') self.labelSum.place(x=50, y=110) self.entryDescription = ttk.Entry(self.slave) self.entryDescription.place(x=200, y=50) self.entryMoney = ttk.Entry(self.slave) self.entryMoney.place(x=200, y=110) self.combobox = ttk.Combobox(self.slave, values=[u"Доход", u"Расход"]) self.combobox.current(0) self.combobox.place(x=200, y=80) self.btnCancel = ttk.Button(self.slave, text='Отмена', command=self.slave.destroy) self.btnCancel.place(x=300, y=170) self.btnOk = ttk.Button(self.slave, text='OK') self.btnOk.place(x=220, y=170) self.btnOk.bind('<Button-1>', lambda event: self.insertData(str(self.entryDescription.get()), str(self.combobox.get()), float(self.entryMoney.get()))) self.slave.grab_set() self.slave.focus_set() self.slave.wait_window() def insert_data(self, description, costs, total): c.execute('''INSERT INTO finance(description, costs, sum) VALUES (?, ?, ?)''', (description, costs, total)) conn.commit() '''conn.close()''' # call main.add_data self.main.add_data((description, costs, total)) self.slave.destroy() root = Tk() Main(root)
Офлайн
Огромное спасибо! Я новичёк, самоучка. Моя основная работа очень далека от программирования.
Буду благодарен, если укажите на мои ошибки и неудачные моменты.
Офлайн
Feelgood
1. Наследоваться желательно от чего-то, тогда можно будет этот виджет размещаться как элемент (как кнопку, например). Рекомендую рамку. Она, если надо, сама себе создаст root, если забыли передать (передали None).
2. Для toplevel не надо master. Это не обязательно.
3. Все вижеты класса, которые не нужны в обращения в метода не надо делать атрибутами класса (self где нужно и где нет).
4. При передаче в обработчик зря сразу конвертируете в типы. Пусть обработчик сам на себя возьмет эти задачи. Ну и зачем передавать их явно. Вы же уже их сделали атрибутами объекта (self.entryDescription и т.п.).
5. CamalCase в питоне нужен в определенных местах. PEP8 все же придется почитать. Докстринги тоже никто не отменял.
6. Не принято создание писать в __init__. Лучше завести какой-то метод-инициатор.
7. Зачем эта часть кода, можете пояснить?
# self.slave.grab_set() self.slave.focus_set() self.slave.wait_window()
from tkinter import *
Отредактировано 4kpt_V (Март 15, 2017 19:45:24)
Офлайн
4kpt_V
Вы мне только что взорвали мозг) Спасибо! Сейчас я осознал значимость ментора. Прийдется много чего ещё изучить чтоб понять и исправить Ваши замечания.
self.slave.grab_set()
child перехватывает все события, происходящие в приложении.
self.slave.focus_set()
child захватывает фокус.
self.slave.wait_window()
child ждет, когда будет уничтожен текущий объект, не возобновляя работы .
Офлайн