【Python/tkinter】ログイン機能付きアプリを作成する

ログイン機能付きアプリの開発方法解説ページのアイキャッチ

今回は Python の tkinter でログイン機能付きのアプリのを作成していこうと思います。

作成するアプリ

まずは、このページで作成していくログイン機能付きアプリについて説明していきます。

アプリ起動画面

今回作成するアプリでは、起動時に下の図のようなログイン画面を表示します。

ログイン機能付きアプリの起動画面

スポンサーリンク

ユーザー名とパスワード入力

このログイン画面では「ユーザー名」と「パスワード」を入力することができるようにウィジェットを配置しています。

ユーザー名とパスワードの入力ウィジェット

ユーザー名とパスワードの登録

「ユーザー名」と「パスワード」を入力した後に「登録」ボタンを押せば、入力したユーザー名とパスワードが登録されます

ログイン

また、「ユーザー名」と「パスワード」を入力した後に「ログイン」ボタンを押せば、下記を満たす場合にはログインに成功します。

  • 入力した「ユーザー名」がすでに登録済
  • 入力した「パスワード」と登録済みの「パスワード」が一致

スポンサーリンク

ログイン失敗時の動作

ログインに失敗した場合は、下の図のような画面が表示された後に再度ログイン画面が表示されます。

ログイン失敗時の画面

ログイン成功時の動作

ログインに成功した場合は画面が遷移し、アプリのメイン機能画面が表示されます。

といっても、今回の解説では「ログイン画面」に重点を置いていますので、メイン機能画面はただ単に下の図のようにメッセージを表示するだけになります。

ログイン後の画面

このメイン機能をゲームなどにすれば「ログインしないとプレイできないゲームアプリ」や「ログインユーザーに応じて所持キャラや所持アイテムを変更するゲームアプリ」などを作成することも可能です。

ユーザー名とパスワードの管理

この「ログイン」機能を提供するためには登録された「ユーザー名」と「パスワード」のユーザー情報を管理しておく必要があります。

実際にはこれらはサーバー等で管理しておき、ログイン実行時にサーバーに問い合わせて照合する方が良いのですが、サーバーを準備するのは大変です。

ですので、今回は自身の PC のみで簡単にログイン機能を実現できるように下記の二つの方法でユーザー情報を管理していきたいと思います。

  • CSV ファイル
  • データベース

スポンサーリンク

ログイン機能付きアプリの作り方

ではここまで解説してきたログイン機能付きアプリの作り方を解説していきたいと思います。

ログイン機能付きアプリのクラス構成

ログイン機能付きアプリのスクリプトとしては大きく分けて下記の2つのクラスを用意します。

  • メイン機能を提供するクラス
  • ログイン機能を提供するクラス(Login クラス)

特に今回ポイントになるのはログイン機能を提供する Login クラスです。

このクラスではユーザーからのユーザー名やパスワードの入力を受け付け、その受け付けた情報に基づいてログイン成功・ログイン失敗を判定します。

そして、ログイン成功時にはメイン機能を提供するクラスの処理を開始するように制御するようにします。

逆にログインが成功していない状態では、メイン機能を提供するクラスの処理が開始されないようにする必要があります。

メイン機能の準備

ですので、メイン機能を提供するクラスでは、インスタンス生成時(コンストラクタ実行時)には処理を開始せず、別途処理を開始するためのメソッド(start)を用意するようにします。

そして、ログイン成功時には Login クラスからこの start メソッドを実行するようにします。

2つのクラスの関係図

あとは、start メソッドが実行された際にメインの機能が実行されるようにクラスを作成すれば良いです。例えばメイン機能がゲームであれば、ゲームを開始する処理を start メソッドに実装すれば良いです。

今回は簡単のため、メインの機能は「ユーザー名を表示すること」だけにしています。

このメイン機能を提供するクラスの一例は下記のようになります。

メイン機能を提供するクラス
class MainAppli():
	'''アプリ本体'''

	def __init__(self, master):
		'''
			コンストラクタ
			master:ログイン画面を配置するウィジェット
		'''

		self.master = master

		# ログイン完了していないのでウィジェットは作成しない

	def start(self, login_name):
		'''アプリを起動する'''

		# ログインユーザー名を表示する
		self.message = tkinter.Label(
			self.master,
			font=("",40),
			text=login_name + "でログイン中"
		)
		self.message.pack()

		# 必要に応じてウィジェット作成やイベントの設定なども行う

スポンサーリンク

ウィジェットの作成と配置

ここからはログイン機能を提供する Login クラスを作成していきます。

