質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

Q&A

解決済

1回答

7637閲覧

Python3 Tkinter Treeviewでソートしたい

person

総合スコア223

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

0グッド

0クリップ

投稿2020/09/25 12:49

CSVのデータをTreeviewで表示し、
ヘッダ列をクリックしたら昇順、もう一度クリックしたら降順、もう一度クリックしたら昇順、・・・、としたいです。
(一応この段階ではもとの順番に戻さなくていいです。)

クリックしたヘッダが何列目かまでは取得できましたが、クリックした列の各行のデータの取得と各行の入れ替え方法がわかりません。

一応、コメントアウトしてあるやつを有効化したときと同じ動作を期待しているのですが、最初のforの前にあるやつがよくわかりませんでした。文法的な意味で です。

以下ソースコードです。すべて同じ階層に配置。

main.py

Python

1from tkinter import ttk 2from tkinter.font import Font 3import tkinter as tk 4 5import read 6 7 8def headerSelected(tree, reverse_flag): 9 """ Memo 10 winfo_pointerx() マウスカーソルのx座標 11 winfo_rootx() ディスプレイ上でのx座標 12 identify_column(x) x座標のセルの識別子(文字列 "#n"。 nは1以上の整数)を返す 13 """ 14 # クリックされたヘッダ列取得(http://notwodaily.hatenablog.com/entry/2018/06/15/003411) 15 x = tree.winfo_pointerx() - tree.winfo_rootx() 16 select_column_str = tree.identify_column(x) 17 select_column_int = int(select_column_str[1:]) - 1 18 print(select_column_int) # 1列目クリックで0, 2列目クリックで1、・・・、n列目クリックでn-1 19 20 # クリックした列の各行のデータ取得 21 print(tree.get_children()) # ('I001', 'I002', 'I003', 'I004', 'I005', 'I006') 22 23 24 """ ソート(https://stackoverrun.com/ja/q/396512) 25 26 l = [(tree.set(k, select_column_int), k) for k in tree.get_children("")] 27 l.sort(reverse=reverse_flag) 28 29 for index, (val, k) in enumerate(l): 30 tree.move(k, "", index) 31 32 tree.heading(select_column_int, command=lambda:headerSelected(tree, not reverse_flag)) 33 """ 34 35 36win = tk.Tk() 37 38win.rowconfigure(0, weight=1) 39win.columnconfigure(0, weight=1) 40 41s = ttk.Style() 42s.theme_use("clam") 43fontsize = 30 44myfont = Font(size=fontsize) 45s.configure("Treeview.Heading", font=("", fontsize)) 46s.configure("Treeview", font=("", fontsize), 47 rowheight=myfont.metrics()["linespace"]) 48s.configure("Vertical.TScrollbar", arrowsize=30) 49 50 51datas = read.read() 52 53columns = 0 54for data in datas: 55 if columns < len(data): 56 columns = len(data) 57 58tree = ttk.Treeview(win) 59tree.grid(row=0, column=0, sticky="nsew", padx=(5, 0), pady=(5, 5)) 60tree["columns"] = tuple(range(columns)) 61tree["show"] = "headings" 62for i in range(columns): 63 tree.heading(i, text="Data"+str(i+1), command=lambda:headerSelected(tree, False)) 64for data in datas: 65 tree.insert("", "end", value=(data)) 66 67ysb = ttk.Scrollbar(win, orient="vertical", command=tree.yview) 68tree.configure(yscrollcommand=ysb.set) 69ysb.grid(row=0, column=1, sticky="nsew", padx=(0, 5), pady=5) 70 71 72win.mainloop() 73

read.py

Python

1import csv 2import os 3import sys 4 5def read(): 6 data = [] 7 SRC = os.path.dirname(sys.argv[0]) + "/" + "table.csv" 8 with open(file=SRC, mode="r", encoding="utf-8") as rf: 9 f = csv.reader(rf, lineterminator="\r\n") 10 for i in f: 11 data.append(i) 12 return data 13

table.csv

csv

1Aa0,Bb1,,, 2Cc2,Dd3, 3,Ee4 4Ff5,,,Gg6 5Hh7,Ii8,Jj9,Ll10,Mm11 6,,Nn12,,Oo13

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

機能自体は正常に動いてるように見えます。

enumerate が解らないという事でしょうか?
for in のループ変数に関しては、Extended Iterable Unpacking
という機能で、for文に限らず通常の変数の代入でも使えます。
(但し、関数の引数では使えなくなりました。2.xの頃は出来た)

python

1 2a, (b, c) = 1, ["a", "b"] 3 4print(a, b, c) # => 1 a b 5

python

1data = {"A": 1, "B": 2, "C": 3} 2 3for key, value in data.items(): # items() => [("A", 1), ("B", 2), ("C", 3)] 4 print(key, value) 5 6# => "A", 1 7# => "B", 2 8# => "C", 3 9 10# ループなしで単体で見た場合 11# key, value = ("A", 1)

enumerate により、リストの各要素に index が付いてるため

python

1data = {"A": 1, "B": 2, "C": 3} 2 3for index, (key, value) in enumerate(data.items()): 4 print(index, key, value) 5 6# => 0, "A", 1 7# => 0, "B", 2 8# => 0, "C", 3

子要素なしの場合ですが、順序を元に戻すには iid 順序にすると
insert された順序に戻ります。(ひとつ前に戻すは別途、ソート状態を保存しておく必要があります)

python

1def reset(): 2 for index, iid in enumerate(sorted(tree.get_children(""))): 3 tree.move(iid, "", index) 4ttk.Button(win, text="reset", command=reset).grid()

実行時に躓いた点

実行環境によっては SRC は /table.csv になってしまいます。間に os.path.abspath が必要ですが、
pyinstaller が絡むと少し複雑になるので、参考リンク。pathlib を使った解決策が良さそうです。

https://stackoverflow.com/questions/404744/determining-application-path-in-a-python-exe-generated-by-pyinstaller

投稿2020/09/26 09:52

teamikl

総合スコア8664

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

person

2020/09/27 16:34

回答ありがとうございます。 質問文に書いた「forの前にあるやつ」というのは l = [(tree.set(k, select_column_int), k) for k in tree.get_children("")] というやつです。
teamikl

2020/09/27 21:03

文法的には、「リスト内包表記」というものです。 for 文に書き直すと以下の様になります(※ コメント内の為、全角インデント) l = [] for k in tree.get_children(""): # アイテムID (IID) のリスト I001, I002 ~  value = tree.set(k, select_column_int) # ソート対象のカラムの値  l.append((value, k)) (ソート対象の値, IID) のリストをソートすることにより、 目的の IID の順序を得ています。 ---- tree.set の挙動は引数によって変わります。 > https://docs.python.org/ja/3/library/tkinter.ttk.html#tkinter.ttk.Treeview set(item, column=None, value=None) 1 引数で呼び出された場合、指定された item のカラムと値のペアからなる辞書を返します。 2 引数で呼び出された場合、指定された column の現在の値を返します。 3 引数で呼び出された場合、与えられた item の column を指定された値 value に設定します。
person

2020/09/27 23:26

ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問