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

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

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

openpyxlは、Excel2007以降のファイル(xlsx/xlsm/xltx/xltm)を読み書きするためのPythonライブラリです。

Tkinter

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

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

7341閲覧

Openpyxlでセルの色情報を取得する方法とTreeviewのイベントの設定の仕方について

nto

総合スコア1438

openpyxl

openpyxlは、Excel2007以降のファイル(xlsx/xlsm/xltx/xltm)を読み書きするためのPythonライブラリです。

Tkinter

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

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/09/25 10:34

編集2020/09/25 11:22

前提・実現したいこと

現在Excel情報を取得し、取得した情報をTkinter.Treeviewに反映するGUIを作成しております。
Excelファイル内は以下の画像の様な形式とデータになっており
GUIでは、一つのIDを指定しopenpyxlでデータを抽出し画像の様にTreeviewで表示しております。

今回目的の実装したい項目は

  • Excel内の塗りつぶし情報のTreeviewへの反映

(Treeview内でもbgを同じ色で反映したいです)

  • Treeviewへのイベントの設定

 

Excelデータサンプル
GUI動作画像

該当のソースコード

python

1 #-------Excel Window------- 2 def ExcelProcess(self): 3 # NewWindow create. 4 self.submaster = tk.Toplevel() 5 self.submaster.geometry('700x400') 6 self.submaster.grab_set() 7 self.submaster.attributes('-topmost', True) 8 9 ttk.Button(self.submaster, text='データ表示', command=self.ExcelDataGet).pack(pady=10) 10 11 # Treeview create. set data of index and anchor together for tree. 12 tvframe = ttk.Frame(self.submaster) 13 tvframe.pack() 14 self.tree = ttk.Treeview(tvframe) 15 self.tree['column'] = tuple([i for i in range(7)]) 16 tree_info = {'INDEX1': [70, tk.CENTER], 'INDEX2': [50, tk.CENTER], 'INDEX3': [70, tk.CENTER], 17 'INDEX4': [60, tk.E], 'INDEX5': [150, tk.W], 'INDEX6': [50, tk.W], 'INDEX7': [120, tk.W]} 18 for i, [header, [width, anchor]] in enumerate(tree_info.items()): 19 self.tree.column(i, width=width, anchor=anchor) 20 self.tree.heading(i, text=header) 21 self.tree["show"] = "headings" 22 self.tree.grid(row=0, column=0) 23 24 # Scrollbar create. 25 ysb = tk.Scrollbar(tvframe, orient=tk.VERTICAL, width=16, command=self.tree.yview) 26 self.tree.configure(yscrollcommand=ysb.set) 27 ysb.grid(row=0, column=1, sticky='nsew') 28 29 30 def ExcelDataGet(self): 31 # Ecelfile open. 32 wb = px.load_workbook(self.excel_path) 33 sheet = wb['Sheet1'] 34 35 target = 1000001 36 self.data = [] 37 # Data create. Read line, Datetime attribute are convert and replace if blank. 38 for row in sheet.iter_rows(): 39 if row[1].value == target: 40 tmp = [] 41 for cell in row: 42 celldata = cell.value 43 if type(celldata) == datetime: 44 celldata = cell.value.strftime('%Y/%m/%d') 45 elif celldata == None: 46 celldata = '' 47 48 tmp.append(celldata) 49 self.data.append(tmp) 50 51 # If data has target tree delete it. 52 if self.tree: 53 tree_data = self.tree.get_children() 54 for td in tree_data: 55 self.tree.delete(td) 56 # Set data for tree 57 for d in self.data: 58 self.tree.insert('', 'end', values=d)

試したこと

以下でExcelを読み込みながらセル内の塗りつぶしに関するプロパティの取得は出来ました。
if文などで塗りつぶされている色が赤だった場合~と条件の分岐をさせ、Treeview上に反映を
させる為のデータの成形を考えておりましたが、色を指定した分岐方法がわかりません。

python

1import openpyxl as px 2 3wb = px.load_workbook(file) 4sheet = wb['Sheet1'] 5 6for row in sheet.iter_rows(): 7 for cell in row: 8 print(cell.fill.fgColor) 9 print(type(cell.fill.fgColor)) 10 11>>> <openpyxl.styles.colors.Color object> 12>>> Parameters: 13>>> rgb='FFFF0000', indexed=None, auto=None, theme=None, tint=0.0, type='rgb' 14>>> <class 'openpyxl.styles.colors.Color'> 15. 16.

イベントの設定についてですが、初めにイベントの内容として
itemをダブルクリックで、現在塗りつぶしが無い場合は赤に、赤ならば黄色に
黄色ならば塗りつぶしを無しに~とTreeview上の表示を変更していくつもりです。
その場合にself.tree.bind('<Double-1>', self.function)とすべきなのか
self.tree.bind('<<TreeviewSelect>>', self.function)とすべきなのかがわからず
また、いずれの場合にはイベントの内容をどの様に組み立てれば良いのかがわからず今回質問を致しました。

