【Python】tkinter:アンケート入力フォームを作成し、回答結果をcsv出力する

■ツール概要と目的

社内アンケートをtkinterのGUIアプリとして作成する。
アンケートの回答結果をCSVファイルで出力する。
なお、複数人の回答結果については、集計しやすように、1つのCSVファイルに追記していく。

以降、本ツールは「アンケート入力フォーム」と呼ぶ。

■機能設計

本項では、「アンケート入力フォーム」の機能概要を示す。

▼機能フロー図

「アンケート入力フォーム」について、ユーザが使用する観点の機能フロー図を以下に示す。

▼機能概要

▼機能フロー図」に基づく、機能概要を以下表に示す。

処理概要処理内容
アンケート入力フォームを起動アンケート入力フォームを起動する。
アンケート入力フォームアンケート入力アンケートを入力する。
アンケート回答ボタンを押下し、回答結果を出力する。
アンケート入力フォームを終了アンケート入力フォームを終了する。

▼入出力一覧

▼機能フロー図」に基づく、入出力一覧を以下表に示す。

項目名区分内容
マスタ情報入力アンケート入力フォームに必要な情報を記入するファイル。
回答結果出力ユーザが回答したアンケート結果を出力するファイル。

・マスタ情報ファイルの仕様

入力ファイルである、「マスタ情報」ファイルは、「年代」、「部署」、「役職」、「五段階評価」、「アンケート項目」を記入する。
ファイルの記載内容は、以下の通り。

・マスタ情報ファイル(mst.ini)

[AGE]
AGES = ["10代", "20代", "30代", "40代", "50代", "60代", "70代"]

[BUSYO]
BUSYO_NAME = ["営業","人事","経理","開発"]

[YAKUSYOKU]
YAKUSYOKU_NAME = ["部長", "課長", "係長", "主任", "一般"]

[HYOUKA]
HYOUKA_STATE = ["大変悪い", "悪い", "普通", "良い", "大変良い"]

[QUESTION]
QUESTION_DATA = ["〇〇は適切か", "XXは適切か", "△△は良かったか"]

・解答結果ファイルの仕様

出力ファイルである、「解答結果」ファイル(answer.csv)について、ヘッダー情報および出力値を以下に示す。

ヘッダー項目名出力値内容
年代0〜60:10代
1:20代
2:30代
3:40代
4:50代
5:60代
6:70代
部署0〜30:営業
1:人事
2:経理
3:開発
役職0〜40:部長
1:課長
2:係長
3:主任
4:一般
5段階評価0〜40:大変悪い
1:悪い
2:普通
3:良い
4:大変悪い

▼画面仕様

「アンケート入力フォーム」に関する画面仕様を以下に示す。

番号機能機能内容
年代プルダウン形式で年代を選択する。
▼年代
10代、20代、30代、40代、50代、60代、70代
部署プルダウン形式で部署を選択する。
▼部署
営業、人事、経理、開発
役職プルダウン形式で役職を選択する。
▼役職
部長、課長、係長、主任、一般
アンケート項目アンケートの項目について、5段階の評価を選択する。
なお、選択形式は、ラジオボタンとする。
送信ボタン
押下時にcsvファイルを出力する。

▼制約事項・前提条件

「アンケート入力フォーム」を作成するにあたり、以下の条件を前提として実装する。

  • アンケート項目数は3とする。
  • 画面サイズは「700×350」とする。
  • 「年代」、「部署」、「役職」、「5段階評価」、「アンケート項目」はマスタ情報ファイルで管理する。

■プログラム設計

本項では、「アンケート入力フォーム」のプログラム仕様について示す。

▼各処理の概要

「アンケート入力フォーム」で使用する処理概要を以下に示す。

処理名処理概要
メイン処理アンケート入力フォームのメイン処理。
画面レイアウトを設定する。
マスタ情報読み込み処理マスタ情報ファイルを読み込み、変数に格納する処理。
回答結果csv出力処理画面で選択した回答結果をCSVファイルに出力する処理。

▼メイン処理

「アンケート入力フォーム」実行時のメイン処理を以下に示す。


・プログラム処理フロー図

「メイン処理」のプログラム処理フロー図を以下に示す。


・プログラム仕様

「メイン処理」のプログラム仕様を以下の表に示す。

区分概要
引数引数なし
戻り値戻り値なし
入力処理内容出力
「マスタ情報読み込み処理」を呼び出し、
配列にマスタデータを格納する。
tkinterのインスタンスをする。
画面のタイトルを設定する。
タイトル:アンケート
画面のサイズを設定する。
サイズ:700×350
ラジオボタンで選択した値を保持する変数をセットする。
※今回は質問項目が3つであるため、予め変数も3つ用意する。
年代に関する設定をする。
[ラベル]
名前:年代
[リスト]
値:マスタデータの「AGES」
部署に関する設定をする。
[ラベル]
名前:部署
[リスト]
値:マスタデータの「BUSYO_NAME」
役職に関する設定をする。
[ラベル]
名前:役職
[リスト]
値:マスタデータの「YAKUSYOKU_NAME」
###アンケート項目と回答に関する設定###(ここから)
y座標の初期値をセットする。
初期値:160
■ループ処理:マスタデータ「QUESTION_DATA」分繰り返す
アンケート項目に関する設定をする。
[ラベル]
名前:QUESTION_DATAの値
x座標の初期値をセットする。
初期値:30
■ループ処理:5段階評価分繰り返し
▼条件分岐:アンケート項目
<アンケート項目1の場合>
ラジオボタンの変数1をセット
<アンケート項目2の場合>
ラジオボタンの変数2をセット
<アンケート項目3の場合>
ラジオボタンの変数3をセット
▲条件分岐:アンケート項目
5段階評価ラジオボタンに関する設定をする。
値:マスタデータのHYOUKA_STATE
x座標のインクリメント(+100)
■ループ処理:5段階評価分繰り返し
y座標のインクリメント
(+40)
■ループ処理:マスタデータ「QUESTION_DATA」分繰り返す
###アンケート項目と回答に関する設定###(ここまで)
回答ボタンに関する設定をする。
値:回答
画面の表示をする

▼マスタ情報読み込み処理

「./DEF/mst.ini」ファイルから「年代」、「部署」、「役職」、「5段階評価」、「アンケート内容」を取得し、配列に格納する。


・プログラム処理フロー図

「マスタ情報読み込み処理」の処理フロー図を以下に示す。


・プログラム仕様

「マスタ情報読み込み処理」の処理仕様を以下に示す。

区分概要
引数引数なし
戻り値List年代
List部署名
List役職名
List5段階評価
Listアンケート内容
入力処理内容出力
iniファイル読み込みのため、
「configparser.ConfigParser()」をインスタンスする。
【iniファイル】
マスタ情報
マスタ情報ファイルを読み込む
年代([AGE], AGES)を取得する。
部署名([BUSYO], BUSYO_NAME)を取得する。
役職名([YAKUSYOKU], YAKUSYOKU_NAME)を取得する。
5段階評価([HYOUKA], HYOUKA_STATE)を取得する。
アンケート内容([QUESTION], QUESTION_DATA)を取得する。
戻り値として、以下の項目を返す。
・年代
・部署名
・役職名
・5段階評価
・アンケート内容

▼回答結果csv出力処理

「回答」ボタン押下時、ユーザが選択した各項目について、CSVファイル(./ANS/answer.csv)に追記する。


・プログラム処理フロー図

「回答結果csv出力処理」の処理フロー図を以下に示す。


・プログラム仕様

「回答結果csv出力処理」のプログラム仕様を以下に示す。

区分概要
引数引数なし
戻り値戻り値なし
入力処理内容出力
【tkinter】
回答
回答結果を配列に格納する。
・年代
・部署名
・役職名
・アンケート内容1
・アンケート内容2
・アンケート内容3
回答結果をpandasのデータフレームにセットする。
csvファイルに出力する。(追記モード)【csvファイル】
回答結果
完了のメッセージを出力する。【MsgBox】
回答完了

■サンプルコード

「アンケート入力フォーム」のサンプルコードを以下に示す。

import configparser
import json
import pandas as pd
import tkinter as tk
import tkinter.ttk as ttk
import tkinter.messagebox as msg


# マスタiniファイルの相対パス
MST_INI_FILEPATH = r'./DEF/mst.ini'

# 回答結果出力ファイルの相対パス
ANS_CSV_FILEPATH = r'./ANS/ansewr.csv'

def read_mst():
    """
    処理名:
        マスタ情報読み込み処理
    処理概要:
        「./DEF/mst.ini」ファイルからマスタ情報を読み込み、
        それぞれの情報を配列に格納する。
    引数:
        なし
    戻り値:
        年代(配列)
        部署名(配列)
        役職名(配列)
        評価(配列)
        アンケート内容(配列)
    """
    # iniファイル読み込みインスタンス
    mst_ini = configparser.ConfigParser()
    # マスタファイル読み込み
    mst_ini.read(MST_INI_FILEPATH, encoding='utf-8')
    # 年代読み込み
    mst_ages = json.loads(mst_ini.get('AGE', 'AGES'))
    # 部署名読み込み
    mst_busyo = json.loads(mst_ini.get('BUSYO', 'BUSYO_NAME'))
    # 役職名読み込み
    mst_yakusyoku = json.loads(mst_ini.get('YAKUSYOKU', 'YAKUSYOKU_NAME'))
    # 5段階評価読み込み
    mst_hyouka = json.loads(mst_ini.get('HYOUKA', 'HYOUKA_STATE'))
    # アンケート項目読み込み
    mst_question = json.loads(mst_ini.get('QUESTION', 'QUESTION_DATA'))
    
    return mst_ages, mst_busyo, mst_yakusyoku, mst_hyouka, mst_question