まずは最初にログイン画面っぽくウィジェットの作成と配置を行っていきます。

今回紹介するスクリプトでは下の図のようなログイン画面を作成しますので、

ログイン画面のウィジェット

下の図のようにウィジェットの作成と配置を行います。

ログイン画面のウィジェット配置

ウィジェットはそれぞれ grid メソッドにより配置しています。

ウィジェットの配置に関しては下記ページで詳細を解説していますので、必要に応じてこちらも参照していただければと思います。

ウィジェット配置方法解説ページのアイキャッチTkinterの使い方:ウィジェットの配置(pack・grid・place)

tkinter.Entry クラスではユーザーから文字列の入力を受け付けることができます。パスワード入力する tkinter.Entry クラスのインスタンス生成時に、引数 show="*" を指定することで、入力された文字列を “*” で隠すことができます。

パスワード表示

ウィジェットの作成と配置を行う create_widgets メソッドは下記のようになります。

ウィジェットの作成と配置
def create_widgets(self):
	'''ウィジェットを作成・配置する'''

	# ユーザー名入力用のウィジェット
	self.name_label = tkinter.Label(
		self.master,
		text="ユーザー名"
	)
	self.name_label.grid(
		row=0,
		column=0
	)
	self.widgets.append(self.name_label)

	self.name_entry = tkinter.Entry(self.master)
	self.name_entry.grid(
		row=0,
		column=1
	)
	self.widgets.append(self.name_entry)

	# パスワード入力用のウィジェット
	self.pass_label = tkinter.Label(
		self.master,
		text="パスワード"
	)
	self.pass_label.grid(
		row=1,
		column=0
	)
	self.widgets.append(self.pass_label)

	self.pass_entry = tkinter.Entry(
		self.master,
		show="*"
	)
	self.pass_entry.grid(
		row=1,
		column=1
	)
	self.widgets.append(self.pass_entry)

	# ログインボタン
	self.login_button = tkinter.Button(
		self.master,
		text="ログイン",
		command=self.login
	)
	self.login_button.grid(
		row=2,
		column=0,
		columnspan=2,
	)
	self.widgets.append(self.login_button)

	# 登録ボタン
	self.register_button = tkinter.Button(
		self.master,
		text="登録",
		command=self.register
	)
	self.register_button.grid(
		row=3,
		column=0,
		columnspan=2,
	)
	self.widgets.append(self.register_button)

	# ウィジェット全てを中央寄せ
	self.master.grid_anchor(tkinter.CENTER)

下記のようにインスタンスをリスト widgets に参照させるようにしていますが、これはログイン画面の非表示・再表示を行う際に各ウィジェットのインスタンスを参照するためです。

ウィジェットの管理リスト
self.widgets.append(self.pass_entry)

このリスト widgets は後述するログイン失敗時の処理ログイン成功時の処理で使用します。

ユーザー情報の登録

「登録」ボタンが押された時には、ユーザー情報の登録を行います。

このユーザー情報の管理方法としては、まず CSV ファイルで管理する方法を紹介していきます。

ユーザー情報の登録は、CSV ファイルにユーザー情報を紐付けて追記することで実現します。

より具体的には、Entry ウィジェットに入力された文字列(ユーザー名とパスワード)を取得し、その取得したユーザー名とパスワードを 紐づけて CSV ファイルに追記することでユーザー情報の登録を行います。

ユーザー情報のCSVファイルへの追記

この CSV ファイルは Python 標準モジュールの csv を利用することで簡単に扱うことができます。

ユーザー情報を登録する register メソッドの例は下記のようになります。

ユーザー情報の登録
def register(self):
	'''ユーザー名とパスワードを登録する'''

	# 入力された情報をEntryウィジェットから取得
	username = self.name_entry.get()
	password = self.pass_entry.get()

	# 取得した情報をCSVに追記
	f = open(CSV_FILE, 'a')
	csv_data = csv.writer(f)

	csv_data.writerow([username, password])
	f.close()

self.name_entry はユーザー名を self.pass_entry はパスワードをそれぞれ入力するウィジェットのインスタンスで、これらのインスタンスに get メソッドを実行させることで入力された文字列を取得することができます。

さらに、この取得した情報を下記により CSV ファイルの最後に追記しています。

CSVへの追記
# 取得した情報をCSVに追記
f = open(CSV_FILE, 'a')
csv_data = csv.writer(f)

csv_data.writerow([username, password])
f.close()

writerow メソッドを実行することで、csv ファイルに指定されたリストの各要素を同じ行に書き込むことができます。