補足情報(FW/ツールのバージョンなど)

python3.8
widnows10

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

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

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

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

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

guest

回答2

0

セルの色情報の出力について(自己解決)

質問内容 - 試したこと に掲題のコードまで出来ており
そこから更にrgbを指定する事でカラーコードの抽出が可能でした。

python

1print(cell.fill.fgColor.rgb) 2 3>>> 00000000

修正後

諸々を修正し以下の様な形となり、自身としては問題の解決に至りました。

python

1 #-------Excel Window------- 2 def ExcelProcess(self): 3 # NewWindow create. 4 self.submaster = tk.Toplevel() 5 self.submaster.geometry('700x400') 6 self.submaster.grab_set() 7 self.submaster.attributes('-topmost', True) 8 9 ttk.Button(self.submaster, text='データ表示', command=self.ExcelDataGet).pack(pady=10) 10 self.BTN = ttk.Button(self.submaster, text='リセット', state='disable', command=self.TreeviewReset) 11 self.BTN.pack() 12 13 # Treeview create. set data of index and anchor together for tree. 14 tvframe = ttk.Frame(self.submaster) 15 tvframe.pack() 16 self.tree = ttk.Treeview(tvframe) 17 self.tree['column'] = tuple([i for i in range(7)]) 18 tree_info = {'INDEX1': [70, tk.CENTER], 'INDEX2': [50, tk.CENTER], 'INDEX3': [70, tk.CENTER], 19 'INDEX4': [60, tk.E], 'INDEX5': [150, tk.W], 'INDEX6': [50, tk.W], 'INDEX7': [120, tk.W]} 20 for i, [header, [width, anchor]] in enumerate(tree_info.items()): 21 self.tree.column(i, width=width, anchor=anchor) 22 self.tree.heading(i, text=header) 23 self.tree["show"] = "headings" 24 self.tree.grid(row=0, column=0) 25 26 # Scrollbar create. 27 ysb = tk.Scrollbar(tvframe, orient=tk.VERTICAL, width=16, command=self.tree.yview) 28 self.tree.configure(yscrollcommand=ysb.set) 29 ysb.grid(row=0, column=1, sticky='nsew') 30 31 def ColorChange(self, event): 32 tree = event.widget 33 for itemid in tree.selection(): 34 tags = tree.item(itemid)['tags'] 35 num = tags[0] # num for tag. 36 # For each color as specify the i, set bg in color & Rewring tags. 37 if 'white' in tags: 38 self.tree.tag_configure(num, background='red') 39 self.tree.item(itemid, tags=[num, 'red']) 40 break 41 elif 'red' in tags: 42 self.tree.tag_configure(num, background='yellow') 43 self.tree.item(itemid, tags=[num, 'yellow']) 44 break 45 elif 'yellow' in tags: 46 self.tree.tag_configure(num, background='white') 47 self.tree.item(itemid, tags=[num, 'white']) 48 break 49 50 self.tree.selection_set() # focus out, this is optimal...for me. 51 52 if str(self.BTN['state']) == 'disable': # a little strange. str??? whatever, its fine:( 53 self.BTN['state'] = 'normal' 54 55 def TreeviewReset(self): 56 if self.tree: # treeitems delete. 57 self.tree.delete(*self.tree.get_children()) 58 for i, [value, color] in enumerate(self.data): # Rebuild. 59 self.tree.insert('','end', values=value, tags=[i, color]) 60 self.tree.tag_configure(i, background=color) 61 self.BTN['state'] = 'disable' # Resetbutton has state change. 62 63 def ExcelDataGet(self): 64 # Ecelfile open. 65 wb = px.load_workbook(self.excel_path) 66 sheet = wb['Sheet1'] 67 68 target = 1000001 69 color_dict = {'00000000': 'white', 'FFFF0000': 'red', 'FFFFFF00': 'yellow'} 70 self.data = [] 71 # Data create. Read line, Datetime attribute are convert and replace if blank. 72 for row in sheet.iter_rows(): 73 if row[1].value == target: 74 tmp = [] 75 for cell in row: 76 celldata = cell.value 77 if type(celldata) == datetime: 78 celldata = cell.value.strftime('%Y/%m/%d') 79 cellcolor = color_dict[cell.fill.fgColor.rgb] # 8 digit Colorcord get for here 80 elif celldata == None: 81 celldata = '' 82 83 tmp.append(celldata) 84 self.data.append([tmp, cellcolor]) 85 86 # If data has target tree delete it. 87 if self.tree: 88 self.tree.delete(*self.tree.get_children()) 89 # Set data for tree 90 for i, [value, color] in enumerate(self.data): 91 self.tree.insert('','end', values=value, tags=[i, color]) # [num, colorcorde] addition to tags. 92 self.tree.tag_configure(i, background=color) # Specify the i, set bg in color. 93 self.BTN['state'] = 'disable' # Resetbutton has state change.

