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

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

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

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

Python

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

Q&A

解決済

3回答

12502閲覧

【Python】【Tkinter】1つ目のプルダウンで選択したものによって、2つ目のプルダウンのリストの内容を変えたい

mintiamegahard

総合スコア8

Tkinter

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

Python

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

0グッド

2クリップ

投稿2020/03/18 05:50

###前提
Comboboxを用いて一つ目のプルダウンメニュー('ひらがな', 'かたかな', 'alphabet')
を作成した。このそれぞれのリストに関連する二つ目のプルダウンメニューを作成したい。

OS:Windows 10
Pythonバージョン:3.5.4(64bit)
開発環境:Pycharm

###実現したい事
'ひらがな'を選択した時、二つ目のプルダウンメニューは('あ', 'い', 'う', 'え', 'お')
'カタカナ'を選択した時、二つ目のプルダウンメニューは('ア', 'イ', 'ウ', 'エ', 'オ')
'alphabet'を選択した時、二つ目のプルダウンメニューは('a', 'i', 'u', 'e', 'o')
となるようにしたい。

###発生している問題
0. 一つ目のプルダウンメニューを選択してから二つ目のプルダウンメニューが表示される(できれば最初から存在していて、一つ目を選択してから二つ目のリストを表示させたい)

  1. 一つ目のプルダウンメニューを選択した後、再度選択ができない(選択肢がalphabetのみになる)

###該当のソースコード

Python

1import tkinter as tk 2import tkinter.ttk as ttk 3 4root = tk.Tk() 5 6cb1 = ttk.Combobox(root, state='readonly') 7cb1['values'] = ('ひらがな', 'カタカナ', 'alphabet') 8cb1.grid(row=1, column=1) 9 10 11# cb1で'ひらがな'を選択したら、cb2_1のプルダウンリストになる 12def hira_selected(event): 13 cb1['values'] = 'ひらがな' 14 cb2_1 = ttk.Combobox(root, state='readonly') 15 cb2_1['values'] = ('あ', 'い', 'う', 'え', 'お') 16 cb2_1.grid(row=1, column=2) 17 18 19cb1.bind('<<ComboboxSelected>>', hira_selected) 20cb1.bind('<<Return>>', hira_selected) 21 22 23# cb1で'カタカナ'を選択したら、cb2_2のプルダウンリストになる 24def kata_selected(event): 25 cb1['values'] = 'カタカナ' 26 cb2_2 = ttk.Combobox(root, state='readonly') 27 cb2_2['values'] = ('ア', 'イ', 'ウ', 'エ', 'オ') 28 cb2_2.grid(row=1, column=2) 29 30 31cb1.bind('<<ComboboxSelected>>', kata_selected) 32cb1.bind('<<Return>>', kata_selected) 33 34 35# cb1で'alphabet'を選択したら、cb2_3のプルダウンリストになる 36def alph_selected(event): 37 cb1['values'] = 'alpabet' 38 cb2_3 = ttk.Combobox(root, state='readonly') 39 cb2_3['values'] = ('a', 'i', 'u', 'e', 'o') 40 cb2_3.grid(row=1, column=2) 41 42 43cb1.bind('<<ComboboxSelected>>', alph_selected) 44cb1.bind('<<Return>>', alph_selected) 45 46root.mainloop() 47

初歩的な質問かと思いますが、ご回答をお願いいたします。

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

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

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

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

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

t_obara

2020/03/18 06:04

cb1が選択された時のイベントの中で、何が選択されているかをチェックし、それに対応したcombox(cb2_1,cb2_2,cb2_3)を表示するようにするのが良いのではないでしょうか。cb2_1からcb2_3はあらかじめ非表示で作成しておく。
mintiamegahard

2020/03/18 06:37

情報提供ありがとうございます。お手数ですが、もしよろしければ、あらかじめ非表示するにはどうすればいいか教えていただけますでしょうか。
teamikl

2020/03/18 06:54

問題1について確認させてください > できれば最初から存在していて、一つ目を選択してから二つ目の「リスト」を表示させたい 2つ目の「プルダウンのUI」は最初から表示されていて、 その「選択項目」を一つ目を選択してから表示させたい という事でしょうか?
mintiamegahard

2020/03/18 07:06

teramiklさん、ご返信ありがとうございます。 >2つ目の「プルダウンのUI」は最初から表示されていて、 その「選択項目」を一つ目を選択してから表示させたい そうです。一つ目を選択する前は、二つ目を選択しても何もない状態にしていたいです。
guest

回答3

0

python