CSV ファイルの最後に追記するためには open の第2要素に 'a' を指定する必要があります。

CSV ファイルがまだ存在しない場合は、自動的に作成されます。

register メソッドを実行することで、下記のような CSV ファイルを作成していくことができます。

userA, aiueo
userB, kakikukeko
userC, sashisuseso

各行の第 0 要素がユーザー名、第 1 要素がパスワードになります。

register メソッドが実行されるたびに CSV ファイルの最後に入力されたユーザー情報がどんどん追記されていきます。

userA, aiueo
userB, kakikukeko
userC, sasisuseso
userD, tatituteto

ログイン実行

「ログイン」ボタンが押された時には、ログインの実行を行います。

まず Entry クラスのウィジェットに入力されたユーザー名とパスワードを取得し、ユーザー名がユーザー情報を管理している CSV ファイルに登録されているかどうかを確認します。

登録されている場合は、そのユーザー名が登録された時に一緒に登録されたパスワードと、ウィジェットから取得したパスワードが一致するかどうかを確認します。

パスワードが一致する場合はログイン成功時の処理、ユーザー名が登録されていない or パスワードが一致しない場合はログイン失敗時の処理を行います。

これらの処理を行う login メソッドの一例は下記のようになります。

ログイン
def login(self):
	'''ログインを実行する'''

	# 入力された情報をEntryウィジェットから取得
	username = self.name_entry.get()
	password = self.pass_entry.get()

	# 登録済みのユーザー名とパスワードを取得
	try:
		f = open(CSV_FILE)
	except FileNotFoundError:
		self.fail()
		return

	csv_data = csv.reader(f)
	
	# 登録されているものと一致するかを確認
	for user in csv_data:
		if user[0] == username:
			if user[1] == password:
				# 登録されているユーザー名・パスワードと一致する場合

				# ログインユーザー名を設定
				self.login_name = username
				self.success()
				break
	else:
		# 入力された情報が登録されていないば場合

		self.fail()

	f.close()

入力されているユーザー名やパスワードを取得するのは register メソッドと同様ですが、ログイン時にはこの取得したユーザー名やパスワードと照合するために CSV ファイルの読み込みを行う必要があります。

これは下記のように csv モジュールを行うことで行なっています。これにより CSV ファイル全体が読み込まれます。

さらに、下記のように for 文を記述することで、CSV ファイルの一行分の要素がリスト形式で順々に取得することができます。

CSVの行単位のループ処理
for user in csv_data:

register メソッドでは、下記のような形式で各行の第 0 要素にはユーザー名、第 1 要素にはパスワードが格納されるように CSV への追記を行っています。

userA, aiueo
userB, kakikukeko
userC, sashisuseso

for 文内の userもこれと同様に、第 0 要素にユーザー名、第 1 要素にパスワードとなるリストとなります。

リストの内容
['ユーザー名', 'パスワード']

ですので、login で各行の user[0]user[1] それぞれを入力されたユーザー名とパスワードと照合していくことで、入力されたユーザー名が既に登録されており、さらにパスワードが一致しているかどうかを確認することができます。

上記の login メソッドでは、ログインに失敗した場合(入力されたユーザー名が登録されていない場合や、パスワードが一致しない場合)は、fail メソッドによりログイン失敗時の処理を行うようにしています。

ログイン成功した場合は、success メソッドによりログイン成功時の処理を行っています。

スポンサーリンク

ログイン失敗時の処理

ログイン失敗時の処理を行う fail メソッドの一例は下記のようになります。

ログイン失敗時の処理
def fail(self):
	'''ログイン失敗時の処理を行う'''

	# 表示中のウィジェットを一旦削除
	for widget in self.widgets:
		widget.destroy()

	# "ログインできませんでした"メッセージを表示
	self.message = tkinter.Label(
		self.master,
		text="ログインに失敗しました",
		font=("",40)
	)
	self.message.place(
		x=self.master.winfo_width() // 2,
		y=self.master.winfo_height() // 2,
		anchor=tkinter.CENTER
	)

	# 少しディレイを入れてredisplayを実行
	self.master.after(1000, self.redisplay)

この fail メソッドでは、主に下記のことを行っています。

  • ログイン画面を非表示にする
  • ログイン失敗したことをメッセージ表示する
  • 一定時間後にメッセージを非表示にし、ログイン画面を再表示する

ログイン画面を非表示にする

ログイン画面の非表示は、ログイン画面を構成するウィジェットを全て削除することで実現しています。

ログイン画面の非表示
# 表示中のウィジェットを一旦削除
for widget in self.widgets:
	widget.destroy()

