【python】作りながら覚えるデスクトップアプリ開発|tkinter

python

7ページ目です。

今回は、JSONファイルを読み込んで、カテゴリーのリストをコンボボックスに追加し、カテゴリーを選ぶと該当する名称とURLをそれぞれリストボックスで表示するようにします。

今回使用するJSONファイル

今回は、カテゴリー分けしたJSONファイルを用意します。

{
    "blog": {
        "p1": "https://bliss-growth.com/python_tkinter/",
        "p2": "https://bliss-growth.com/python_tkinter/2/",
        "p3": "https://bliss-growth.com/python_tkinter/3/",
        "p4": "https://bliss-growth.com/python_tkinter/4/"
    },
    "site": {
        "google": "https://www.google.com/",
        "yahoo": "https://www.yahoo.co.jp/",
        "amazon": "https://www.amazon.co.jp/",
        "rakuten": "https://item.rakuten.co.jp/"
    },
    "Photo": {
        "pixabay": "https://pixabay.com/ja/",
        "unsplash": "https://unsplash.com/ja",
        "500px": "https://500px.com/",
        "o-dan": "https://o-dan.net/ja/"
    },
    "illust": {
        "undraw": "https://undraw.co/illustrations",
        "enpitsu-sozai": "https://enpitsu-sozai.com/",
        "vectorshelf": "https://vectorshelf.com/",
        "irasutoya": "https://www.irasutoya.com/",
        "irasuton": "http://www.irasuton.com/"
    }
}

例えば副業をされている方は、案件ごとにカテゴリー分けして管理するということもできますね。

コンボボックスとリストボックスの追加

コンボボックスを使うには、tkinter.ttk をインポートする必要があります。

import tkinter.ttk as ttk

また、ListBox の制御用に tkinter から END をインポートする必要があります。

from tkinter import END

以下がコンボボックスと2つのリストボックスを表示させるコードです。

v = tk.StringVar()
combobox = ttk.Combobox(list_frame,textvariable= v, height=5,values=get_category(), style="office.TCombobox")
combobox.pack(side = tk.TOP)
combobox.bind('<<ComboboxSelected>>', select_combo)
combobox.set('カテゴリーを選択') #初期表示

listbox_name = tk.Listbox(list_frame,borderwidth=3,selectmode='SINGLE',width=10,height=8)
listbox_name.pack(side = tk.LEFT)

listbox_site = tk.Listbox(list_frame,borderwidth=3,selectmode='SINGLE',width=50,height=8)
listbox_site.pack(side = tk.LEFT)
listbox_site.bind("<Double-Button-1>", listbox_event)
listbox_site.bind("<Key-Return>", listbox_event)

コンボボックスにカテゴリーを追加する関数

先ほどのコードで、combobox.bind('<<ComboboxSelected>>', select_combo) が、コンボのカテゴリーを選択した際にイベントが発生し、関数を呼ぶ部分で、以下の select_combo 関数が呼ばれます。

def select_combo(event):
    category = combobox.get()
    print(category)
    data = read_json()  #JSONを辞書へ
    listbox_name.delete(0,END)
    listbox_site.delete(0,END)
    name_list = []
    url_list = []
    for name,url in data[category].items():
        listbox_name.insert(END,name)
        listbox_site.insert(END,url)

処理としては、カテゴリーを選ぶと、そのカテゴリーの名称とURLがリスト表示されるというものです。

URLをブラウザで開く処理

右側のURLリストをダブルクリックか行選択された状態でEnter押下すると、選択されたURLがブラウザの新規タブで開かれます。

def ListBox_LeftDoubClick(event):
    target = listbox_site.get(listbox_site.curselection())
    print(target)
    webbrowser.open_new(target)

listbox_site.bind("<Double-Button-1>", ListBox_LeftDoubClick)
listbox_site.bind("<Key-Return>", ListBox_LeftDoubClick)

これもバインドでイベントを発生させていますね。

今回の全コード

ずいぶん長いコードになってしまいました。

import tkinter as tk
import tkinter.ttk as ttk
from tkinter import END
import webbrowser
import subprocess
import os
import json
from tkinter import messagebox
import re

#色の設定
bg_color1='cornsilk2'
bg_color2='LightSteelBlue1'
bg_color3='#A8BAC3'
bg_color4='#C9AC85'

# ウィンドウの作成
root = tk.Tk()
root.title('python×tkinter')
root.geometry('380x360')
root.resizable(1, 1)
root.config(bg=bg_color3)
root.attributes("-topmost", True)  #常に前面に表示

# frameの作成
frame1 = tk.Frame(root,bg=bg_color2)
list_frame = tk.Frame(root,bg=bg_color1)
frame2 = tk.Frame(root,bg=bg_color4)

frame1.pack(fill=tk.BOTH, expand=True)
list_frame.pack(fill=tk.BOTH, expand=True)
frame2.pack(fill=tk.BOTH, expand=True)

#jsonファイルのパス
json_dir= os.path.join(os.getcwd(),'json')
json_path = os.path.join(json_dir,'sitelist.json')

#正規表現でURLのパターンチェック
pattern = "https?://[\w/:%#\$&\?\(\)~\.=\+\-]+"
    