def make_csv_answer():
    """
    処理名:
        回答結果csv出力処理
    処理概要:
        「回答」ボタン押下時、選択した項目について、
        csvファイルに追記する。
    引数:
        なし
    戻り値:
        なし
    """
    # 回答結果を配列に格納
    answer_list = [[
        combobox_age.current(),
        combobox_busyo.current(),
        combobox_yakusyoku.current(),
        radiobtn_value_1.get(),
        radiobtn_value_2.get(),
        radiobtn_value_3.get()
        ]]
    # 回答結果をセット
    result_data = pd.DataFrame(answer_list)
    # csv出力(追記)
    result_data.to_csv(ANS_CSV_FILEPATH, index=False, header=False, mode='a')
    
    # 完了メッセージ出力
    msg.showinfo("回答送信", "回答の送信が完了しました")


# メイン処理
if __name__ == '__main__':
    # マスタデータの読み込み
    age_list, busyo_list, yakusyoku_list, hyouka_list, question_list = read_mst()
    
    # tkinterのインスタンス
    base = tk.Tk()
    # タイトル設定
    base.title("アンケート")
    # 画面幅の設定
    base.geometry("700x350")
    
    # ラジオボタンの値を保持
    radiobtn_value_1 = tk.IntVar()
    radiobtn_value_2 = tk.IntVar()
    radiobtn_value_3 = tk.IntVar()
    
    # 年代に関する設定(ラベルとリスト)
    label_age = tk.Label(base, text="年代")
    label_age.place(x=20, y=40) 
    combobox_age = ttk.Combobox(base, width=6, justify='center', state='readonly')
    combobox_age["values"] = (age_list)
    combobox_age.current(0)
    combobox_age.place(x=60, y=40)
    
    # 部署に関する設定(ラベルとリスト)
    label_busyo = tk.Label(base, text="部署")
    label_busyo.place(x=20, y=80) 
    combobox_busyo = ttk.Combobox(base, width=6, justify='center', state='readonly')
    combobox_busyo["values"] = (busyo_list)
    combobox_busyo.current(0)
    combobox_busyo.place(x=60, y=80)

    # 役職に関する設定
    label_yakusyoku = tk.Label(base, text="役職")
    label_yakusyoku.place(x=20, y=120) 
    combobox_yakusyoku = ttk.Combobox(base, width=6, justify='center', state='readonly')
    combobox_yakusyoku["values"] = (yakusyoku_list)
    combobox_yakusyoku.current(0)
    combobox_yakusyoku.place(x=60, y=120)

    # アンケート項目(ラベル)と回答(ラジオボタン)に関する設定 -ここから-

    # y座標の初期値
    y_place = 160
    
    # アンケート項目(配列)分繰り返し
    for i in range(len(question_list)):
        # アンケート項目ラベルをセット
        label_question = tk.Label(base, text=question_list[i])
        label_question.place(x=20, y=y_place)
        
        # x座標の初期値
        x_place = 30
        
        # 5段階評価(配列)分繰り返し
        for j in range(len(hyouka_list)) :
            # 回答結果を保持する変数を設定
            if i == 0:
                radiobtn_value = radiobtn_value_1 
            elif i == 1:
                radiobtn_value = radiobtn_value_2
            elif i == 2:
                radiobtn_value = radiobtn_value_3
           
           # 5段階評価ラジオボタンに関する設定
            radiobtn_hyouka = ttk.Radiobutton(
                base,
                text=hyouka_list[j],
                value=j,
                variable=radiobtn_value)           
            radiobtn_hyouka.place(x=x_place, y=y_place+20)

            # x座標のインクリメント
            x_place += 100

        # y座標のインクリメント
        y_place += 40
    
    # アンケート項目(ラベル)と回答(ラジオボタン)に関する設定 -ここまで-

    # 回答ボタンの設定
    btn_answer = tk.Button(base, text="回答", command=make_csv_answer)
    btn_answer.place(x=330, y=y_place+30)

    # 画面の表示
    base.mainloop()

■実行結果

・起動時の画面


・任意の項目を選択し「回答」ボタンを押下


・完了メッセージ出力


・csvファイルに出力されていることを確認(赤枠部分

■参考

「アンケート入力フォーム」ツールを作成するにあたり、参考とさせていただいた外部リンクおよび内部リンクを示す。

▼外部参考リンク

・iniファイル読み込み


・ラジオボタン


・CSVファイルへの追記

▼内部参考リンク

・GitHub

コメント

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