エクセルアンケートフォーム VBAユーザーフォームで、Sheetに作成した質問事項からフォームを自動作成する。

質問用のフォームを自動作成する。

エクセルを使ってアンケートを作る場面で、いろんな種類のアンケートを何度も作っていくと「また1からアンケートのフォームを作らないといけないのか…」という場面があるのではないでしょうか?

「年に1回、決まった内容のアンケートを取る」なら、1回フォームを作ってしまえば終了ですが、
「たびたび、アンケート内容が変わりその都度アンケート用紙を作り直している」という人は地獄だと思います。

そんな悩みを解決するための、VBAを作成しました。


この記事は過去記事を元に作成しております。↓↓
bimori466-1.hatenablog.com


1 閲覧対象者

1 エクセルVBAのユーザーフォームでアンケートマクロを作成したい初心者の人。
2 エクセルでアンケートをたくさん作っている人。

2 得られる効果

質問Sheetに作成したアンケート入力のFrameを自動作成して、回答を他BookにSQL文で反映する。

処理イメージ

<まずは動画をごらんください>


「アンケート入力用」、「回答書き込み用」の2つのエクセルを準備します。
f:id:bimori466:20200506084826p:plain


1 下のような、質問Sheetを作成し、
f:id:bimori466:20200505083346p:plain


2 ユーザーフォームを起動し、回答開始をクリックします。
f:id:bimori466:20200505084953p:plain


3 「回答用Frame」と「← 前へ」「次へ →」のコマンドボタンが出現します。質問に回答して「次へ →」で進んでいきます。
f:id:bimori466:20200505092327p:plain


4 最終項目になったら、「回答を送信」が出現します。すべて回答したら、「回答を送信」をクリックする。
f:id:bimori466:20200505092717p:plain


5 他BOOKにデータが反映される。
f:id:bimori466:20200505092958p:plain

集計後のグラフのまとめ方は、今回は触れません。あくまで、質問Sheetを作って、アンケ―ト回答の結果を書き込むところまでです。
この記事でお伝えしたいのは、「質問Sheetを作れば、アンケートフォームは自動でできる」という部分です。

3 設計

概要

回答用Sheetに作成したアンケート内容を、ユーザーフォームで回答用フォームを作成する。
回答用フォームで入力されたアンケート結果を、他のBOOKにSQL文で反映する。

詳細

回答用Sheet

1 列Aに問題番号を入れる。質問が複数ある場合は、質問ごとに番号を入れる。

例:年齢(1Frameに、6項目) ↓↓
f:id:bimori466:20200505131243p:plain


2 単一回答はOptionButton。複数回答はCheckBox。フリー入力はTextboxを使用。

3 OptionButton、CheckBoxは必須項目のみ。Textboxは必須or任意とする。
  (変更したいなら、コード追加すれば可能。とりあえずは、「その他ありましたらご記入ください」みたいなときに空白でもOKというニュアンスで作ってます。)

4 質問に対しての項目数は7つまで。
  (Frameのサイズ変えれば何個でもOK。)


↓↓今回の作りでは、7つまでがFrameぎりぎりです。
f:id:bimori466:20200505132724p:plain

回答集計Sheet

ユーザーフォームからのアンケート回答データを受け取るSheetです。回答用Sheetがある別BOOKのユーザーフォームで「回答を送信」したらこのSheetに書込まれます。


↓↓今回のアンケートは、質問数が6なので、列が6までです。
f:id:bimori466:20200505134731p:plain

ここまでで、アンケート集計を処理する準備は完了です。次にユーザーフォームで何をやっているのかを解説します。

4 ユーザーフォームの処理を解説

質問SHEET作成済の前提で書いていきます。

アンケート回答処理の流れ

1 ユーザーフォームの表示(UserForm_Initialize)
2 「回答開始」をクリック(cmd_strart_Click)
3 「次へ→」をクリック(cmd_Next_Click)
4 最後の質問になったら、「回答を送信」をクリック(cmd_回答送信_Click)。回答集計Sheetにアンケート結果が反映される。

以上の1~4までです。
では、順番に解説していきます。

