Найти - Пользователи
Полная версия: Обновление данных в treeview из БД
Начало » GUI » Обновление данных в treeview из БД
1 2 3 4 5
Feelgood
Помогите написать функцию обновления отображаемых данных в 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)
4kpt_V
Нее. Так не пойдет. Давайте конкретный вопрос.
Feelgood
Кликаю по кнопке “добавить позицию”, далее попадаю в дочернее окно. Ввожу необходимые данные, жму “ОК” окно закрывается, но при этом только что введённые данные не отображаются в treeview. Только после перезапуска приложения данные отображаются, соответственно необходима помощь в реализации фукции динамического добавления в treeview новых данных. Чтоб после нажатия кнопки “ОК” вновь введённые данные отобразились.
4kpt_V
Понял. Вам нужно выбрать из двух паттернов: обзервер или Описание их есть в книге М. Самерфилд. Питон на практике.

Если же делать просто, то нужно или перересовывать каждый раз дерево или используя его методы вставлять данные в нужные места.
4kpt_V
Фактически после нажатия на клавишу Вы должны вызвать обработчик (метод) внутри класса Main, который добавит данные в treeview.

Для того, чтобы передать он должен их связать.
Просмотрел код. Могу написать вызовы, но обработку напишите сами. Так годиться?
Feelgood
4kpt_V
Могу написать вызовы, но обработку напишите сами. Так годиться?
Да годится. Спасибо!
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
Огромное спасибо! Я новичёк, самоучка. Моя основная работа очень далека от программирования.
Буду благодарен, если укажите на мои ошибки и неудачные моменты.
4kpt_V
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()

Ну а так для первого раза очень и очень ничего.

P.S. За
 from tkinter import *
Бил бы по-рукам. Особенно в связке с ttk.
Feelgood
4kpt_V
Вы мне только что взорвали мозг) Спасибо! Сейчас я осознал значимость ментора. Прийдется много чего ещё изучить чтоб понять и исправить Ваши замечания.

self.slave.grab_set()
child перехватывает все события, происходящие в приложении.
self.slave.focus_set()
child захватывает фокус.
self.slave.wait_window()
child ждет, когда будет уничтожен текущий объект, не возобновляя работы .

Взято от сюда
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB