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

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

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

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

Python

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

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

Q&A

解決済

2回答

2651閲覧

ExcelのSheet名をGUI上で繰り返し選択&取得ができない

temtemtemtem

総合スコア9

Tkinter

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

Python

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

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

0グッド

0クリップ

投稿2020/06/02 03:49

わからないこと

Python3.#でTKINTERを使ってエクセルのファイルネームとシートネームを取得したいです。
しかし初回は取得できるのですが、再取得をGUI上からボタンで行うとシートネームを表示してくれません。
これはなぜでしょうか。

python

1import tkinter as tk 2import pandas as pd 3import tkinter as tk 4import tkinter.filedialog 5 6def sheet_select(sheets): 7 import tkinter as tk 8 frame2 = tk.Tk() 9 frame2.title('sheet選択') 10 # フレームの作成 11 12 # フレーム1(上側:リストボックスを格納する) 13 frame = tk.Frame(frame2) 14 frame.grid(row=0, sticky="we") 15 # フレーム2(下側:ボタンを格納する) 16 frame_button = tk.Frame(frame2) 17 frame_button.grid(row=1, sticky="we") 18 19 # データ(リストボックスに表示させる) 20 list_value = tk.StringVar() 21 list_value.set(sheets) 22 23 # リストボックスの作成 24 lb = tk.Listbox(frame, height=8, listvariable=list_value, selectmode="single") 25 lb.pack() 26 27 # テキストの作成 28 text_str = tk.StringVar() 29 text_str.set("ボタンを押して下さい") 30 text = tk.Label(frame_button, textvariable=text_str) 31 text.grid(row=0, columnspan=3) 32 # tk.messagebox.showinfo('CBD比較プログラム','Sheetsを選んでください') 33 selected = [] 34 35 def ok_button(): 36 for i in lb.curselection(): 37 selected.append(lb.get(i, i)[0]) 38 39 def close_window(): 40 frame2.destroy() 41 # frame2.quit() 42 43 44 button = tk.Button(frame_button, text="OK", command=lambda: [ok_button(), close_window()]) 45 button.grid(row=1, column=0, columnspan=2) 46 # 画面の表示 47 frame2.mainloop() 48 return selected[0] 49 50 51def file_select(): 52 # --------------------------------------------------------------------------------------------------------------------------- 53 # 基のファイル選択ダイアログの表示 54 root2 = tk.Tk() 55 56 fTyp = [("excel(.xlsm)", ".xlsm")] 57 iDir = 'C://pg' 58 file1 = tk.filedialog.askopenfilename(filetypes=fTyp, initialdir=iDir) 59 print(file1) 60 61 # シートを取得 62 root2.destroy() 63 bk = pd.ExcelFile(file1) 64 print(bk) 65 sheets = list(bk.sheet_names) 66 print(sheets) 67 selected = sheet_select(sheets) 68 return selected, file1 69 70 71 72sheet_name1, file1 = file_select() 73class Main(tk.Frame): 74 def __init__(self, master): 75 super().__init__(master) 76 77 button = tk.Button(self, text='re-do', command=lambda: re_set(self)) 78 button.pack() 79 frame = tk.LabelFrame(self, text='test', bg='#fff', fg='Blue', name='labelframe_test') 80 frame.pack(pady=10, anchor=tk.NW) 81 82 print(sheet_name1, file1) 83 84def re_set(owner): 85 sheet_name1, file1 = file_select() 86 print(sheet_name1, file1) 87 88def main(): 89 root = tk.Tk() 90 root.geometry("500x500") 91 win = Main(root) 92 win.pack(fill='both', expand='YES') 93 root.mainloop() 94 95 96if __name__ == '__main__': 97 main() 98

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

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

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

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

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

guest

回答2

0

ウィンドウ表示前にダイアログ表示と、
リスト選択ダイアログのサンプルです。

リストダイアログは書籍からの借用。[source]

python