まえおき FROMについて

VBEのユーザーフォームについて
f:id:bimori466:20200505162615p:plain

上の画像ののように、VBEからフォームを見ると7つのオブジェクトがあります。
しかし、標準モジュールからユーザーフォームを開いた時には「回答開始」のみを表示しています。
コードの記述上、非表示(Visible=False)にしています。なぜ非表示にするかは、「回答の流れを誘導するため」です。おいおい流れの中で説明をします。

それぞれのフォームの説明
f:id:bimori466:20200505213036p:plain


今回の記事の肝(言いたいこと)は、「FRAME部分は回答Sheetから自動で作ります」ということです。
f:id:bimori466:20200505215203p:plain


1 ユーザーフォームの表示(UserForm_Initialize)

UserForm_Initializeの処理(標準モジュールで「Userform.Show」したときの処理)

処理
プロジージャ「uf_open」を実行する。

f:id:bimori466:20200505213706p:plain


結果
FROMが表示され、「回答開始」のみ表示。

f:id:bimori466:20200505214029p:plain


解説 
まず、VBEのFROMを表示します。
ここのメイン処理は「lst_Answer」の作成です。
最初はlst_Answer(アンケート結果)の中身は空です。
質問Sheetから、lst_Answerを作成します。

lst_Answerの結果は下の画像で(Visible=Trueにしてます)↓↓
f:id:bimori466:20200505220611p:plain

今回の質問数は6つなので、lst_Answerに1~6のレコードが作成されます。
項目は、「Question_No」「アンケート回答」「入力必須or任意」の3つです。


次に、Formのサイズ変更処理をします(ここでFormのサイズを変更できます)。


最後にPublic変数「SQN」に「1」を代入します。(SQN=Start_Question_No)という意味で作った変数です。
Public変数にすることで、フォームモジュールの処理を何か実行しても、SQNの値は保持されたままです。
主に、コマンドボタン「← 前へ」「次へ →」の処理をするときの開始位置として使います。なので、結構大事な変数になります。


2 「回答開始」をクリック(cmd_strart_Click)

処理
「回答開始」をクリック

f:id:bimori466:20200506075015p:plain


結果
コマンドボタン「← 前へ」「次へ →」を表示します(Visible=True)。
アンケート回答用のFRMAEを作成します。
f:id:bimori466:20200506075154p:plain


解説
この記事で主張しているFrameの自動作成の処理です。

質問Sheetの列(ROW)を、変数「S_Line」に取得します。
この場合、InitializeでSQN=1としたので、質問Sheetの最初のROW番号は「2」となります。


↓↓*SQN=1のとき、ROW番号は「2」
f:id:bimori466:20200506092015p:plain


FROMの中には、Frameを「3つまで」作ります。あとは、回答入力します。
このように、回答の流れを誘導しています。

*ちょっと小話

VBEからFROMをみると、問題検索という機能を作っています。これを最初から表示させておくと、 いきなり問題検索をする人もいます。
「そんな人いない」と言われそうですが、こちらが思いもしない行動をユーザーはとるものです。なので、表示の仕方にも工夫が必要なんですね。


3 「次へ→」をクリック(cmd_Next_Click)

処理
回答を入力して、「次へ →」をクリックする。

f:id:bimori466:20200506215803p:plain


結果
次の質問が表示される(Q4~Q6)。最終問題になったので「回答を送信」を表示する。

f:id:bimori466:20200506220235p:plain


解説
まず、問題を回答します。該当するOptionButtonをクリック。


cmd_Next_Clickの処理の流れ
1 Next_Answet_Flgをたてる。
2 Frame名を調査。
3 Frameの入力チェック。
4 lst_Answerに、回答を書込む処理。
5 次のFrameを作るため、現在のFrameを削除。
6 次のQuestionを作る(cmd_strart_Click)。
7 Next_Answet_Flgを切る。

1~7まで順番に解説します。


1 Next_Answet_Flgをたてる。
SQN(Start_Question_No)に+3して、Last_Question_Noより大きくない場合、変数Next_Answet_Flg = Trueとする。
(「6 次のQuestionを作る」時に「Next_Answet_Flg = True」ならば、SQN+3して次の質問Frameを作成する。)

