Я потратил несколько дней на то, что я думал, будет простой задачей. Я создаю графическое приложение для просмотра загруженных данных, содержащих данные баланса, переданные в FDIC.
LabelFrame, содержащий холст, называется self.results, а сам холст является экземпляром класса GridResult с именем tvr, у которого есть подкласс tk.Canvas. Полоса прокрутки появляется и прокручивается, но она не перемещает вид при прокрутке (см., Например, изображения). Это отнимает слишком много времени, и я клянусь своей жизнью, что я сделаю venmo / cashapp / ethereum первым человеком, который исправит эти 10 долларов, огромную сумму, но я в своем уме.
# canvas will contain GridResults object bound to date selector
self.results = tk.LabelFrame(self, text='Search Results', width=250, height=250, font=REG_FONT)
self.results.pack_propagate(False)
# initialize data table with parent self.results
self.results.tvr = GridResult(self.results)
Полоса прокруткисоздается и упаковывается в функцию init класса GridResult. Класс GridResult содержит древовидные представления, которые привязаны к датам, выбранным для каждого из банковских идентификаторов, введенных в поле поиска. Я настраиваю полосу прокрутки и ее подключение к холсту в функции сборки класса GridResult. Я также планирую добавить вертикальную полосу прокрутки для диаграмм, подключенных к древовидным представлениям, определенным классом ChartResult, который отображается на холсте GridResult, но мы можем пока игнорировать ChartResults
self.sb.config(command=self.xview)
self.config(xscrollcommand=self.sb.set)
self.config(scrollregion=(0,0,5000,500))
self.place(anchor='nw')
Прежде чем переместить полосу прокрутки
Перемещение полосы прокрутки (ничего не происходит)
Полный код приложения:
import tkinter as tk
from tkinter import ttk
import sqlite3
import re
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
conn = sqlite3.connect('BHC.db')
cur = conn.cursor()
LARGE_FONT = ('Verdana', 20)
REG_FONT = ('Verdana', 12)
# 746223,3317192,564856,419255,350657,148470,3048487
# 746223,3317192
# MainApp is top level, all other widgets are children
class MainApp(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
x = PageOne(self)
x.pack(side="top", fill="both", expand=True)
# Page one
class PageOne(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
# random data to initialize some elements
self.srch = "746223,3317192"
self.date = []
self.data = ['1']
self.names = ['A']
# page title
title = tk.Label(self, text='Bank Holding Company Database', font=LARGE_FONT)
# RSSD ID entry widget contained in LabelFrame widget
entry = tk.LabelFrame(self, text='Enter comma separated RSSD Ids', font=REG_FONT, width=300)
self.e = tk.Entry(entry)
# search button triggers callback
search_button = ttk.Button(entry, text="Search", command=self.callback)
self.e.pack(pady=10, padx=10)
search_button.pack(pady=10, padx=10)
# date selector treeview in LabelFrame widget
self.dateselector = tk.LabelFrame(self, text='Select Filling Dates')
self.dateselector.tv = ttk.Treeview(self.dateselector, columns='Dates', show='headings', height=10)
self.dateselector.tv.heading(0, text="Date Selection")
self.dateselector.tv.pack(pady=10, padx=10)
# canvas will contain GridResults object bound to date selector
self.results = tk.LabelFrame(self, text='Search Results', width=250, height=250, font=REG_FONT)
self.results.pack_propagate(False)
# initialize data table with parent self.results
self.results.tvr = GridResult(self.results)
# pack widgets to PageOne Frame
title.grid(row=0, column=0, columnspan=2)
entry.grid(row=1, column=0)
self.dateselector.grid(row=2, column=0)
self.results.grid(row=2, column=1)
def callback(self):
# bind date tree to self.callback2
print('tv')
print(self.dateselector.tv)
self.dateselector.tv.heading(0, text="Date Selection")
self.dateselector.tv.bind('<<TreeviewSelect>>', self.callback2)
# fix query string format
self.srch = list(re.split(',', self.e.get()))
# using this query for metadata, could be lighter
cur.execute("SELECT * FROM BankData WHERE Fed_Rssd IN {}".format(
str(self.srch).replace('[', '(').replace(']', ')')
))
# get attribute names
self.names = [cur.description[x][0] for x in range(len(cur.description))]
# get dates to populate date tree
cur.execute("SELECT DISTINCT repdte FROM BankData WHERE Fed_Rssd IN {}".format(
str(self.srch).replace('[', '(').replace(']', ')')
))
uni = cur.fetchall()
# loop populates dates
for x in range(len(uni)):
self.dateselector.tv.insert('', 'end', values=uni[x])
self.dateselector.tv.pack(pady=10, padx=10)
# handle changing date selection
def callback2(self, event):
# get active date selection
self.date = []
self.date = [self.dateselector.tv.item(x)['values'][0] for x in self.dateselector.tv.selection()]
# get bank data for selected dates
query = [cur.execute("SELECT * FROM BankData WHERE Fed_Rssd IN ('" + str(x) + "') AND repdte IN " +
str(self.date).replace('[', '(').replace(']', ')')).fetchall() for x in self.srch]
self.data = [{
self.names[k]: [
query[x][y][k] for y in range(len(query[x]))]
for k in range(len(self.names))}
for x in range(len(query))]
# create Gridresult object from inputs and pack in results canvas
self.results.tvr.build(srch=self.srch, date=self.date, data=self.data, names=self.names)
# GridResult Frame contains tables, child of Pageone.results
class GridResult(tk.Canvas):
def __init__(self, parent):
tk.Canvas.__init__(self, parent)
self.parent = parent
self.height = 200
self.width = 200
self.config(width=200, height=200)
self.tv_list = []
self.cr_list = []
self.date = []
self.sb = tk.Scrollbar(self.parent, orient='horizontal')
self.sb.pack(side='bottom', fill='x')
print('Gridresult')
def build(self, **kwargs):
srch = kwargs['srch']
date = kwargs['date']
self.date = date
data = kwargs['data']
names = kwargs['names']
# create TreeViews
for x in self.tv_list:
x.destroy()
for x in self.cr_list:
x.destroy()
self.tv_list = []
self.cr_list = []
for x in range(len(data)):
#parent?
tvx = ttk.Treeview(self, columns=date, show='tree headings', height=10)
cr = ChartResult(self, df=None)
tvx.heading('#0', text=srch[x])
tvx.column('#0', stretch=False, width=70)
if len(date) >= 1:
for y in range(len(date)):
ix = '#' + str(y+1)
tvx.heading(ix, text=date[y])
tvx.column(ix, stretch=False, width=80)
for z in range(len(names)):
tvx.insert('', z+1, text=str(names[z]), values=data[x][names[z]], tag=x)
print('tvx')
print(tvx)
tvx.grid(row=0, column=x)
self.tv_list.append(tvx)
self.cr_list.append(cr)
# bind GridResult.TreeViews to ChartResult
tvx.bind("<<TreeviewSelect>>", self.callback)
print(self.tv_list)
print(len(self.tv_list))
self.sb.config(command=self.xview)
self.config(xscrollcommand=self.sb.set)
self.config(scrollregion=(0,0,5000,500))
self.place(anchor='nw')
def clear(self):
try:
self.destroy()
except Exception:
print('error')
pass
# handle callback for Charts
def callback(self, event):
#self.cr.clear()
print('CALLBACK')
print(self)
w = event.widget
x = w.selection()
print('W Grid {}'.format(w.grid_info()))
print('W {}'.format(w))
title = w.item(x)['text']
col = w.grid_info()['column']
values = [float(x) for x in w.item(x)['values']]
print('values')
print(values)
data = {'Date': self.date, title: values}
df = pd.DataFrame(data, columns=['Date', title])
self.cr_list[col].build(df, col)
# ChartResult Frame contains charts
class ChartResult(tk.Frame):
def __init__(self, parent, **kwargs):
tk.Frame.__init__(self, parent)
self.w = None
def build(self, df, col):
try: self.w.destroy()
except Exception:
pass
figure = plt.Figure(figsize=(1.5, 1.5), dpi=100)
ax1 = figure.add_subplot(111)
bar1 = FigureCanvasTkAgg(figure, self)
df.plot(kind='bar', legend=True, ax=ax1)
self.w = bar1.get_tk_widget()
self.w.pack()
self.grid(row=1, column=col)
def clear(self):
try:
self.destroy()
except Exception:
print('error')
pass
# 746223,3317192,564856,419255,350657,148470,3048487
# 746223,3317192
if __name__ == "__main__":
app = tk.Tk()
app.geometry("400x400")
MainApp(app).pack(side="top", fill="both", expand=True)
app.mainloop()