前提・実現したいこと
Python 3.6で、Tkinterをつかって、動的に生成したラベルとチェックボックスから、
どのチェックボックスを押したかを判別したいです。画面イメージ(例)を貼り付けます。
※ボタンは別の用途に使う予定で、チェックボックスを押した時点で、どのチェックボックスがおされたかは、イベントでとるつもりで設置しています。
イメージとしては下記となります。
発生している問題・エラーメッセージ
エラーが出ないように作ることはできたのですが、動的に生成する関係で、チェックボックスを押したときに呼ばれた関数が共通にならざるを得なくなってしまっています。(self.cb_clicked)
そのため、どのチェックボックスを押されても同じ関数がコールされるため、
どのチェックボックスを押されたかが判断できなくなっています。
該当部分のクラス実装を下記に示します。(一部ラベルは、上位のクラスからstrのlistで飛んでくるため
中身は見えなくなっていますが、本質ではないため、省略します。)
ご回答いただきたいこと
下記に関してご回答いただければ幸甚に存じます。
①どのチェックボックスが押されたかを(できればこのクラス内で)判断する方法
(難しければ、ほかのクラスでの判別でもよいです)
②これらのチェックボックスのうち、N個まで同時に押せるが、N+1個にならないように
制御できる方法(今は無理やり「cb_clicked」でやろうとしていますが、思った処理になっていないので悩ましいです。。。N+1個になった場合、直近で押したもの以外で、一番若いチェックを外したいです。)
③(これはもし可能であればでよいのですが)スクロールバーが、右のチェックボックスとラベルのリストにうまい感じに張り付かないです。(以前ここでご質問させていただきました通り、Canvasにスクロールバーを貼り付けると、再描画がうまくいったのですが、チェックボックスとラベルのリストの大きさなどを変えるとCanvasのサイズと会わず、このようにずれてしまいます。もしよい方法をご存知の方がいれば、チェックボックスとラベルのテーブルの大きさが変わっても追従できるようにしたいです。
該当のソースコード
Python
1# Checkboxを含むLabelのテーブル(スクロールバーの影響を防ぐ変更により、タイトル部分は外に出すことにした。) 2class LabelTableWithCb: 3 def __init__(self, master=None, num_y=3, p_x=0, p_y=0, dir_lbl=None): 4 # self.master = master 5 # place使うときは、フレームサイズを決めておく必要。 6 if dir_lbl is None: 7 dir_lbl = [] 8 9 self.pane = tk.Frame(master=master) 10 # self.pane.configure(width=400, height=600) 11 # self.pane.place(x=p_x, y=p_y) 12 self.pane.pack(side=LEFT) 13 14 # canvas, scrollbar設定 15 # self.canvas = tk.Canvas(master=self.pane, bg='blue') 16 self.canvas = tk.Canvas(master=self.pane) 17 self.canvas.propagate(False) # ウィジェットの大きさに関係なくフレームサイズ決めたいときに必要 18 self.tbl_frame = tk.Frame(self.canvas, bg="red") 19 self.my_scrollbar = tk.Scrollbar(self.pane, orient="vertical", command=self.canvas.yview) 20 21 self.cb = [] 22 self.cb_val = [] 23 24 # タイトル部分 25 title_lst = ["label", "cb"] 26 col_span = len(title_lst) 27 for x in range(col_span): 28 tk.Label(master=self.tbl_frame, text=title_lst[x], bd=2, relief="ridge" 29 ).grid(column=x, row=0, sticky=tk.NSEW) 30 # tk.Label(master=self.pane, text=title_lst[x], bd=2, relief="ridge" 31 # ).grid(column=x, row=0, sticky=tk.NSEW) 32 33 self.canvas.configure(yscrollcommand=self.my_scrollbar.set) 34 # self.canvas.grid(column=0, row=1, columnspan=col_span, sticky=tk.NSEW) 35 self.my_scrollbar.pack(side="right", fill="y") 36 self.canvas.pack(side="top") 37 self.canvas.create_window((0, 0), window=self.tbl_frame, anchor='nw') 38 self.tbl_frame.bind("<Configure>", self.update_frame) 39 40 for y in range(1, num_y): 41 tk.Label(master=self.tbl_frame, text=dir_lbl[y - 1], bd=2, 42 relief="ridge").grid(column=0, row=y, sticky=tk.NSEW) 43 # チェックボックスの列 44 self.cb_val.append(tk.BooleanVar()) 45 self.cb_val[y - 1].set(False) 46 self.cb.append(tk.Checkbutton(master=self.tbl_frame, variable=self.cb_val[y - 1], bd=2, relief="ridge", 47 command=self.cb_clicked)) 48 # self.cb.append(tk.Checkbutton(master=self.tbl_frame, variable=self.cb_val[y - 1], bd=2, relief="ridge")) 49 # self.cb[y - 1].bind("<Button-1>", self.cb_clicked) 50 self.cb[y - 1].grid(column=1, row=y, sticky=tk.NSEW) 51 52 self.create_widget() 53 54 def create_widget(self): 55 self.canvas.configure(yscrollcommand=self.my_scrollbar.set) 56 self.my_scrollbar.pack(side="right", fill="y") 57 self.canvas.pack(side="top") 58 self.canvas.create_window((0, 0), window=self.tbl_frame, anchor='nw') 59 self.tbl_frame.bind("<Configure>", self.update_frame) 60 61 def update_frame(self, event): 62 self.canvas.configure(scrollregion=self.canvas.bbox("all"), width=105, height=200) 63 pass 64 65 def get_cb_val(self, cb_id): 66 if self.cb_val[cb_id] is not None: 67 return self.cb_val[cb_id].get() 68 else: 69 pass 70 71 # チェックボックス押下時処理。チェックの値は、self.cb_valのlistに格納されている。 72 def cb_clicked(self): 73 # print('チェックボックス押下') 74 cnt = 0 75 for k, cb in enumerate(self.cb_val): 76 # print("{},".format(cb.get())) 77 if cb.get() is True: 78 cnt += 1 79 80 # チェックが2こ目になった時点で抜け。(本当は押したcbのIDが取れればよいが、簡単には分からないので暫定処置) 81 if cnt >= 2: 82 for cb2 in self.cb_val: 83 cb2.set(False) 84 cb.set(True) 85 break 86 87 # 確認用 88 for k, cb in enumerate(self.cb_val): 89 print("cb_id:{}, val:{},".format(k, cb.get())) 90
試したこと
QiitaやTkinter本家のページなどを見て実装方法を確認した
補足情報(FW/ツールのバージョンなど)
Python 3.6.6
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/03/11 12:30
2019/03/12 00:02
2019/03/13 15:53