1import json 2import collections 3import tkinter as tk 4import tkinter.ttk as ttk 5 6LANG_DATA = """ 7{ 8 "ひらがな": { 9 "あ": ["亜", "阿", "吾", "㋐"], 10 "い": [], 11 "う": [], 12 "え": [], 13 "お": [] 14 }, 15 "カタカナ": { 16 "ア": [], 17 "イ": [], 18 "ウ": [], 19 "エ": [], 20 "オ": [] 21 }, 22 "alphabet": { 23 "a": [], 24 "i": [], 25 "u": [], 26 "e": [], 27 "o": [] 28 } 29} 30""" 31 32lang = json.loads(LANG_DATA, object_pairs_hook=collections.OrderedDict) 33root = tk.Tk() 34 35cb1 = ttk.Combobox(root, state='readonly') 36cb1['values'] = list(lang.keys()) 37cb1.grid(row=1, column=1) 38 39cb2 = ttk.Combobox(root, state='readonly') 40cb2.grid(row=1, column=2) 41 42cb3 = ttk.Combobox(root, state='readonly') 43cb3.grid(row=1, column=3) 44 45def cb1_selected(event): 46 cb2['values'] = list(lang[cb1.get()].keys()) 47 cb2.set('') 48 49def cb2_selected(event): 50 cb3['values'] = lang[cb1.get()][cb2.get()] 51 cb3.set('') 52 53cb1.bind('<<ComboboxSelected>>', cb1_selected) 54cb2.bind('<<ComboboxSelected>>', cb2_selected) 55 56root.mainloop()

~selected関数の中身は、langのデータ構造に応じて変更します。

lang[key] での辞書の参照は、キーが存在しない場合に例外を出すので、
例外処理等は適宜必要になるかもしれません。


キーの順序に関して

json モジュール 注釈より

Python3.7 以前では、dict は順序が保証されておらず、 collections.OrderedDict が指定された場合以外は、出力順や入力順が保たれていませんでした。 Python3.7 からは、標準の dict の挿入順序が保証されるため、 JSON の生成と解析にあたって collections.OrderedDict を指定する必要がなくなりました。

3.7以前の対応として、JSONでOrderedDictを指定し、
読み込むことでキーを順序付きに出来ます。

投稿2020/03/18 09:34

編集2020/03/18 09:58
teamikl

総合スコア8664

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

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

0

ベストアンサー

また少し改変しました。

こういう事でしょうか?

Python

1import tkinter as tk 2import tkinter.ttk as ttk 3 4root = tk.Tk() 5 6lang = {'ひらがな': ('あ', 'い', 'う', 'え', 'お'), 7 'カタカナ': ('ア', 'イ', 'ウ', 'エ', 'オ'), 8 'alphabet': ('a', 'i', 'u', 'e', 'o')} 9 10cb1 = ttk.Combobox(root, state='readonly') 11cb1['values'] = list(lang.keys()) 12cb1.grid(row=1, column=1) 13 14cb2 = ttk.Combobox(root, state='readonly') 15cb2['value'] = '' 16cb2.grid(row=1, column=2) 17 18 19def selected(event): 20 var = cb1.get() 21 cb2['value'] = lang[var] 22 23cb1.bind('<<ComboboxSelected>>', selected) 24 25root.mainloop()

投稿2020/03/18 08:00

nto

総合スコア1438

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

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

mintiamegahard

2020/03/18 08:25

すみません、少し違います。私の伝え方が悪かったですね。cb1で'ひらがな'、cb2で'あ'を選んだとして、三つ目のコンボボックス(例:('亜', '阿', '吾', '㋐'))を作って、選択、という流れを実現したいという意味です。 また、改変いただいたコードを実行してみましたが、 ①一つ目のプルダウンメニューの順番が'カタカナ','ひらがな','alphabet'の順番になっている。 ②例えば一つ目で'カタカナ'を選択→二つ目で'ア'を選択→1つ目で'ひらがな'を選択した時、二つ目のプルダウンの表示が'ア'のままでリセットされない。 上記2点について、差し支えなければ教えていただけますでしょうか。
nto

2020/03/18 09:25 編集

その場合には lang2 = {'あ':('亜', '阿', '吾', '㋐'), 'い':(), 'う':(), 'え':(), 'お':()} といった様に辞書を更に用意し cb3 = ttk.Combobox(root, state='readonly') cb3['value'] = '' cb3.grid(row=1, column=3) と、3つ目のコンボボックスの設置、 そしてcb1の様に、cb2にも同様のイベントを用意 def selected2(event): var = cb2.get() cb3['value'] = lang2[var] そしてイベントの設置 cb2.bind('<<ComboboxSelected>>', selected2)
nto

2020/03/18 08:50

>>①一つ目のプルダウンメニューの順番が'カタカナ','ひらがな','alphabet'の順番になっている。 これについては原因は判りかねます。こちらの環境では順番通りに表示されています。 辞書の順番通りに読み込まれるはずですので、辞書の順番さえ変更していなければそのまま読み込まれるはずです。 >>②例えば一つ目で'カタカナ'を選択→二つ目で'ア'を選択→1つ目で'ひらがな'を選択した時、二つ目のプルダウンの表示が'ア'のままでリセットされない。 こちらもごめんなさい、前回選択したセットされた値をクリアしたいという事ですよね? 思いついたやり方で何パターンか試してみましたが、私には動的にクリアさせ表示を空白にする事は出来ませんでした。
teamikl