1import tkinter as tk 2from tkinter.filedialog import askopenfilename 3from tkinter.simpledialog import Dialog 4 5# 6# Modern Python Standard Library Cookbook Chapter13 7# 8class ChoiceDialog(Dialog): 9 def __init__(self, parent, title, text, items): 10 self.selection = None 11 self._items = items 12 self._text = text 13 super().__init__(parent, title=title) 14 15 def body(self, parent): 16 self._message = tk.Message(parent, text=self._text, aspect=400) 17 self._list = tk.Listbox(parent) 18 self._list.pack(expand=1, fill=tk.BOTH, side=tk.TOP) 19 for item in self._items: 20 self._list.insert(tk.END, item) 21 return self._list 22 23 def validate(self): 24 if not self._list.curselection(): 25 return 0 26 return 1 27 28 def apply(self): 29 self.selection = self._items[self._list.curselection()[0]] 30 31 32def askchoice(parent, title, text, items): 33 dialog = ChoiceDialog(parent, title, text, items) 34 return dialog.selection 35 36def select_list(owner, items): 37 return askchoice(owner, "Choose", "...", items) 38 39def select_file(owner): 40 return askopenfilename( 41 filetypes=[("Python File", "*.py")], 42 initialdir="./", 43 parent=owner) 44 45def reset(owner): 46 filepath = select_file(owner) 47 if not filepath: 48 return 49 50 # 仮) 51 value = select_list(owner, ["A", "B", "C"]) 52 if value: 53 owner.setSelected(value) 54 else: 55 owner.setSelected("selection was canceled") 56 57 58class MainFrame(tk.Frame): 59 def __init__(self, master, *args, **kw): 60 super().__init__(master, *args, **kw) 61 62 self.selected = tk.StringVar(self) 63 64 button = tk.Button(self, text="Re-Do") 65 button["command"] = lambda: reset(self) 66 button.pack() 67 68 label = tk.Label(self, textvar=self.selected) 69 label.pack() 70 71 def setSelected(self, item): 72 self.selected.set(item) 73 74 75def main(): 76 root = tk.Tk() 77 root.title("Select Python file demo") 78 root.geometry("500x500") 79 80 win = MainFrame(root) 81 82 def init_win(): 83 # メインウィンドウ前にダイアログを出したい場合 84 # ダイアログ選択後に pack() を呼び出して表示 85 reset(owner=win) 86 win.pack(fill=tk.BOTH, expand=tk.YES) 87 88 root.after_idle(init_win) # <-- mainloop()内から対象の関数を呼び出します 89 root.mainloop() 90 91 92if __name__ == '__main__': 93 main()

投稿2020/06/02 07:43

teamikl

総合スコア8664

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

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

0

ベストアンサー

原因: tk.Tk() を複数回使っている為だと思います。

tk.Tk() は root = tk.Tk() の一カ所のみにした方が、無難です。


算定的な回避策

python

1# def sheet_select(sheets)内 2 3 # データ(リストボックスに表示させる) 4 list_value = tk.StringVar(frame2)

どうしてこれで直るのかうまく説明できませんが、
この変更により2回目以降のシート名一覧の表示を確認。

補足追記:
StringVar() の親を指定しない場合、モジュール内グローバルの_default_root が適応されるのですが、
複数回 Tk() のインスタンスを作って破棄している為、
destroy時にこの _default_root が使えなくなってしまいます。=>2回目以降正常にできない理由

上記の回避策は、親を明示的に与える事で回避できたのだと思いますが、
根本的な対策にはなりません。


修正方法(根本的な対策)

概要のみになりますが、

  • sheet_select(): frame2 = tk.Tk() -> tk.Toplevel() に変更

 詳しくは、「モーダルダイアログ」について調べて見て下さい。

  • 最初の sheet_name1, file1 = file_select() は root = tk.Tk() 呼び出し後にする。

 ※ 但し、別の問題で、sheet_name1, file1 の2つのグローバル変数を用いた値の受け渡しが
ここの問題修正を少し難しくしてます。

sheet_select は、Tk() を別途作成しない場合は、mainloop()呼び出した後である必要があります。
-> root.after() でmainloopの起動後に呼び出し。

方針としては、

  • まずは、最初の1回のダイアログ表示を一旦辞めて、(※ グローバル変数は使わない)
  • reset ボタン押したときに正常に動くようにする。(※ Tk()は何度も呼び出さない)
  • その後、起動時にダイアログ表示を root.after() を使って呼び出すようにすると良いと思います。

投稿2020/06/02 06:13

編集2020/06/02 07:52
teamikl

総合スコア8664

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問