ウィジェットの削除は、そのインスタンスに destroy メソッドを実行することで行うことができます。

各ウィジェットのインスタンスは、ウィジェットの作成と配置で作成したリスト widgets に格納されていますので、この widgets の全要素に destroy メソッドを実行させればログイン画面を非表示にしています。

ログイン失敗したことをメッセージ表示する

ログイン画面を非表示にした後は「ログインに失敗したこと」をユーザーに伝えるメッセージを画面に表示します。

これは単純に tkinter の Label クラスのインスタンスを生成・配置することで実現することができます。

ログイン失敗メッセージの表示
# "ログインに失敗しました"メッセージを表示
self.message = tkinter.Label(
	self.master,
	text="ログインに失敗しました",
	font=("",40)
)
self.message.place(
	x=self.master.winfo_width() // 2,
	y=self.master.winfo_height() // 2,
	anchor=tkinter.CENTER
)

一定時間後にメッセージを非表示にし、ログイン画面を再表示する

ログイン失敗後は再度ログインをユーザーが試行できるように、先ほど表示したメッセージを非表示にし、再度ログイン画面を表示します。

すぐに表示するとユーザーがメッセージを読む時間もありませんので、after メソッドを利用して 1000 ms 遅らせてからメッセージの非表示とログイン画面の表示を行うようにしています。

afterメソッドの実行
# 少しディレイを入れてredisplayを実行
self.master.after(1000, self.redisplay)

これにより after メソッド実行してから 1000 ms 経過した後に下記の redisplay メソッドが実行されます。

ログイン画面の再表示
def redisplay(self):
	'''ログイン画面を再表示する'''

	# "ログインできませんでした"メッセージを削除
	self.message.destroy()

	# ウィジェットを再度作成・配置
	self.create_widgets()

redisplay メソッドでは Label ウィジェットの削除によるメッセージの非表示と、create_widgets メソッド実行によるウィジェットの作成と配置を行っています。

after メソッドについて詳しく知りたい方は是非下記のページも読んでみてください。

Tkinterの使い方:after で処理を「遅らせて」or 処理を「定期的」に実行する

ログイン成功時の処理

ログイン失敗時の処理を行う success メソッドの一例は下記のようになります。

ログイン成功時の処理
def success(self):
	'''ログイン成功時の処理を実行する'''

	# 表示中のウィジェットを一旦削除
	for widget in self.widgets:
		widget.destroy()

	# "ログインに成功しました"メッセージを表示
	self.message = tkinter.Label(
		self.master,
		text="ログインに成功しました",
		font=("",40)
	)
	self.message.place(
		x=self.master.winfo_width() // 2,
		y=self.master.winfo_height() // 2,
		anchor=tkinter.CENTER
	)

	# 少しディレイを入れてredisplayを実行
	self.master.after(1000, self.main_start)

この success メソッドでは、主に下記のことを行っています。

  • ログイン画面を非表示にする
  • ログイン失敗したことをメッセージ表示する
  • 一定時間後にメッセージを非表示にし、メイン機能をスタートする

上記2つに関しては fail メソッドと同様ですので説明は省略します。

一定時間後にメッセージを非表示にし、メイン機能をスタートする

これに関しても after メソッドを利用して一定時間送らせた後に処理を行う点は fail メソッドと同様です。

ただし success メソッドでは、after メソッドで下記の main_start メソッドを実行するようにしています。

メイン機能のスタート
def main_start(self):
	'''アプリ本体を起動する'''

	# "ログインに成功しました"メッセージを削除
	self.message.destroy()

	# アプリ本体を起動
	self.main.start(self.login_name)

main は、メイン機能の準備で作成した「アプリのメイン機能を提供するクラス」のインスタンスで、start メソッドはこのクラスに用意したメイン機能をスタートするメソッドです。

ですので、ログインに成功すると success メソッドからメイン機能を提供するクラスが起動され、メイン機能が実行されることになります。

以上が、ログイン機能付きアプリの作り方になります。

ログイン機能付きアプリのサンプルスクリプト

ではここまで解説してきた内容を踏まえたログイン機能付きアプリのサンプルスクリプトを紹介していきたいと思います。

スポンサーリンク

スクリプト

ログイン機能付きアプリのサンプルスクリプトは下記のようになります。

ログイン機能付きアプリ
import csv
import tkinter

# ログイン情報を管理するCSVへのファイルパス
CSV_FILE = "login.csv"

