・はじめに
VBAのユーザーフォームを他の言語のGUIに変換するツールは今までに2言語分手がけてきましたが、3言語目はHTML/CSSとしました
過去に作成した2言語についての記事はこちらになります
VBAForm2Tkinter(Python/Tkinter変換用)
VBAForm2PowerShell(PowerShell/WinForms変換用)
HTMLはウェブブラウザから使えるのはもちろん、多くのプログラミング言語からWebView2経由でGUIとして扱うことが可能で非常に万能です
JScript(HTA), UWSCなどHTMLフォームによるGUI作成を前提とした言語もあります
ただし、HTMLフォームを手書きで書くのは結構大変なので高速でHTMLフォームを作成できるRADツールがあれば便利かと思い、HTML用の作成に至りました
ツールはGitHubで公開しています
https://github.com/GUI-Conversion-Tools/VBAForm2HTML
・動作要件
OS・・・Windows XP以降
(XP/10/11で動作確認済みです)
必要ソフト・・・Excel/Word/PowerPoint/Outlook 2000以降 (32bit/64bit両対応)
推奨ソフト・・・Excel 2016以降
Access VBAはユーザーフォームの機能がないため非対応です
1.ユーザーフォームの作成
まず、VBAで普通にユーザーフォームを作成します
2.ツールをダウンロード
ここから最新版のSource code (zip)をダウンロードして解凍してください、中にbasファイルが入っておりそのファイルを後に使用します
ダウンロードが禁止されている場合はここにアクセスして全選択→メモ帳にコピペして.basファイルとして保存してください(コピペはOKと仮定します)

