0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

VBScriptでGUIプログラム作りたかったのでとりあえず作ってみた

Posted at

経緯

ExcelVBAを齧った程度の知識でフォームアプリケーション作れるからとC#を始めてみたら覚えることが多いし、
何よりVisual Studioが重すぎて嫌になったので何か楽に低スペックでもフォームアプリケーション作れないかな、
と思っていたころが私にもありました。
いやExcelでもフォーム作れるけどExcelを起動しなきゃダメなのが何となく嫌で。

結論

まず、あまりお勉強をしたくないしWINDOWS10で動くお手頃なヤツとしてVBScriptで書こうと決めました 
UI周りが非常に貧弱でした、INPUTBOXとかそんな感じのものばかり。
IEのオブジェクトが使えるけどただでさえVBScriptが時代遅れなのにIE使ってUI作るのは流石にないな…と。
そんな失意の中さらに調べてみるとWINDOWS10で標準搭載でかつフォームを作成可能いう便利な奴を見つけました。
そうPowerShellならね。

何故PowerShellを採用したか

PowerShellさんは動作するのに**.NET Frameworkが必要と書かれています。
要するに
C#を同じようなことができるってこと、じゃあフォームも作れるじゃん**というだけの話です

おマヌケな実装

PowerShellを利用するというその発想までは良かったんですが。
VBScriptから呼び出したはいいけどフォームが処理した結果を受け取る方法まで考えてませんでした。
なのでPowerShellの処理の結果はファイルに書き出してそれをVBScriptを吸い上げて戻り値にしています。
アホです、大目に見てください。

①引数に応じて入力欄が2~5個に変化するインプットボックスのフォームを作成するPowerShellさん
結果はテキストファイルに書き出します

MultiInputBox.ps1
using namespace System.Windows.Forms
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
 
[Application]::EnableVisualStyles()

# 実行中のパス取得サンプルソース
$path = Split-Path -Parent $MyInvocation.MyCommand.Path
Set-Location $path

# 指定のパスへ置換
$path = $path.Replace('ps', 'arg')
$path = $path + "\" + $Args[0]

# フォームを先に作成する
$frame = New-Object Form
$frame.Text = $Args[2]

# テキストボックスの数を決定する変数(2未満にはならず、最大5)
$Formcnt = [int]$Args[1]

# ラベルの名称配列 文字は「,」区切りで受ける
$Tlab = $Args[3].Split(",")

# ラベルの初期高さを変数へ格納
$Hlab = 20

# テキストボックスの初期高さを変数へ格納
$Htxt = 40

# ボタンの高さを計算して変数へ格納
$Hbtn = 120 + ($Formcnt - 2) * 40

# フォーム自身の高さを計算して変数へ格納
$Hform = 220 + ($Formcnt - 2) * 40

# フォームのサイズを決定する
$frame.Size = "500, " + [string]$Hform

# テキストボックスのリストオブジェクトを生成(各テキストを参照する場合は配列内の要素のtextプロパティを参照する)
$txts = New-Object System.Collections.Generic.List[System.Windows.Forms.TextBox]

# ラベルを動的生成するループ
for($i=1; $i -le $Formcnt; $i++) {
	$label = New-Object Label
	$label.Text = $Tlab[$i - 1]
	$label.Name = "Label" + [string]$i
	$label.Font = New-Object Drawing.Font("Meiryo UI",8)
	$label.Location = "20, " + [string]$Hlab
	$label.AutoSize = $True
	$Hlab = $Hlab + 40
	$frame.Controls.Add($label)
}

# テキストを動的生成するループ
for($j=1; $j -le $Formcnt; $j++) {
	$txt = New-Object TextBox
	$txt.Name = "textbox" + [string]$j
	$txt.Location = "20, " + [string]$Htxt
	$txt.Size = "350, 40"
	$Htxt = $Htxt + 40
	$frame.Controls.Add($txt)
	$txts.Add($txt)
}

# ボタン
$btn = New-Object Button
$btn.Text = "OK"
$btn.Font = New-Object Drawing.Font("Meiryo UI",18)
$btn.Size = "120, 50"
$btn.Location = "350, " + [string]$Hbtn