2020/03/18 09:03

キーの順序について失念してました。 順序付き辞書は 標準ライブラリの collections に OrderedDictクラス があります。 選択位置のリセットは cb2.current(0) で出来ます。 (但し、values が設定されていない状態で呼び出すと例外が出るので注意)
teamikl

2020/03/18 09:37

キーの順序についてはPythonのバージョンの違いだと思います。 選択のクリアについて、↑のコメントを踏まえたコードを投稿しましたが current(0) は最初の要素を選択でした。空白にするのとは少し違ったかな。
nto

2020/03/18 09:42

なるほど、私も参考になります。 動的に空白にするのは困難、current(0)で先頭valueの選択で妥協といった所がベストな形かもしれませんね。
teamikl

2020/03/18 10:08

一応、cb.set('') により表示を空白には出来ました。 あまり深くテストはしてませんが。空白を許容すると、 lang[''] (空白文字をキーに)を参照してエラーになるケースへの対応が 必要になりそうな辺りが心配です。
mintiamegahard

2020/03/19 00:05

nto様、teamikl様、返答が遅れてしまい申し訳ありません。 このような拙い質問に対して、ここまで丁寧に解説していただきありがとうございます。皆様からの情報をもとにもう一度作成してみます。
guest

0

上記のコードでは
cb1.bind('<<ComboboxSelected>>', hira_selected)
cb1.bind('<<ComboboxSelected>>', kata_selected)
cb1.bind('<<ComboboxSelected>>', alph_selected)
と、コンボボックスを選択する事で3つ同時にイベントが発生してしまっています。

また質問者様のコードではcb1['values'] = 'alpabet'とスペルミスがある様です。

私も初学者の部類ではありますが、下記のコードに修正した所質問者様が望んだ形の動作をするのではないかと思います。
試してみてください。

Python

1import tkinter as tk 2import tkinter.ttk as ttk 3 4root = tk.Tk() 5 6cb1 = ttk.Combobox(root, state='readonly') 7cb1['values'] = ('ひらがな', 'カタカナ', 'alphabet') 8cb1.grid(row=1, column=1) 9 10 11def selected(event): 12 var = cb1.get() 13 if var == 'ひらがな': 14 val = ('あ', 'い', 'う', 'え', 'お') 15 elif var == 'カタカナ': 16 val = ('ア', 'イ', 'ウ', 'エ', 'オ') 17 elif var == 'alphabet': 18 val = ('a', 'i', 'u', 'e', 'o') 19 20 cb2 = ttk.Combobox(root, state='readonly') 21 cb2['value'] = val 22 cb2.grid(row=1, column=2) 23 24cb1.bind('<<ComboboxSelected>>', selected) 25cb1.bind('<<Return>>', selected) 26 27root.mainloop()

投稿2020/03/18 06:23

nto

総合スコア1438

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

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

mintiamegahard

2020/03/18 06:49

ご回答ありがとうございました。指摘頂いた点を試したところ、作成したい動作が実行できました!可能であれば、発生している問題1のプルダウン非表示のやり方も教えていただけますでしょうか。
teamikl

2020/03/18 07:28 編集

ntoさんの回答とほぼ同じコードになったので、 コメントで補足という形で返答させてもらいますね。 cb2 の生成と配置(grid())の2行を関数の外に出すと問題1も解消できます。 ---- 現状では、selectedが呼び出される度に新しい Comboboxが作成されてます。 配置が同じ位置なので見た目では解りませんが、内部では print(cb2) とすると呼び出される度に新しいIDが振られているのが確認できます。 そして、リスト2の選択に応じて何か処理をするといった時に 変数`cb2` はselected内のローカル変数なので、 外部から直接参照できないといった別の課題も出てきます。
teamikl

2020/03/18 07:21

更に蛇足になりますが、 - cb1の選択項目をキーとした辞書を作ると便利です (コード断片のみになります) - cb2values = {'ひらがな':('あ', 'い', 'う', 'え', 'お'), ...} # 辞書を準備 - cb1['values'] = list(cb2values.keys()) # キーをcb1の選択項目に設定 - cb2['values'] = cb2values.get(cb1.get(), ()) # 選択された項目をキーにcb2の選択項目を設定 - `<<Return>>` のイベントに関しては、直接入力がなし(readonly)なら不要になります。
mintiamegahard

2020/03/18 07:31

ご回答ありがとうございます。この後同様の流れで三つ目のプルダウンメニューを作る予定なのですが、教えていただいた辞書を使ったほうがすっきりしそうですね。
nto

2020/03/18 07:35

そうですね、辞書で用意した上に選択された項目をキーに設定するのが非常にスムーズですね。 ローカル変数である点については質問者様がその後どういったコーディングをしていくか次第な所もある為、極力改変はせずコードを提示しておりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問