Прокручиваемый холст внутри LabelFrame - PullRequest
0 голосов
/ 29 октября 2019

Я потратил несколько дней на то, что я думал, будет простой задачей. Я создаю графическое приложение для просмотра загруженных данных, содержащих данные баланса, переданные в 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()
...