# ボタンイベント
$btn_Click = {
	#入力した文字列を回収
	$result = ""
	$cnt = $Formcnt - 1
	for($k=0; $k -le $cnt; $k++) {
		$result = $result + $txts[$k].Text
		If($k -le $cnt - 1){
			$result = $result + "`r`n" #ループの最後以外は改行を加える
		}
	}
	#戻り値をテキストファイルへ出力(SJISで出力)
	Add-Content -path $path -value $result -encoding String
	$frame.Close()
}
$btn.Add_Click($btn_Click)

# ボタンの要素をフォームへ加える
$frame.Controls.Add($btn)

# フォーム表示
$frame.ShowDialog()

②上記フォームを呼び出すVBScriptさん

FormLibrary.vbs
'マルチインプットボックス
'////2~5個の入力欄を持つインプットボックスを表示し入力欄の値を返す関数
'///////////////////////////////////////////////////////////////////////////
'////////第一引数 boxcnt		Integer(テキストボックスの数を決定する、2~5)
'////////第二引数 headername	String(フォームのヘッダー名)
'////////第三引数 boxnames		String(全テキストボックスの名前、「,」区切りの文字列を指定)
'////////戻り値   String(テキストボックスの入力値、boxcntの値と同じ数の列を持つ)
'///////////////////////////////////////////////////////////////////////////
Function MultiInputBox(boxcnt, headername, boxnames)

	'戻り値の初期化
	MultiInputBox = ""

	'引数の正当性チェック
	'1:いずれか引数が空文字
	If boxcnt = "" Or headername = "" Or boxnames = "" Then 
		MultiInputBox = "err_1"
		Exit Function
	End If
	'2:boxcntが2~5であること
	If boxcnt > 5 Or boxcnt < 2 Then
		MultiInputBox = "err_2"
		Exit Function
	End If
	'3:boxcntとboxnamesの要素数が同じであること
	If Not boxcnt = (UBound( Split(boxnames, ",") ) + 1) Then
		MultiInputBox = "err_3"
		Exit Function
	End If

	'フォーム生成用のオブジェクト
	Set objShell = CreateObject("WScript.Shell")
	'戻り値受け取り用ファイル名
	argfilename = replace( replace( replace( now() , ":" , "" ) , "/" , "" ) , " " , "" ) & ".txt"
	'テキストボックスのラベル名を加工
	boxnames = """" & """" & """" & boxnames & """" & """" & """"
	'フォームを同期処理で起動
	objShell.Run "powershell -WindowStyle hidden -ExecutionPolicy Bypass -command .\ps\MultiInputBox.ps1 " _
				 & argfilename & " " & boxcnt & " " & headername & " " & boxnames, 0, true
	Set objShell = nothing

	'ファイルシステムオブジェクト
	Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
	'戻り値ファイルのパスを生成
	argfullfilename = replace(WScript.ScriptFullName, WScript.ScriptName, "") & "arg\" & argfilename
	'戻り値ファイルの存在をチェック
	If objFSO.FileExists(argfullfilename) Then
		'ファイルを取り込んで書き出す
		Set objFile = objFso.OpenTextFile(argfullfilename)
    	MultiInputBox = objFile.ReadAll
		'ファイルを閉じて削除する
		objFile.Close
		objFSO.DeleteFile(argfullfilename) 
		Set objFile = nothing
	End If
	Set objFSO = nothing
	
End Function

使い方

①上記ソースを以下のようなフォルダ構成にして好きなところへ格納する
・フォーム拡張用フォルダ
└・FormLibrary.vbs
└・arg(フォルダ、空でOK)
└・ps(フォルダ)
 └・MultiInputBox.ps1
②下記のようなWSFファイルを作成してVBScriptのコーディングを実施すれば利用可能

sample.wsf
<job>
	'フォーム用のライブラリ、追加のライブラリを加える場合は同じような記載をすること
	<script language="VBScript" src="格納したどこか\フォーム拡張用フォルダ\FormLibrary.vbs"></script>
	'以下へ今まで通りのVBScriptを記載する
	<script>
		msgbox MultiInputBox(3, "名前・年齢・性別入力", "名前,年齢,性別")
	'下記2行はそのままにすること
	</script>
</job>

上記WSFを作ってダブルクリックすれば入力欄が3個のボックスが出来上がり。srcのところはちゃんと書き換えてください。
引数次第で入力欄は2~5個に変更可能で戻り値は全テキストボックスの値を入力欄の個数と対応した行数で返します。

ちなみに

文字コードSJISです、まぁしゃーない。

0
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?