第3章:行番号をつける(左右に分割・縦スクロール同期)

python

目的

左側に「行番号専用 Treeview」、右側に「データ用 Treeview」を置き、縦スクロールを同期させます。

コード(抜粋・最小版)

import tkinter as tk
from tkinter import ttk, filedialog
import csv

class App(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("CSV Viewer")
        self.geometry("1000x600")

        wrap = ttk.Frame(self)
        wrap.pack(fill=tk.BOTH, expand=True)

        self.vscroll = ttk.Scrollbar(wrap, orient="vertical")
        self.hscroll = ttk.Scrollbar(wrap, orient="horizontal")

        self.left = ttk.Treeview(wrap, columns=("#",), show="headings", selectmode="none",
                                 yscrollcommand=self.vscroll.set)
        self.left.heading("#", text="#")
        self.left.column("#", width=60, anchor="e", stretch=False)

        self.right = ttk.Treeview(wrap, columns=(), show="headings",
                                  yscrollcommand=self._on_right_yset,
                                  xscrollcommand=self.hscroll.set)

        self.left.grid(row=0, column=0, sticky="ns")
        self.right.grid(row=0, column=1, sticky="nsew")
        self.vscroll.grid(row=0, column=2, sticky="ns")
        self.hscroll.grid(row=1, column=1, sticky="ew")

        wrap.columnconfigure(1, weight=1)
        wrap.rowconfigure(0, weight=1)

        self.vscroll.config(command=self._on_yview)
        self.hscroll.config(command=self.right.xview)

        ttk.Button(self, text="Open CSV", command=self.open_csv).pack()

    def _on_right_yset(self, first, last):
        self.left.yview_moveto(first)
        self.vscroll.set(first, last)

    def _on_yview(self, *args):
        self.left.yview(*args)
        self.right.yview(*args)

    def open_csv(self):
        path = filedialog.askopenfilename(filetypes=[("CSV","*.csv")])
        if not path: return
        with open(path, newline="", encoding="utf-8") as f:
            rows = list(csv.reader(f))
        headers, data = rows[0], rows[1:]
        self.right["columns"] = headers
        for h in headers:
            self.right.heading(h, text=h)
            self.right.column(h, width=120, anchor="w", stretch=False)
        self.left.delete(*self.left.get_children())
        self.right.delete(*self.right.get_children())
        for i, row in enumerate(data, start=1):
            self.left.insert("", "end", values=(i,))
            self.right.insert("", "end", values=row)

if __name__ == "__main__":
    App().mainloop()

解説

  • 行番号は別 Treeviewにすることで「横スクロールの影響を受けない固定列」になる
  • yview を互いに呼ぶことで縦スクロール同期

前へ → 第2章
次へ → 第4章:列の表示/非表示(右サイドバー)

タイトルとURLをコピーしました