Python初心者がブログの検索順位取得ツールを作っています。
今まで、キーワードを検索してファイルに書き出す部分、ちょっとしたGUIの作成等を行ってきました。
今回は、画面に表示された表のチェックボックス(Checkbutton)の制御部分を作成していきます。
- 複数行にわたって配置されたチェックボックスが個々に動作すること
- 全部一括選択/全部一括解除ができること
- チェックされた行のキーワードを取得できること
を目標にしていきます。
現状の画面は以下のとおり。
前回はキーワードやタイトルをソースに埋め込んでいましたが、Excelファイルを読み込めるように改良しました。
また、必要なボタンも追加し、画面案に近い画面が出せるようになっています。


複数チェックボックスを制御するソースコード
Python/tkinterで複数のチェックボックス(Checkbutton)の動作を作りこんでみました。
チェックボックス(Checkbutton)に関連する箇所のみ載せます。
ちなみに、ソースの行が多くなってきたので、今回から関数化させてみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
import os import sys import tkinter from tkinter import messagebox from tkinter import filedialog import tkinter.ttk rt_width=600 rt_hgt=300 #selctボタンを押したときの処理 def select_click(): fileType = [('Excelファイル','*.xlsx')] #ファイルタイプをExcelファイルに指定 iniDir = os.path.abspath(os.path.dirname(__file__)) #初期表示フォルダ global filepath filepath = filedialog.askopenfilename(filetypes=fileType,initialdir = iniDir) if len(filepath) < 1: print('exit ブログ検索順位取得ツール') sys.exit() #Excel読み込み 戻り値はリストを3つ返す global list_keyword global list_rank global list_title list_keyword,list_rank,list_title=readExcelFile() #関数の中身は省略 makeList() #表を作成 def makeList(): global list_keyword #検索キーワード一覧 global list_rank #順位一覧 global list_title #記事タイトル一覧 num_list = len(list_keyword) #リストの数 if 'rank_str_list' in globals(): #update or 画面サイズ変更 print('rank update') else: global rank_str_list rank_str_list = list_rank #ファイル読み込み時の表示 #Canvas widgetを生成 cv_width=rt_width-20 cv_hgt=rt_hgt-70 canvas = tkinter.Canvas(root,width=cv_width,height=cv_hgt,bg='white') #背景を白に canvas.grid(row=1,rowspan=num_list,column=0,columnspan=5) #5列分 #スクロールバー vbar=tkinter.ttk.Scrollbar(root,orient=tkinter.VERTICAL) #縦方向 vbar.grid(row=1,rowspan=25,column=5,sticky='ns') #スクロールバーの制御をCanvasに通知する処理 vbar.config(command=canvas.yview) #Canvasの可動域をスクロールバーに通知する処理 canvas.config(yscrollcommand=vbar.set) #スクロール可動域<=これがないと、どこまでもスクロールされてしまう。 sc_hgt=25*(num_list+1) print(str(sc_hgt)) canvas.config(scrollregion=(0,0,cv_width,sc_hgt)) #Frameを作成 frame = tkinter.Frame(canvas,bg='white') #背景を白に #frameをcanvasに配置 canvas.create_window((0,0),window=frame,anchor=tkinter.NW,width=canvas.cget('width')) #anchor<=NWで左上に寄せる #各ラベルの幅(文字がある場合は文字ユニットとなる) c0_width=5 #チェックボックス c1_width=25 #検索キーワード c2_width=10 #順位 c3_width=70 #記事タイトル #header row=1に設定する文字列 余白は0に e0=tkinter.Label(frame,width=c0_width,text='select',background='white') e0.grid(row=1,column=0,padx=0,pady=0,ipadx=0,ipady=0) #0列目 e1=tkinter.Label(frame,width=c1_width,text='keyword',background='white',anchor='w') e1.grid(row=1,column=1,padx=0,pady=0,ipadx=0,ipady=0) #1列目 e2=tkinter.Label(frame,width=c2_width,text='rank',background='white',anchor='w') e2.grid(row=1,column=2,padx=0,pady=0,ipadx=0,ipady=0) #2列目 e3=tkinter.Label(frame,width=c3_width,text='title',background='white',anchor='w') e3.grid(row=1,column=3,padx=0,pady=0,ipadx=0,ipady=0) #3列目 irow = 2 irow0=2 erow=num_list+irow0 global list_chk list_chk = [] while irow < erow: #リストの数分ループしてLabelとチェックボックスを設置 #色の設定 if irow%2==0: color='#cdfff7' #薄い青 else: color='white' #チェックボックスの設置 bln=tkinter.BooleanVar() bln.set(False) c = tkinter.Checkbutton(frame,variable = bln,width=c0_width,text='',background='white') list_chk.append(bln) #チェックボックスの初期値 c.grid(row=irow,column=0,padx=0,pady=0,ipadx=0,ipady=0) #0列目 #検索キーワード a1=list_keyword[irow-irow0] b1=tkinter.Label(frame,width=c1_width,text=a1,background=color,anchor='w') b1.grid(row=irow,column=1,padx=0,pady=0,ipadx=0,ipady=0) #1列目 #検索順位 a2=rank_str_list[irow-irow0] if ('↑' in str(a2)) == True: a2color = 'red' elif ('↓' in str(a2)) == True: a2color = 'blue' else: a2color = 'black' b2=tkinter.Label(frame,width=c2_width,text=a2,foreground=a2color,background=color,anchor='w') b2.grid(row=irow,column=2,padx=0,pady=0,ipadx=0,ipady=0) #2列目 #記事タイトル a3=list_title[irow-irow0] b3=tkinter.Label(frame,width=c3_width,text=a3,background=color,anchor='w') b3.grid(row=irow,column=3,padx=0,pady=0,ipadx=0,ipady=0) #3列目 irow=irow+1 #リストの下に設置するボタン allSelectButton = tkinter.Button(root,text='全て選択',command=allSelect_click) allSelectButton.grid(row=erow,column=0) #1列目 allClearButton = tkinter.Button(root, text='選択解除',command=allClear_click) allClearButton.grid(row=erow, column=1) #1列目 plotButton = tkinter.Button(root, text='make plot',command=make_plot) plotButton.grid(row=erow,column=3) #3列目 #全て選択をチクリック def allSelect_click(): for i in range(len(list_chk)): list_chk[i].set(True) #選択解除をクリック def allClear_click(): for i in range(len(list_chk)): list_chk[i].set(False) #プロット作成ボタンをクリック(現状はチェックの状態を調べるのみ) def make_plot(): global list_keyword global list_chk print('make_plot') num_list = len(list_keyword) list_plot_keyword = [] for ilist in range(num_list): bln = list_chk[ilist].get() #checkbuttonの値 if bln == True: #チェック済みの行 list_plot_keyword.append(list_keyword[ilist]) print(list_plot_keyword) #メイン関数 def main(): global root root = tkinter.Tk() root.title('ブログ検索順位取得ツール') #タイトル root.geometry(str(rt_width)+'x'+str(rt_hgt)) #サイズ #ファイル選択ボタンを作成(コマンド関数は省略) selectButton = tkinter.Button(root, text='File Select',command=select_click) selectButton.grid(row=0,column=1) #順位アップデートボタン(コマンド関数は省略) updateButton = tkinter.Button(root, text='Update Rank',command=update_click) updateButton.grid(row=0,column=2) #ウィンドウを動かす root.mainloop() if __name__ == '__main__': main() |
今回の重要箇所は、106行目からのチェックボックスの配置の部分、141行目からの全選択/全解除ボタンの動作、あとは161行目からのチェックされている行の取得する部分です。
108行目のCheckbuttonの宣言で「variable=」と指定してあげるのがポイント。variableで指定した変数にチェックボックスの値 (True/False) が格納されます。
そして「list_chk」というリストに各チェックボックスの値を保持するようにしました。
チェックボックスの値を設定するには「set(True/False)」(143,148行目)を、チェックボックスの値を取得するには「get()」(162行目)を使用します。
画面下部に配置した「全て選択」ボタンをクリックすると、全ての行のチェックボックスがチェックされます。
「選択解除」ボタンをクリックすると、チェックされている行のチェックボックスが全てチェックを外されるようになっています。
実行結果
上記で作成したコードを動かしてみました。
今回はScreenToGifというツールを使って、動画を操作している動画を撮ってみました。