class Login():
	'''ログインを制御するクラス'''

	def __init__(self, master, main):
		'''コンストラクタ
			master:ログイン画面を配置するウィジェット
			body:アプリ本体のクラスのインスタンス
		'''

		self.master = master

		# アプリ本体のクラスのインスタンスをセット
		self.main = main

		# ログイン関連のウィジェットを管理するリスト
		self.widgets = []

		# ログイン画面のウィジェット作成
		self.create_widgets()

	def create_widgets(self):
		'''ウィジェットを作成・配置する'''

		# ユーザー名入力用のウィジェット
		self.name_label = tkinter.Label(
			self.master,
			text="ユーザー名"
		)
		self.name_label.grid(
			row=0,
			column=0
		)
		self.widgets.append(self.name_label)

		self.name_entry = tkinter.Entry(self.master)
		self.name_entry.grid(
			row=0,
			column=1
		)
		self.widgets.append(self.name_entry)

		# パスワード入力用のウィジェット
		self.pass_label = tkinter.Label(
			self.master,
			text="パスワード"
		)
		self.pass_label.grid(
			row=1,
			column=0
		)
		self.widgets.append(self.pass_label)

		self.pass_entry = tkinter.Entry(
			self.master,
			show="*"
		)
		self.pass_entry.grid(
			row=1,
			column=1
		)
		self.widgets.append(self.pass_entry)

		# ログインボタン
		self.login_button = tkinter.Button(
			self.master,
			text="ログイン",
			command=self.login
		)
		self.login_button.grid(
			row=2,
			column=0,
			columnspan=2,
		)
		self.widgets.append(self.login_button)

		# 登録ボタン
		self.register_button = tkinter.Button(
			self.master,
			text="登録",
			command=self.register
		)
		self.register_button.grid(
			row=3,
			column=0,
			columnspan=2,
		)
		self.widgets.append(self.register_button)

		# ウィジェット全てを中央寄せ
		self.master.grid_anchor(tkinter.CENTER)

	def login(self):
		'''ログインを実行する'''

		# 入力された情報をEntryウィジェットから取得
		username = self.name_entry.get()
		password = self.pass_entry.get()

		# 登録済みのユーザー名とパスワードを取得
		try:
			f = open(CSV_FILE)
		except FileNotFoundError:
			self.fail()
			return

		csv_data = csv.reader(f)
		
		# 登録されているものと一致するかを確認
		for user in csv_data:
			if user[0] == username:
				if user[1] == password:
					# 登録されているユーザー名・パスワードと一致する場合

					# ログインユーザー名を設定
					self.login_name = username
					self.success()
					break
		else:
			# 入力された情報が登録されていないば場合

			self.fail()

		f.close()

	def register(self):
		'''ユーザー名とパスワードを登録する'''

		# 入力された情報をEntryウィジェットから取得
		username = self.name_entry.get()
		password = self.pass_entry.get()

		# 取得した情報をCSVに追記
		f = open(CSV_FILE, 'a')
		csv_data = csv.writer(f)

		csv_data.writerow([username, password])
		f.close()

	def fail(self):
		'''ログイン失敗時の処理を行う'''

		# 表示中のウィジェットを一旦削除
		for widget in self.widgets:
			widget.destroy()

		# "ログインに失敗しました"メッセージを表示
		self.message = tkinter.Label(
			self.master,
			text="ログインに失敗しました",
			font=("",40)
		)
		self.message.place(
			x=self.master.winfo_width() // 2,
			y=self.master.winfo_height() // 2,
			anchor=tkinter.CENTER
		)

		# 少しディレイを入れてredisplayを実行
		self.master.after(1000, self.redisplay)

	def redisplay(self):
		'''ログイン画面を再表示する'''

		# "ログインできませんでした"メッセージを削除
		self.message.destroy()

		# ウィジェットを再度作成・配置
		self.create_widgets()

	def success(self):
		'''ログイン成功時の処理を実行する'''

		# 表示中のウィジェットを一旦削除
		for widget in self.widgets:
			widget.destroy()

		# "ログインに成功しました"メッセージを表示
		self.message = tkinter.Label(
			self.master,
			text="ログインに成功しました",
			font=("",40)
		)
		self.message.place(
			x=self.master.winfo_width() // 2,
			y=self.master.winfo_height() // 2,
			anchor=tkinter.CENTER
		)

		# 少しディレイを入れてredisplayを実行
		self.master.after(1000, self.main_start)

	def main_start(self):
		'''アプリ本体を起動する'''

		# "ログインに成功しました"メッセージを削除
		self.message.destroy()

		# アプリ本体を起動
		self.main.start(self.login_name)
		
