tkinterとsqlite3を使ってデータベースを操作できるGUIアプリをつくる

ゲームに利用するデータベースを、GUIで操作できるようにアプリを作成します。

なぜデータベースを使うのか

ゲームにはたくさんのデータがあり、それらが複雑に絡み合あって関係しています。

特にRPGなどは、属性・相性・武器ごとのパラメータやたくさんのモンスターたちのステータスなど、膨大なデータを管理する必要が出てきます。

そんなとき、CSVファイルやTXTファイルで管理するのは限界がありますよね。

例えば、10体いる水属性のモンスターたちを氷属性に修正しようとした場合、CSVファイルでは10体分のデータを修正しなくてはなりません。

詳しい説明は省略しますが、データベースであればその問題を解決することができます。

使用するモジュール

sqlite3

Pythonでは、標準ライブラリとして「sqlite3」が用意されており、インストールの必要なくデータベースを利用することができます。

sqlite3は1つのファイルでデータベースを管理するので移行も簡単です。

tkinter

tkinterも、Pythonの標準ライブラリとして用意されているGUIを作成できるツールです。

細かい仕様などは調べればたくさんの情報が出てくるので、説明を省いてしまうこともあるかと思います。

tkinterでGUI部分を作成する(ログイン画面)

それでは、さっそくtkinterを使って実際にGUI部分を作成します。

まずは、tkinterになれるために簡単なログイン画面を作成してみようと思います。

ルートウィンドウを作成する

import tkinter as tk

まずは、tkinterを使用するためにインポートします。

tkinterは標準ライブラリなので、pipでインストールすることなく使うことができます。

定数などを使用するときにtkinter.〇〇といちいち書くのは長いので、慣習的にtkと略すようです。

class Main():
    def __init__(self):
        self.root = tk.Tk()
        self.root.mainloop()

if __name__ == "__main__":
    Main()

まずは、メインとなるクラスを作成します。

コンストラクタでルートウィンドウを作成します。

ルートウィンドウはtk.Tk()で作成できます。

ここに、ボタンやラベルなどのさまざまなウィジェット(tkinterでは各構成要素をウィジェットと呼びます)を配置することでGUIアプリを作成していきます。

最後のmainloop()関数は、その名のとおり無限ループのための関数です。

これがないとアプリが起動と同時に終了してしまいます。

上記のコードを実行すると、なにもないウィンドウが表示されましたね!

ルートウィンドウの設定

作成したウィンドウに、少し味付けをします。

def __init__(self):
    self.root = tk.Tk()

    self.root.title("Jizo Client")
    self.root.geometry("320x240")
    self.root.resizable(0, 0)

    self.root.mainloop()

先ほどのコードの、mainloop()関数の前に、コードをいくつか追加します。

ウィンドウのタイトルを設定します。アプリの名称などが一般的かと思老いますので、ここでは「Jizo Client」とします。

self.root.title("Jizo Client")

ウィンドウのサイズを指定します。

とりあえずログイン画面だけであればそんなに大きさは必要ないので小さめに設定します。

あとから変更も可能です。

self.root.geometry("320x240")

続いて、ユーザーがウィンドウのサイズを変更することを許可するかどうかを設定します。

self.root.resizable(0, 0)

今回は、縦にも横にも変更を許可しないことにしました。

resizable(横, 縦)で、縦横のサイズを固定するかどうか設定できます。

縦のみ許可するのであれば

self.root.resizable(0, 1)

のように指定します。

ここまでのコードを実行すると、上のようなウィンドウが表示されます。

ラベル・ボタンを作成する

続いては、ラベルとボタンを作成します。

各ウィジェットの引数については、説明を省略します。

title = tk.Label(self.root, text="Jizo Client", font=("", 24, "bold"))

ラベルを作成するには、tk.Label()を使用します。

ウィジェットの引数で共通しているのは、配置する親ウィジェットを指定するところです。

今回はルートウィンドウであるself.rootに配置するので、第一引数にself.rootを指定します。

続いてログインボタンを作成します。

button = tk.Button(self.root, text="ログイン")

tk.Button()を使用し、親ウィジェットにself.rootをします。

textは、ボタンに表示するテキストです。

import tkinter as tk

class Main():
    def __init__(self):
        self.root = tk.Tk()

        self.root.title("Jizo Client")
        self.root.geometry("320x240")
        self.root.resizable(0, 0)

        title = tk.Label(self.root, text="Jizo Client", font=("", 24, "bold"))
        button = tk.Button(self.root, text="ログイン")

        self.root.mainloop()

if __name__ == "__main__":
    Main()

全体のコードは、このようになりました。

せてこれを実行してみましょう!

あれ?先ほどと同じ画面ですね。

そうなのです。tkinterでは、ウィジェットをただ作成しただけではアプリ上に表示されず、配置する必要があります。

作成したウィジェットを配置する

tkinterでウィジェットを配置するためには、grid、pack、placeの三つのメソッドが用意されています。

これらはそれぞれに異なる特徴を持っており、同じフレーム上で複数のメソッドを混在させることはできません。

あまり深く考えても最初は混乱するだけなので、とりあえずpackを使っていこおうと思います。

title = tk.Label(self.root, text="Jizo Client", font=("", 24, "bold"))
button = tk.Button(self.root, text="ログイン")

title.pack()
button.pack()

packを使って配置してみました。

簡単ですね。

これで実行してみると、今度こそウィジェットが表示されます。

packは、このように上から積み上げていくようなイメージでウィジェットを配置していきます。

このままだと見にくいので、packの引数にオプションを設定して、見た目を整えていきます。

title = tk.Label(self.root, text="Jizo Client", font=("", 24, "bold"))
button = tk.Button(self.root, text="ログイン")
copy = tk.Label(self.root, text="by Jizo Games")

title.pack(pady=30)
button.pack(ipadx=10, ipady=5, pady=5)
copy.pack(side=tk.BOTTOM, pady=5)

上記のコードを実行すると、以下のようになりました(ついでにコピーライト表記も追加しました)。

だいぶアプリっぽくなりました。

オプションで設定しているpadx、padyは、ウィジェットの外側の余白を設定するためのものです。

padxは左右の、padyは上下の余白を設定することができます。

ウィジェットの内側の余白は、ipadx、ipadyで設定します。

また、sideオプションを設定することで、ウィジェットを親ウィジェットのどこを基準に配置するか設定できます。

今回、コピーライト表記にside=tk.BOTTOMというオプションを設定しています。

左から配置したい場合はtk.LEFTを、右から配置したい場合はtk.RIGHTを指定します。

ソースコードのダウンロード