投稿2020/09/27 06:21

編集2020/09/27 11:10
nto

総合スコア1438

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

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

0

ベストアンサー

Excel内の塗りつぶし情報のTreeviewへの反映

ttk.Treeview は、ライブラリ元の tcl/tk 側の不具合があって
背景色変更に対応するにはパッチ(もしくはダウングレード)が必要です。

python

1FIX_TTK_TREEVIEW_STYLE = """ 2ttk::style map Treeview \ 3 -foreground {disabled SystemGrayText \ 4 selected SystemHighlightText} \ 5 -background {disabled SystemButtonFace \ 6 selected SystemHighlight} 7""" 8 9import tkinter as tk 10root = tk.tk() 11root.tk.eval(FIX_TTK_TREEVIEW_STYLE) 12
  • tree.tag_configure でタグに対して background等のオプションを設定
  • 色変えは任意の行に対して タグ を付ける事で実現できます
  • タグは insert 時の tags に複数付けられます。
  • 選択時の色等は、タグで管理するのではなく、ウィジェットのスタイルで指定できます。

ツリービューをカスタマイズする

Treeviewへのイベントの設定

ダブルクリックかどうかは任意なので、好きな方で良いのですが
<<TreeviewSelect>> イベントはキーボードで移動しただけでも発呼されます。
リスト要素のactivate に対応するなら、<Double-1><Return>が適切ですね。

何方の場合も、イベント内では全体がクリックされた・選択されたしか通知されないので、
Treeview の selection() メソッドで選択中の行を所得する必要があります。
デフォルトでは単一選択ですが、複数選択の場合の扱いにのみ注意。

python

1 2# 塗りつぶしの色をタグ付けしておく 3tree.tag_configure("red", background="red") 4tree.insert("", tk.END, values=[...], tags=["red"]) 5 6def onActivated(event): 7 tree = event.widget 8 for iid in tree.selection(): 9 tags = tree.item(iid)["tags"] 10 if "red" in tags: # タグに赤が含まれる場合・・・ 11 print(tags) 12 13 break # 単一行選択の場合、最初の要素のみ処理することを明示する為の break 14 15tree.bind('<Double-1>', onActivated) 16tree.bind('<Return>', onActivated)

追記: タグの他に、非表示のcolumnにデータを持たせる方法もあります。
タグをリセットする等で、タグでは管理が面倒になる場合。
例: columns=["A", "B", "C"], displaycolumns=["A", "C"]
とすれば、"B" は非表示領域として活用可能。

この方法で管理しておくと、displaycolumns切り替えにより
デバッグ時のみ情報を表示する等が簡単になります。

投稿2020/09/26 08:14

編集2020/09/26 08:45
teamikl

総合スコア8664

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

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

nto

2020/09/27 09:06 編集

ご回答ありがとうございます。 無事、ダブルクリックによるbgの変更は実装する事が出来ました。 たしかに不使用であるカラムを使用するのもありでしたが、掲題のfor row in sheet.iter_rows():にて、辞書型として色情報も含めデータを管理していく予定で考えておりますので、今回は無難な形での実装となりました。 ちなみになのですが、ダブルクリックを行った際、フォーカスの色が上に被ってしまい 正常に色が変更出来ているかどうかの視認が困難になってしまっています。 (他のitemを選択し直さないと色が変更されている事が確認出来ない) この場合、フォーカスの色を無色(または変更した色と同じ色)にすべきなのか もしくは、自動でフォーカスを外す処理を施すのか nextを指定してselection_setするべきか(その場合のスクロールバーを追従させる方法がわかりません) はたまたその他に処理があるのか。 何れが自然な処理になるでしょうか?
teamikl

2020/09/27 10:23

今実際に試せないので、解る範囲で 可能なら無色(無効にする)がよさそうですが、出来るのかな… 次点で、同じ色にする -> 行によって変える必要があるので少し手間ですね。 フォーカスを外すのはキーボード上下での選択操作が出来なくなりそうです。 >スクロールバーを追従 see(iid) メソッドで指定の行に移動できます。スクロールだけなら yview ですが、selection_set は選択した時点で色が変わるので問題解決にはなりません。
nto

2020/09/27 10:42

使用上、キーボード操作もおそらくは行われない為(使用者がマウス操作のみの為) フォーカスアウトする事で済ませました。 追従についてもフォーカスアウトで追従の必要性をなくせました。 自己解決についての回答に、大まかな修正後のコードを掲載致しました。 おそらくはこれで目的の動作は得られておりますので、細かい点はこれから修正していく予定です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問