class MainAppli():
	'''アプリ本体'''

	def __init__(self, master):
		'''
			コンストラクタ
			master:ログイン画面を配置するウィジェット
		'''

		self.master = master

		# ログイン完了していないのでウィジェットは作成しない

	def start(self, login_name):
		'''アプリを起動する'''

		# ログインユーザー名を表示する
		self.message = tkinter.Label(
			self.master,
			font=("",40),
			text=login_name + "でログイン中"
		)
		self.message.pack()

		# 必要に応じてウィジェット作成やイベントの設定なども行う


app = tkinter.Tk()

# メインウィンドウのサイズ設定
app.geometry("600x400")

# アプリ本体のインスタンス生成
main = MainAppli(app)

# ログイン管理クラスのインスタンス生成
login = Login(app, main)

app.mainloop()

アプリの設定

下記で、ユーザーのユーザー名とパスワードを保存する CSV ファイルのファイルパスを設定することができます。

CSVファイルのパス
# ログイン情報を管理するCSVへのファイルパス
CSV_FILE = "login.csv"

アプリの動作確認

スクリプトを実行すると下図のような画面のアプリが起動します。

ログイン機能付きアプリの起動画面

username 欄にユーザー名、password 欄にパスワードを入力して「登路」ボタンを押すことで、ユーザー情報を登録することができます。

登録済みのユーザー名とパスワードを入力してから「ログイン」ボタンを押せば、ログインに成功して「ログインに成功しました」メッセージ表示後、下の図のようなアプリのメイン機能の画面が表示されます。

ログイン後の画面

登録済みでないユーザー名やパスワードを入力して「ログイン」ボタンを押した場合は、下の図のように「ログインに失敗しました」メッセージが表示され、再度ログイン画面が表示されます。

ログイン失敗時の画面

スポンサーリンク

ユーザー情報をデータベースで管理する

ここまではユーザー情報を CSV ファイルで管理していましたが、次はユーザー情報をデータベースで管理する方法について解説していきたいと思います。

sqlite3 をインポート

Python3 においてはデータベースを利用する sqlite3 が標準モジュールとなっています。今回は簡単のために、この sqlite3 を利用してデータベースによるユーザー情報の管理を実現していきたいと思います。

前述の通り、sqlite3 は標準モジュールですので、Python3 においては単に sqlite3 をインポートするだけで sqlite3 の機能を利用することができます。

sqlite3のインポート
import sqlite3

データベースの操作

sqlite3 でのデータベースの操作は基本的に下記の流れになります。

  • connect 関数でデータベースへのコネクションを生成する
  • コネクションに cursor メソッドを実行させてカーソルを生成する
  • カーソルに execute メソッドを実行させてデータベース操作を行う
    • データベースにテーブルを作成する
    • テーブルに情報を追記する(ユーザー名とパスワード登録時)
    • テーブルから情報を取得する(ログイン時)
  • (必要に応じて)コネクションに commit メソッドを実行させてテーブルの情報を保存する
  • コネクションに close メソッドを実行させてデータベース接続を終了する

execute メソッドの引数には実行する SQL 文を指定する必要があります。

sqlite3 の使い方などは下記ページなどが参考になると思います。

sqlite3入門

スポンサーリンク

データベースでユーザー情報を登録するサンプルスクリプト

ログイン機能付きアプリのサンプルスクリプトで紹介したスクリプトではユーザー情報を CSV ファイルで管理しましたが、今度はデータベースでユーザー情報を管理するようにしたサンプルスクリプトを紹介したいと思います。

データベースを利用したスクリプト
import csv
import tkinter
import sqlite3

# ユーザー情報を登録するDB名
DB_NAME = "user.db"