2 Frame名を調査。
現在表示されているFrame名を取得する。
「入力チェック処理」時、lst_Answerへの「回答書込処理」のときに、ループ処理するFrameの特定のために使用する。

3 Frameの入力チェック。
チェックが入っていないFrameがあれば、メッセージを出す。そのため、Frame3つに回答がされていなければ次には進めない。
その他の項目は、チェックがあってもTextbox内が空白であればエラーとなる。

4 lst_Answerに、回答を書込む処理。
現在表示されているFrameの「Question_No」とlst_Answerの「Question_No」が等しいとき、lst_AnswerにFrameの回答を書き込む。
Frame内のOptionButton、CheckBox、Textboxで分岐して書込処理を作っている。

5 次のFrameを作るため、現在のFrameを削除。
Q1~Q3のFrameを削除する。

6 次のQuestionを作る(cmd_strart_Click)。
cmd_strart_Clickの処理を呼び出しています(Call)。cmd_strart_Clickの処理の中で、「Next_Answet_Flg = True」ならば、SQN+3して次の質問Frameを作成する。

7 Next_Answet_Flgを切る。
「Next_Answet_Flg = False」とする。Next_Answet_Flg はPUBLIC変数なので、何かFrom処理が行われても記憶されたままです。

4 最後の質問になったら回答後、「回答を送信」をクリック(cmd_回答送信_Click)。回答集計Sheetにアンケート結果が反映される。

処理 回答を入力し、「回答を送信」をクリックする。
f:id:bimori466:20200507160123p:plain

結果 メッセージボックスが表示される。回答終了。
f:id:bimori466:20200507160234p:plain

回答集計Sheet アンケート結果が反映される。
f:id:bimori466:20200507160552p:plain


解説
アンケートが最終質問になったら、「回答を送信」ボタンが出現するので回答後クリックする。

cmd_回答送信_Clickの処理の流れを解説。

1 Frame名を調査。
2 Frame項目の「入力チェック処理」
3 lst_Answerに、回答を書込む処理。
4 回答集計Sheet更新用のSQL文作成
5 回答集計Sheet更新する。

1~3は、「cmd_Next_Clickの処理の流れ」と同じです。4,5を解説します。

4 回答集計Sheet更新用のSQL文作成
アンケートの回答結果を書き込んでいたlst_Answerから、SQL文を作ります。
ループ処理して、カンマで区切って文字列として回答をくっつけます。

作成するSQL文のコード
strSQL = " INSERT INTO [回答集計2$](1,2,3,4,5,6) VALUES(" & SQL_VALUES & ")"

変数SQL_VALUES が更新するSQL文の値です。
変数strSQLが回答集計Sheetを更新するためのSQL文です。

回答集計Sheetの、列名1~6は事前に作成しておく必要があります。


以上がユーザーフォーム処理の説明です。

5 反省点

1 「質問Sheet作成入力フォーム」を作る。
  理由:エクセルを直接編集するのではなく、専用の入力フォームを作ればエラーが減る。


2 アンケートの質問文字列を「FrameのCaption」ではなく、「LABELのCaption」にすればよかった。
  理由:アンケ―トの質問が長い場合、「FrameのCaption」は文字の改行ができないため、幅を横に広げるしかなく、見にくいものになってしまう。「LABELのCaption」なら文字の改行が可能。つまり、質問を「LABELのCaption」で作り、回答欄をFrameで作ればよかった。


3 「← 前へ」をクリックしたときに、前回回答した問題にチェックを入れる。
  理由:もう一度入力するユーザーの手間を省ける。


4 回答集計Sheetも自動で作成するようにする。
  理由:今回はSQL文で更新する「回答集計Sheet」は事前に作成していました。しかし、反省点1の「質問Sheet作成入力フォーム」を作り終わった段階で自動作成するようにすれば、SQL文で更新する列を手動入力する必要がなくなる。

6 実際に使ってみたい方は…

noteから無料でダウンロードできます。
興味のある方は、お試しください。

note.com