Python初心者がブログの検索順位取得ツールを作っています。
今まで、キーワードを検索してファイルに書き出す部分、ちょっとしたGUIの作成等を行ってきました。
今回は、画面に表示された表のチェックボックス(Checkbutton)の制御部分を作成していきます。
- 複数行にわたって配置されたチェックボックスが個々に動作すること
- 全部一括選択/全部一括解除ができること
- チェックされた行のキーワードを取得できること
を目標にしていきます。
現状の画面は以下のとおり。
前回はキーワードやタイトルをソースに埋め込んでいましたが、Excelファイルを読み込めるように改良しました。
また、必要なボタンも追加し、画面案に近い画面が出せるようになっています。
複数チェックボックスを制御するソースコード
Python/tkinterで複数のチェックボックス(Checkbutton)の動作を作りこんでみました。
チェックボックス(Checkbutton)に関連する箇所のみ載せます。
ちなみに、ソースの行が多くなってきたので、今回から関数化させてみました。
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つチェックを入れると全てチェックされてしまうようになってしまいました。
そのときのコード(抜粋)がこちら。
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もツールとして様になってきました。
あとはチェックされた行のデータでプロットを作成する機能が必要なので、そこを作っていきます。
んじゃ、また~
おススメのプログラミング独学方法はこちらの記事にまとめました!
コメント