「Pythonでデスクトップアプリを作ろう 後編」 その18
「Pythonでデスクトップアプリを作ろう 後編」 その18前回からだいぶ間隔が空いてしまいましたが、「蔵書管理アプリ」が一応動いたので、ここで一度載せることにします。まだ、写真が表示できるのかなどの確認ができていないので、確認ができたら、また載せたいと思います。# -*- coding: utf-8 -*-"""Created on Sat Jul 1 15:53:05 2023@author: mlupi""""""『日経ソフトウエア』2022年11月号(p.046~p.065)の特集記事 9月号の「特集2 Pythonでデスクトップアプリを作ろう 前編」に引き続いて、 11月号の「特集3 Pythonでデスクトップアプリを作ろう 後編」に挑戦中。なお、基礎については、当ブログの「Pythonことはじめ」などを参照してください。"""# 「Pythonでデスクトップアプリを作ろう 後編」 その18# 標準の「Tkinter」+「SQLite3」を使って# Part3 「蔵書管理アプリ」を作る(p.058~p.065)# ④ 「蔵書管理アプリ」を完成させる(p.062~p.065)#Python#Tkinter#SQLite3#日経ソフトウエア#デスクトップアプリ#データベース#Tkinter#Textウイジェット#collection_manager.py#蔵書管理アプリ#Menuウイジェット#Menu関数#「リサイズ不可」の設定#操作メニューの作成#add_cascade関数#add_command関数#フレームの作成#Frame関数# Menuウイジェットを使う際のコードの流れ# ①ウインドウに「Menu関数」でメニューバーを作る# ②メニューバーに「Menu関数」と「add_cascade関数」でメニューを作る# ③メニューに「add_command関数」で項目を作り、その項目が選択され# た時に事項する関数を設定する。# 併せて、その関数を設定する。## 『日経ソフトウエア』2022年11月号(p.046~p.065)## 目次## Intro Python+Tkinter+SQLiteが一番手軽(p.046~p.047)## Part1 SQLite3の基本をマスターしよう(p.047~p.053)# ① データベースを作成する(p.047~p.048)# ② テーブルを作成する(p.048~p.049)# ③ 「INSERT INTO」文でデータを追加する(p.049~p.050)# ④ データベースやテーブルの削除(p.050)# ⑤ 「SELECT」文でデータを抽出する(p.050~p.051)# ⑥ 「LIKE」演算子であいまい検索を実現する(p.051~p.052)# ⑦ 「ORDER BY」句でデータをソートする(p.052~p.053)# Part2 カレンダー型「メモアプリ」を作る(p.053~p.058)# ① メモアプリのデータベースを作る(p.053p.054)# ② メモを入力・表示する機能(p.054~p.055)# ③ カレンダー型「メモアプリ」のプログラム(p.055~p.057)# ④ 「保存」ボタンがクリックされた時の処理(p.057)# ⑤ 「calender」モジュールを使う(p.057~p.058)# Part3 「蔵書管理アプリ」を作る(p.058~p.065)# ① 「Treeview」ウィジェットの使い方(p.059~p.060)# ② 「Menu」ウィジェットの使い方(p.060~p.061)# ③ データベースを作成する(p.061~p.062)# ④ 「蔵書管理アプリ」を完成させる(p.062~p.065)#========== リスト4●「collection_manager.py」は、ここから# 「蔵書管理アプリ」のプログラム# GUIライブラリーの「Tkinter」モジュールを、「tk」という名前でインポートする。import tkinter as tk# GUIライブラリーの「Tkinter」モジュールから「tkk」ノジュールをインポートする。from tkinter import ttk# 「Tkinter」モジュールから「messagebox」モジュールをインポートする。from tkinter import messagebox# データベースライブラリのインポート(「SQLite3」モジュール)import sqlite3books_list =[]# 登録者情報入力用のEntryin_entry = []sub_win = Nones = ('ISBN', 'タイトル', '著者', '出版社', '発売日', '価格(円)', '画像ファイル')# 書籍情報をデータベースから取得する関数def get_books(): # データベースの作成 # 「sqlite3.connect」関数でデータベースを作成する。 conn = sqlite3.connect('collection.db') # カーソルオブジェクトの作成 # カーソルオブジェクトでデータベースの操作を行う。 cur = conn.cursor() sql = 'SELECT * FROM books' cur.execute(sql) books_list = cur.fetchall() conn.close() return books_list# 一覧の書籍を選択すると呼び出される関数def view_select(event): global img global d_frame slct_items = list_view.selection() s = ('ISBN', 'タイトル', '著者', '出版社', '発売日', '価格(円)') for i in range(len(s)): item_view.item(i, values=(s[i], books_list[int(slct_items[0])][i+1])) try: img = \ tk.PhotoImage(file=books_list[int(slct_items[0])][7]) except tk.TclError: img = '' panel = tk.Label(d_frame, image=img) panel.grid(row=0, column=1)# 登録ボタンをクリックすると呼び出される関数def register(): global sub_win global in_entry # データベースの作成 # 「sqlite3.connect」関数でデータベースを作成する。 conn = sqlite3.connect('collection.db') cur = conn.cursor() sql = """INSERT INTO books(isbn, title, author, publisher, release, price, image) VALUES(?, ?, ?, ?, ?, ?, ?)""" ele = [] for i in range(len(in_entry)): ele.append(in_entry[i].get()) cur.execute(sql, ele) conn.commit() conn.close() messagebox.showinfo('メッセージ', '新規登録しました。') sub_win.destroy() disp()# 新規登録メニューがクリックされると呼び出される関数def save(): global sub_win global in_entry # 書籍情報入力用ウインドウの作成 sub_win = tk.Toplevel() sub_win.geometry("250x250") in_label = [] in_entry.clear() print('for i in range(len(s)):') for i in range(len(s)): in_label.append(tk.Label(sub_win, text=s[i])) in_entry.append(tk.Entry(sub_win, width=20)) register_button = tk.Button(sub_win, text='登録', command=register) for i in range(3): sub_win.columnconfigure(i, weight=1) for i in range(9): sub_win.rowconfigure(i, weight=1) for i in range(7): in_label[i].grid(column=0, row=i) in_entry[i].grid(column=1, row=i, columnspan=2) register_button.grid(column=1, row=8, rowspan=2, sticky=tk.N)# 削除メニューがクリックされると呼び出される関数def delete(): conn = sqlite3.connect('collection.db') cur = conn.cursor() sql = 'DELETE FROM books WHERE id = ?' slct_items = list_view.selection() cur.execute(sql, (books_list[int(slct_items[0])][0],)) conn.commit() conn.close() messagebox.showinfo('メッセージ', 'データを削除しました。') disp()# ウインドウの作成(リサイズ不可) # 「Tk」関数を使って、ウインドウ「(トップレベルtk」ウイジェット)を生成し、 「root」という名前を付ける。# 「Tk」関数は、「Tk」クラスから、ウインドウ(「トップレベルtk」ウイジェット)を生成するための関数。root = tk.Tk()# ウインドウの中身の大きさを指定# ウインドウの中身(タイトルバーなどを除いた内部)の大きさを「geometry」関数で指定する。# ('400x300')は、横サイズ=400ピクセル、縦サイズ=300ピクセルを表しているroot.geometry('400x300') # ウインドウの表示タイトルを「蔵書管理アプリ」にする。root.title('蔵書管理アプリ')# 「リサイズ不可」の設定root.resizable(0, 0)root.grid_rowconfigure(0, weight=1) root.grid_rowconfigure(1, weight=1)root.grid_columnconfigure(0, weight=1)# 「Menu」関数でメニューバーを作成menubar = tk.Menu()root.config(menu=menubar)# 操作メニューを作成menu_command = tk.Menu(menubar, tearoff=0)menubar.add_cascade(label='操作', menu=menu_command)# 操作メニューに「新規登録」「削除」メニューを追加するmenu_command.add_command(label='新規登録', command=save)menu_command.add_separator()menu_command.add_command(label='削除', command=delete)# 一覧用のフレームc_frame = tk.Frame(root)column = ('Title', 'Author', 'Publisher')# 「ttk.Treeview関数」で、「Treeview」ウイジェットを作成list_view = ttk.Treeview(c_frame, columns=column, height=5)# 行が選択されると「<<TreeviewSelect>>イベント」が発生。# このイベントとこのイベントが発生した時に実行されるハンドラ関数をbind関数で紐づけする。list_view.bind('<<TreeviewSelect>>', view_select)# 「heading」関数で表の見出しを設定list_view.heading('#0', text='')list_view.heading('Title', text='タイトル', anchor='center')list_view.heading('Author', text='著者', anchor='center')list_view.heading('Publisher', text='出版社', anchor='center')# 「column」関数で列を設定list_view.column('#0', width=0, stretch='no')list_view.column('Title', anchor='w', width=200)list_view.column('Author', anchor='w', width=80)list_view.column('Publisher', anchor='w', width=80)# 一覧にデータを追加def disp(): # 初期化 list_view.delete(*list_view.get_children()) global books_list books_list = get_books() for i in range(len(books_list)): list_view.insert(parent='', index='end', iid=i , values = (books_list[i][2], books_list[i][3], books_list[i][4])) list_view.grid(row=0, column=0, sticky=tk.NSEW) # 最後のアイテムを選択 list_view.selection_set(i) # 最後のアイテムに移動 list_view.see(i) # スクロールバーの作成 ybar = tk.Scrollbar(c_frame, orient=tk.VERTICAL, width=16, command=list_view.yview) list_view.configure(yscrollcommand=ybar.set) ybar.grid(row=0, column=1, sticky=tk.NSEW) # 一覧の作成disp()# 詳細部分の作成d_frame = tk.Frame(root)d_frame.grid_rowconfigure(0, weight=1)d_frame.grid_columnconfigure(0, weight=1)d_frame.grid_columnconfigure(1, weight=1)column = ('Item', 'Contents')item_view = ttk.Treeview(d_frame, show='tree', columns=column, height = 6)item_view.column('#0', width=0, stretch='no')item_view.column('Item', anchor='w', width=80)item_view.column('Contents', anchor='w', width=140)# 詳細の表示slct_items = list_view.selection()for i in range(len(s)): item_view.insert(parent='', index='end', iid=i, values=(s[i], books_list[int(slct_items[0])][i+1]))item_view.grid(row=0, column=0)try: img = \ tk.PhotoImage(file=books_list[int(slct_items[0])][7])except tk.TclError: img = ''panel = tk.Label(d_frame, image=img)panel.grid(row=0, column=1, sticky=tk.NSEW)c_frame.grid(row=0, column=0)d_frame.grid(row=1, column=0, sticky=tk.NSEW)# ウインドウを表示して、「メインループ」に入る。# 「mainloop(メインループ)」は、「イベントループ」で、ウインドウで発生する# 「イベント」を待っている状態のループ。root.mainloop()#========== リスト4●「collection_manager.py」は、ここまでリスト4●「collection_manager.py」の実行結果新規登録画面新規登録1件新規登録したところ。新規登録の結果。