3.VBAForm2HTML.basのインポート
VBA Projectと書いてある場所の何もないところを右クリックしてファイルをインポートしてください
さっき解凍したファイルにVBAForm2HTML.basが入っているのでそれをインポートします
4.変換コマンドを実行する
イミディエイトウィンドウにコマンドを入力してEnterキーを押してください
コマンドはこれです
「ユーザーフォームのオブジェクト名」のところは変換したいユーザーフォームのオブジェクト名に合わせて変えます
Call ConvertForm2HTML(ユーザーフォームのオブジェクト名)
画像の場合はオブジェクト名が「UserForm1」なのでユーザーフォームのオブジェクト名のところは「UserForm1」に置き換えます
Call ConvertForm2HTML(UserForm1)
イミディエイトウィンドウの使い方がよくわからない人は以下のように標準モジュールにSubプロシージャを作成して実行する形でもかまいません
Sub test()
Call ConvertForm2HTML(UserForm1)
End Sub
この時点でエラーが発生する場合はオブジェクト名に間違いがないか再度確認をお願いします
ConvertForm2HTMLには以下の引数を設定できます:
| 引数 | 型 | 説明 |
|---|---|---|
frms |
Variant |
必須 変換対象の UserFormオブジェクトまたはUserFormオブジェクトの配列を指定 |
usePrefix |
Boolean |
省略可能 (デフォルト: False).Trueにした場合各要素の名前にフォーム名が付加される frmsが配列の場合は自動的にTrueに設定される |
imageMode |
String |
省略可能 (デフォルト: "file")変換時の画像ファイルの扱いを設定する、以下の値を設定可能: • "file" (デフォルト): 画像は出力先フォルダ内に個別の画像ファイルとして保存され、生成されたコードはそれらの画像を参照する• "disabled": 画像の処理そのものを無効化し、生成されたコード内でも画像の参照設定を行わない• "reference-only": "file"と同様、画像を参照するコードを生成するが画像の出力自体はスキップする 既に画像ファイルが存在する場合に有用• "base64": 画像をBase64文字列としてコード内に直接埋め込み単一ファイルに収める |
langAttribute |
String |
省略可能 (デフォルト: "").生成される <html> タグの "lang" 属性に設定する言語コードを指定する(例: 英語は "en"、中国語は "zh"、日本語は "ja") 省略した場合、属性は空のままになる |
' 実行例: 単一のフォームを変換
Call ConvertForm2HTML(UserForm1)
' 実行例: 複数のフォームを変換
Call ConvertForm2HTML(Array(UserForm1, UserForm2))
' 実行例: 単一のフォームを変換 (画像をBase64文字列としてコード内に直接埋め込む)
Call ConvertForm2HTML(UserForm1, imageMode:="base64")
imageMode:="base64"は1つのファイル内に画像も含めまとめたい場合におすすめです
5.変換成功可否を確認
変換に成功したら「Saved: 保存先」のメッセージが出現しhtmlファイルが保存されます、保存先はExcelブック/Wordドキュメントと同じフォルダに「VBAForm2HTML_output」というフォルダが作成され、コードやフォーム内の画像はそのフォルダ内に保存されます
PowerPoint/OutlookのVBAで実行した場合はドキュメントフォルダに作成されます
HTAとして動作させる場合は拡張子を.htaに変えてください(HTAの場合は内部ブラウザがIEなのである程度動作に制約がかかります)
ワークブックが配置されたフォルダ/
├─ MyWorkbook.xlsm
└─ VBAForm2HTML_output/
├─ output.html
└─ エクスポートされた画像ファイル...
失敗した場合は「Control type "XXXX" is not supported」→「Conversion failed」と出ます
その場合、XXXXに当たる部分のコントロールタイプは変換非対応なので該当のコントロールを削除してからもう一度コマンドを実行してください
対応しているコントロールは以下の通りです
| VBA Formのクラス | CSSの要素 |
|---|---|
Label |
<div> |
CommandButton |
<button> |
Frame |
<fieldset> + <legend>
|
TextBox (.MultiLine=False) |
<input> |
TextBox (.MultiLine=True) |
<textarea> |
SpinButton |
<input type="number"> |
ListBox |
<select size=[n]> |
CheckBox |
<label> + <input type="checkbox">
|
ToggleButton |
<input type="checkbox"> (display:none) + <label>
|
OptionButton |
<label> + <input type="radio">
|
Image |
<div> |
ScrollBar |
<input type="range"> |
ComboBox (.Style = fmStyleDropDownCombo) |
<input list="[datalist name]"> |
ComboBox (.Style = fmStyleDropDownList) |
<select> |
MultiPage |
<div> (タブ) + <div> (ページ) + <button> (スクロールボタン) |
ListView |
<div> + <table>
|
TreeView |
<div> + <details> + <summary>
|
6.htmlファイルを実行してみる
実行してVBAと同じ見た目か確認します
違う場合は後述の「コントロールの重なりの順について」を参照してください
この時点ではボタンには何もイベントは登録されていません
ブラウザごとにコントロールの変換先の要素の動作可否が異なり、正常に動作しない場合は多くの場合見た目でわかります
| コントロール / 機能 | IE6 | IE11 | モダンブラウザ |
|---|---|---|---|
Label |
✅ | ✅ | ✅ |
CommandButton |
✅ | ✅ | ✅ |
Frame |
✅ | ✅ | ✅ |
TextBox (.MultiLine=False) |
✅ | ✅ | ✅ |
TextBox (.MultiLine=True) |
✅ | ✅ | ✅ |
SpinButton |
❌ | ❌ | ✅ |
ListBox |
✅ | ✅ | ✅ |
CheckBox |
✅ | ✅ | ✅ |
ToggleButton |
❌ | ✅ | ✅ |
OptionButton |
✅ | ✅ | ✅ |
Image (imageMode:="file") |
✅ | ✅ | ✅ |
Image (imageMode:="base64") |
❌ | ✅ | ✅ |
ScrollBar |
❌ | ❌ | ✅ |
ComboBox (.Style = fmStyleDropDownCombo) |
❌ | ⚠️ | ✅ |
ComboBox (.Style = fmStyleDropDownList) |
✅ | ✅ | ✅ |
MultiPage |
⚠️ | ✅ | ✅ |
ListView |
⚠️ | ⚠️ | ✅ |
TreeView |
❌ | ❌ | ✅ |
ブラウザ環境に関する補足:
- IE6: Windows XPに標準搭載のブラウザ
- IE11: Windows 10/11に内部的に搭載されているIEバージョン
- HTAでの実行について: HTML Application (
.hta) として実行する場合、OSにインストールされているInternet Explorerのバージョンに依存して実行されます- モダンブラウザについて: Microsoft Edge, Google Chrome, Mozilla Firefoxでの動作を確認済です
7.ボタンの動作を設定する
「登録」ボタンを押したらメッセージボックスに登録内容を表示するようにしてみます
これをHTMLファイルの末尾にコピペします
<script>
function showRegistrationInfo(name, email, region) {
var registrationInfo =
"名前: " + name +
"\nE-mail: " + email +
"\n地域: " + region;
alert(registrationInfo);
}
document.getElementById("CommandButton1").addEventListener("click", function() {
showRegistrationInfo(
document.getElementById("TextBox1").value,
document.getElementById("TextBox2").value,
document.getElementById("ComboBox1").value
);
});
</script>
html全文を表示
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>登録用フォーム</title>
<style>
body {
background: #ffffff;
display: flex;
flex-direction: column;
align-items: flex-start;
min-width: max-content;
gap: 0px;
}
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
opacity: 1;
}
#UserForm1 {
position: relative;
margin-left: auto;
margin-right: auto;
box-sizing: border-box;
overflow: hidden;
width: 304px;
height: 201px;
background: #f0f0f0;
cursor: auto;
border: 0px solid #000000;
}
#Label1 {
position: absolute;
box-sizing: border-box;
left: 16px;
top: 24px;
width: 96px;
height: 24px;
border: 1px solid #666666;
outline: 1px solid #ffffff;
outline-offset: -2px;
text-align: center;
color: #000000;
background-color: #f0f0f0;
font-family: MS ゴシック;
font-size: 15.96px;
cursor: auto;
}
#Label2 {
position: absolute;
box-sizing: border-box;
left: 16px;
top: 64px;
width: 96px;
height: 24px;
border: 1px solid #666666;
outline: 1px solid #ffffff;
outline-offset: -2px;
text-align: center;
color: #000000;
background-color: #f0f0f0;
font-family: MS ゴシック;
font-size: 15.96px;
cursor: auto;
}
#Label4 {
position: absolute;
box-sizing: border-box;
left: 16px;
top: 104px;
width: 96px;
height: 24px;
border: 1px solid #666666;
outline: 1px solid #ffffff;
outline-offset: -2px;
text-align: center;
color: #000000;
background-color: #f0f0f0;
font-family: MS ゴシック;
font-size: 15.96px;
cursor: auto;
}
#TextBox1 {
position: absolute;
box-sizing: border-box;
left: 120px;
top: 24px;
width: 168px;
height: 24px;
box-shadow: 1px 1px 0 #ffffff, -1px -1px 0 #666666, 2px 2px 0 #eeeeee, -2px -2px 0 #444444;
text-align: left;
color: #000000;
background-color: #ffffff;
font-family: MS ゴシック;
font-size: 15.96px;
cursor: auto;
}
#TextBox2 {
position: absolute;
box-sizing: border-box;
left: 120px;
top: 64px;
width: 168px;
height: 24px;
box-shadow: 1px 1px 0 #ffffff, -1px -1px 0 #666666, 2px 2px 0 #eeeeee, -2px -2px 0 #444444;
text-align: left;
color: #000000;
background-color: #ffffff;
font-family: MS ゴシック;
font-size: 15.96px;
cursor: auto;
}
#ComboBox1 {
position: absolute;
box-sizing: border-box;
left: 120px;
top: 104px;
width: 168px;
height: 24px;
box-shadow: 1px 1px 0 #ffffff, -1px -1px 0 #666666, 2px 2px 0 #eeeeee, -2px -2px 0 #444444;
text-align: left;
color: #000000;
background-color: #ffffff;
font-family: MS ゴシック;
font-size: 15.96px;
cursor: auto;
}
#CommandButton1 {
position: absolute;
box-sizing: border-box;
left: 32px;
top: 152px;
width: 96px;
height: 32px;
color: #000000;
background-color: #00ffff;
font-family: MS ゴシック;
font-size: 15.96px;
cursor: auto;
}
#CommandButton2 {
position: absolute;
box-sizing: border-box;
left: 160px;
top: 152px;
width: 96px;
height: 32px;
color: #000000;
background-color: #ff80ff;
font-family: MS ゴシック;
font-size: 15.96px;
cursor: auto;
}
</style>
</head>
<body>
<div id="UserForm1">
<div id="Label1">名前</div>
<div id="Label2">E-mail</div>
<div id="Label4">地域</div>
<input id="TextBox1" type="text" value="">
<input id="TextBox2" type="text" value="">
<input id="ComboBox1" list="ComboBox1-items-value" value="">
<datalist id="ComboBox1-items-value">
<option value=" ">
</datalist>
<button id="CommandButton1">登録</button>
<button id="CommandButton2">キャンセル</button>
</div>
<script>
</script>
</body>
</html>
<script>
function showRegistrationInfo(name, email, region) {
var registrationInfo =
"名前: " + name +
"\nE-mail: " + email +
"\n地域: " + region;
alert(registrationInfo);
}
document.getElementById("CommandButton1").addEventListener("click", function() {
showRegistrationInfo(
document.getElementById("TextBox1").value,
document.getElementById("TextBox2").value,
document.getElementById("ComboBox1").value
);
});
</script>
・コントロールの重なりの順について
Tkinter版の記事で言及してる内容とほぼ同じですが、v1.0.0時点では変換される順番はVBAでの設置順なのに対してコントロールの重なり順については必ずしも設置順と一致しないことから
正常に反映されないことがあります
対処法としてはCSSの該当要素のidのz-indexパラメータの数字に大きい数字を設定すれば数字が大きいほど優先して要素が前面に出てくるので、それで調整が可能です
このz-indexの反映についてはv1.1.0のアップデートでできるようにしたいと考えています