class Login():
	'''ログインを制御するクラス'''

	def __init__(self, master, main):
		'''コンストラクタ
			master:ログイン画面を配置するウィジェット
			body:アプリ本体のクラスのインスタンス
		'''

		self.master = master

		# アプリ本体のクラスのインスタンスをセット
		self.main = main

		# ログイン関連のウィジェットを管理するリスト
		self.widgets = []

		# ログイン画面のウィジェット作成
		self.create_widgets()


	def create_widgets(self):
		'''ウィジェットを作成・配置する'''

		# ユーザー名入力用のウィジェット
		self.name_label = tkinter.Label(
			self.master,
			text="ユーザー名"
		)
		self.name_label.grid(
			row=0,
			column=0
		)
		self.widgets.append(self.name_label)

		self.name_entry = tkinter.Entry(self.master)
		self.name_entry.grid(
			row=0,
			column=1
		)
		self.widgets.append(self.name_entry)

		# パスワード入力用のウィジェット
		self.pass_label = tkinter.Label(
			self.master,
			text="パスワード"
		)
		self.pass_label.grid(
			row=1,
			column=0
		)
		self.widgets.append(self.pass_label)

		self.pass_entry = tkinter.Entry(
			self.master,
			show="*"
		)
		self.pass_entry.grid(
			row=1,
			column=1
		)
		self.widgets.append(self.pass_entry)

		# ログインボタン
		self.login_button = tkinter.Button(
			self.master,
			text="ログイン",
			command=self.login
		)
		self.login_button.grid(
			row=2,
			column=0,
			columnspan=2,
		)
		self.widgets.append(self.login_button)

		# 登録ボタン
		self.register_button = tkinter.Button(
			self.master,
			text="登録",
			command=self.register
		)
		self.register_button.grid(
			row=3,
			column=0,
			columnspan=2,
		)
		self.widgets.append(self.register_button)

		# ウィジェット全てを中央寄せ
		self.master.grid_anchor(tkinter.CENTER)

	def login(self):
		'''ログインを実行する'''

		# 入力された情報をEntryウィジェットから取得
		username = self.name_entry.get()
		password = self.pass_entry.get()

		if self.check(username, password):
			# ログインユーザー名を設定
			self.login_name = username

			self.success()
		else:
			self.fail()

	def check(self, username, password):
		'''
			入力されたユーザー情報が登録済みか確認する
			username:ユーザー名
			password:パスワード
			返却値:True(登録済み),False(未登録)
		'''

		# DB接続
		self.connection = sqlite3.connect(DB_NAME)
		self.cursor = self.connection.cursor()

		# まだDBにテーブルがなければ作成
		self.cursor.execute(
			"CREATE TABLE IF NOT EXISTS user_info (username text, password text)"
		)

		# ユーザー情報を取得
		check = self.cursor.execute(
			"SELECT * FROM user_info WHERE username=? and password=?",
			[username, password]
		)

		# 取得したユーザー情報をリスト化
		user_list = check.fetchall()

		# ユーザー情報の有無をチェック
		if user_list:
			ret = True
		else:
			ret = False

		# DB接続をクローズ
		self.connection.close()

		# ユーザー情報が登録されているかどうかを返却
		return ret

	def save(self, username, password):
		'''
			入力されたユーザー情報を登録する
			username:ユーザー名
			password:パスワード
		'''

		# DB接続
		self.connection = sqlite3.connect(DB_NAME)
		self.cursor = self.connection.cursor()

		# まだDBにテーブルがなければ作成
		self.cursor.execute(
			"CREATE TABLE IF NOT EXISTS user_info (username text, password text)"
		)

		# 取得した情報をDBに追記
		self.cursor.execute("INSERT INTO user_info VALUES (?,?)", [username, password])

		# DBを保存
		self.connection.commit()

		# DB接続をクローズ
		self.connection.close()


	def register(self):
		'''ユーザー名とパスワードを登録する'''

		# 入力された情報をEntryウィジェットから取得
		username = self.name_entry.get()
		password = self.pass_entry.get()

		self.save(username, password)

	def fail(self):
		'''ログイン失敗時の処理を行う'''

		# 表示中のウィジェットを一旦削除
		for widget in self.widgets:
			widget.destroy()

		# "ログインに失敗しました"メッセージを表示
		self.message = tkinter.Label(
			self.master,
			text="ログインできませんでした",
			font=("",40)
		)
		self.message.place(
			x=self.master.winfo_width() // 2,
			y=self.master.winfo_height() // 2,
			anchor=tkinter.CENTER
		)

		# 少しディレイを入れてredisplayを実行
		self.master.after(1000, self.redisplay)

	def redisplay(self):
		'''ログイン画面を再表示する'''

		# "ログインできませんでした"メッセージを削除
		self.message.destroy()

		# ウィジェットを再度作成・配置
		self.create_widgets()

	def success(self):
		'''ログイン成功時の処理を実行する'''

		# 表示中のウィジェットを一旦削除
		for widget in self.widgets:
			widget.destroy()

		# "ログインに成功しました"メッセージを表示
		self.message = tkinter.Label(
			self.master,
			text="ログインに成功しました",
			font=("",40)
		)
		self.message.place(
			x=self.master.winfo_width() // 2,
			y=self.master.winfo_height() // 2,
			anchor=tkinter.CENTER
		)

		# 少しディレイを入れてredisplayを実行
		self.master.after(1000, self.main_start)

	def main_start(self):
		'''アプリ本体を起動する'''

		# "ログインに成功しました"メッセージを削除
		self.message.destroy()

		# アプリ本体を起動
		self.main.start(self.login_name)
		