やりたいこと
- 「全て選択」ボタンで全部のチェックボックスをチェック
- 「選択解除」ボタンで全部のチェックを外す
- チェックボックスを個別にチェックできる(連動していない)
ができています。
また、動画には出していませんが、「make plot」ボタンを押すとコマンド画面にチェックされた行のキーワード一覧が表示されるようになっています。
注意点
複数あるチェックボックスを制御するうえで躓いたところがあります。
最初、チェックボックス設置の部分で、チェックボックスの初期値をループの外で設定していました。
そうすると全てのチェックボックスが連動してしまい、1つチェックを入れると全てチェックされてしまうようになってしまいました。

そのときのコード(抜粋)がこちら。
1 2 3 4 5 6 7 |
bln=tkinter.BooleanVar() bln.set(False) while irow < erow: #リストの数分ループしてLabelとチェックボックスを設置 #チェックボックスの設置 c = tkinter.Checkbutton(frame,variable =bln,width=c0_width,text='',background='white') list_chk.append(bln) #チェックボックスの初期値 |
1,2行目の初期値(bln)の設定をwhile文の中に入れたら、チェックボックスが個別に動作するようになりました。
初期値は全部Falseなんだから、1回宣言すればいいじゃん、と思っていたのですが、そうではないようです。
こんなわけで、だいぶGUIもツールとして様になってきました。
あとはチェックされた行のデータでプロットを作成する機能が必要なので、そこを作っていきます。
んじゃ、また~
コメント