#関数の作成
def open_json_dir():
    subprocess.Popen(['explorer',json_dir])
    
def read_json():
    #jsonの読み込み
    with open(json_path) as f:
        json_load = json.load(f)
    return json_load
    
def add_dict(data,key,val):
    site_dict = data[combobox.get()]
    site_dict[key]=val  #keyとvalを辞書に追加
    return data

def write_json():
    key = txt_name.get()  #入力値:サイト名
    val = txt_url.get()  #入力値:URL

    if len(key) == 0:    
        # メッセージボックス(警告) 
        messagebox.showwarning('サイト名の確認','サイト名の入力が正しくありません。')
    elif not re.match(pattern, val): #urlか?
        # メッセージボックス(警告) 
        messagebox.showwarning('URLの確認','URLの入力が正しくありません。') 
    elif combobox.get() == "":
        messagebox.showwarning('カテゴリーの確認','カテゴリーが選ばれていません。') 
    else:
        dict_data = read_json()  #JSONを辞書へ
        add_data = add_dict(dict_data,key,val)
        #jsonの書き込み
        with open(json_path, 'w') as f:
            json.dump(add_data, f, indent=4)
        messagebox.showinfo('データ保存','JSONファイルに保存しました。')
        #0文字目~最後まで入力値を削除
        txt_name.delete(0, tk.END)
        txt_url.delete(0, tk.END)

def get_category():
    data = read_json()  #JSONを辞書へ
    c_list=[]
    for category, links in data.items():
        print(f"Category: {category}")
        c_list.append(category)
    return c_list
        
def select_combo(event):
    category = combobox.get()
    print(category)
    data = read_json()  #JSONを辞書へ
    listbox_name.delete(0,END)
    listbox_site.delete(0,END)
    name_list = []
    url_list = []
    for name,url in data[category].items():
        listbox_name.insert(END,name)
        listbox_site.insert(END,url)

def listbox_event(event):
    target = listbox_site.get(listbox_site.curselection())
    print(target)
    webbrowser.open_new(target)
    
#ウィジェットの作成
lbl01 = tk.Label(frame1,text='python_tkinter JSONに追加',bg=bg_color2)
lbl01.pack()

v = tk.StringVar()
val = get_category()

combobox = ttk.Combobox(list_frame,textvariable= v, height=5,values=val, style="office.TCombobox")
combobox.pack(side = tk.TOP)
combobox.bind('<<ComboboxSelected>>', select_combo)
combobox.set('カテゴリーを選択')

listbox_name = tk.Listbox(list_frame,borderwidth=3,selectmode='SINGLE',width=10,height=8)
listbox_name.pack(side = tk.LEFT)

listbox_site = tk.Listbox(list_frame,borderwidth=3,selectmode='SINGLE',width=50,height=8)
listbox_site.pack(side = tk.LEFT)
listbox_site.bind("<Double-Button-1>", listbox_event)
listbox_site.bind("<Key-Return>", listbox_event)

lbl02 = tk.Label(frame1,text='カテゴリーを選びサイト名とURLを入力してください',bg=bg_color2)
lbl02.pack()
lbl_name = tk.Label(frame2,text='サイト名:',bg=bg_color4)
lbl_name.grid(row=0, column=0, padx=5, pady=5)
txt_name = tk.Entry(frame2,width=28)
txt_name.grid(row=0, column=1, padx=5, pady=5)
lbl_url = tk.Label(frame2,text='URL:',bg=bg_color4)
lbl_url.grid(row=1, column=0, padx=5, pady=5)
txt_url = tk.Entry(frame2,width=28)
txt_url.grid(row=1, column=1, padx=5, pady=5)

#ボタンの作成
btn_ini_write = tk.Button(root,text='保存',command=write_json)
btn_ini_write.pack()

button = tk.Button(root,text='JSONフォルダを開く',command=open_json_dir)
button.pack(expand = True)

# ウィンドウのループ処理
root.mainloop()

コードを実行して、カテゴリーで「blog」を選択するとこのようになります。

動作確認

JSONファイルのこのブログのURLですが、P4までになっているので、動作確認として7ページ目まで追加してみましょう。

{
    "blog": {
        "p1": "https://bliss-growth.com/python_tkinter/",
        "p2": "https://bliss-growth.com/python_tkinter/2/",
        "p3": "https://bliss-growth.com/python_tkinter/3/",
        "p4": "https://bliss-growth.com/python_tkinter/4/"
以下省略・・・

コンボボックスで「blog」を選んで

「p5」「https://bliss-growth.com/python_tkinter/5/"」
「p6」「https://bliss-growth.com/python_tkinter/6/"」
「p7」「https://bliss-growth.com/python_tkinter/7/"」

と3項目を追加してみてください。

他のカテゴリーでもいろいろと追加してみるとよいですね。

ところで、新たにカテゴリーを追加したり、カテゴリーやURLを削除する処理も必要ですよね。

次回はそのあたりのカスタマイズをやってみましょう!

では今回はこの辺で終わりにします。

次回をお楽しみに。

コメント

タイトルとURLをコピーしました