class MainAppli():
	'''アプリ本体'''

	def __init__(self, master):
		'''コンストラクタ
			master:ログイン画面を配置するウィジェット
		'''

		self.master = master

		# ログイン完了していないのでウィジェットは作成しない

	def start(self, login_name):
		'''アプリを起動する'''

		# ログインユーザー名を表示する
		self.message = tkinter.Label(
			self.master,
			font=("",40),
			text=login_name + "でログイン中"
		)
		self.message.pack()

		# 必要に応じてウィジェット作成やイベントの設定なども行う

app = tkinter.Tk()

# メインウィンドウのサイズ設定
app.geometry("600x400")

# アプリ本体のインスタンス生成
main = MainAppli(app)

# ログイン管理クラスのインスタンス生成
login = Login(app, main)

app.mainloop()

スクリプトの解説

ログイン機能付きアプリのサンプルスクリプトで紹介したスクリプトと異なるのは、register メソッドと login メソッドの2つです。

特にこれらのメソッドから実行される save メソッドと check メソッドでは前述のデータベース操作を行っています。

save メソッドでも check メソッドでも、まだデータベースにユーザー情報を管理するテーブル(user_info)が存在しない場合は、下記の execute でテーブルを作成してからデータベース操作を行うようにしています。

データベーステーブルの作成
# まだDBにテーブルがなければ作成
self.cursor.execute(
	"CREATE TABLE IF NOT EXISTS user_info (username text, password text)"
)

これにより、下の図のように usernamepassword の2つの列を持つテーブル user_info が作成されます(既にテーブル user_info が存在する場合は何も行われないと思います)。

CREATE_TABLEで作成されるテーブル

save メソッドではユーザーの情報をデータベースに追記するため、下記のように execute メソッドで SQL 文の INSERT を実行してデータベースの user_info テーブルに追記し、その後 commit メソッドを実行して追記内容の保存を行っています。

データベースへの情報追記
# 取得した情報をDBに追記
self.cursor.execute("INSERT INTO user_info VALUES (?,?)", [username, password])

# DBを保存
self.connection.commit()

check メソッドではデータベースのユーザー情報の照合を行うため、下記のように execute メソッドで SQL 文の SELECT を実行してデータベースの user_info テーブルからユーザーが入力したユーザー名とパスワードの検索を行っています。

データベースからの情報検索
# ユーザー情報を取得
check = self.cursor.execute(
	"SELECT * FROM user_info WHERE username=? and password=?",
	[username, password]
)

# 取得したユーザー情報をリスト化
user_list = check.fetchall()

最後に実行している fetchall では、直前の execute で実行した SELECT  による検索結果をリスト化するメソッドです。この fetchall の返却値 user_listNone でなければ検索結果が存在したことになるので、ログイン画面で入力されたユーザー情報がデータベースに存在したことになります。

つまり、ログインボタン押し下げ時にログイン画面に入力されていたユーザー情報は既に登録されていたことになるので、この場合は check メソッドに True を返却させ、その後 check メソッドの呼び出し元である login メソッドにログイン成功時の処理を行うようにしています。

正直私も SQL 文については詳しくないのですが、割と歴史のある命令文ですのでググるとたくさん情報が見つかると思います。やりたいことに応じて適宜検索しながら SQL 文を記述してみてください。

まとめ

このページでは「ログイン機能付きアプリ」の作成方法について解説しました。

ログイン機能を実現するポイントは下記の2つだと思います。

  • ユーザー情報の管理
  • メイン機能の開始

ユーザー情報の管理については、今回は「CSV ファイルで管理する方法」と「データベースで管理する方法」を紹介しました。

特に、データベースで管理する方法ではデータベースや SQL 文について学べますので是非こちらも挑戦してみていただければと思います。

WEB サーバー上でユーザー情報を管理するようにすれば、ちょっとした簡単なソシャゲアプリなんかも作れそうですね!

メイン機能の開始については、ログイン画面を非表示にしてからメイン機能を提供するクラスのメソッドを実行する方法を紹介しました。

ログイン画面を非表示にする際に destroy メソッドを利用してウィジェットを削除したり、after メソッドでちょっと遅らせて画面を遷移させるあたりはいろんなアプリ作成で利用できるテクニックですので、是非この辺りのメソッドについては理解しておくと良いと思います!

2 COMMENTS

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です