アンケート作成 苦戦中です。 愚痴みたいなもの。
アンケートのHTAを最終的にはつくるべく,HTMLやJavaScriptと格闘中です。
あまりホームページ等作ったことはないので,このへんはツールの力でごり押ししていて,タグ打ちとかほぼしたことなくて未知の領域。
進まない進まない。。
ネットや本の力を借り,見た目は テキストボックス,ラジオボックス,チェックボックス,複数行入力できるフィールド等配置したものを作り,送信ボタンをつけてあげる。
そう,サーバーを立てれない環境でしかやっていなかった私にとって 不思議極まりなかったのが Submitボタンです。
送信てどこに送信してるの どんなもの送信してるの 細かい設定はどこでしてるのと
???????????
はてなの大行進の内容でした。
ですが,JavaScriptをやり始めてから,外部には何も出さずにJavaScriptでデータを受け取って望みの形に成型して望む場所に出す,ということが現実的になりました。
チェックボックス以外のエレメントに関しては,比較的簡単に制御はわかりましたが,複数選択で使えるチェックボックスについてはかなりてこずりました。
丸一日くらいはそれで引っかかってました。やっとなんとかなりそうではあります。そのうち触れることはあるかと。
わからないことばかりで,本当に困ったものですが,遅々とした歩みではありますが,なんか目標に歩けているようです。
見込みが立ってきたので,望むものを作る方向性だけ書き出しておくことにしました。
1.Excelにアンケートの設問形式,設問の内容,選択肢を書き込めるシートを用意する。
2.VBAでそれに従ったHTAのコードを作らせて,保存までさせる。
3.できあがり ヽ(*´∇`)ノ
UTF-8の文字コードでVBAで保存させるってとこがよくわかってませんが,まぁたぶんできるはず。
form内のname属性を配列で取りたい,というのもずいぶん調べたんですが私には理解できませんでした。getAttributeとかでできるのかなぁと試していましたが,
デバッグの仕方もまだよくわかってないのでとても効率が悪い。
VBAのエディタのローカルウィンドウとかイミディエイトウィンドウが神様のように見えます。 (ノД`)
ただ,自分でどうせ設問のコードを吐き出すわけですので,
コードのどこかに配列できちんとname属性を記録しておけばそれに従って処理は可能なわけで,なんとかなるなとは思えています。
または,全エレメントの値を返させて後でゆっくり料理するというのもありですね。
JavaScriptに慣れていけばいろんな手段は思いつきそうですので,がんばろう。
まだ本やネットを見ないとほとんど何も書けない,VBAと比べるととてもひどい状況ですが,
JavaScriptはとても興味をそそられます。
この気持ちがあるうちに,理解度をできるだけ進めたいところです。力尽きたらまたしばらくやらなくなりますしね。。(;´∀`)
疑似掲示板 その2
TextStreamのCloseをきちんとすると,動きがとてもよくなったので,実際の使用に向けてさらに調整を加えてみました。
各授業で簡単に使えるように,データファイルに当たるbbs.txtを掲示板ファイルの名前を利用してつけるように変更。
同じフォルダにHTAファイルとtxtファイルがあるとごちゃごちゃなるので,bbsフォルダを作成してそこにtxtを保存するように変更。
見た目が悪かったので,CSSで若干調整。
(追記)更新ボタンも付け加えました。
この辺の手を加えてみました。試してみないと本当のとこわかりませんが,うまくいきそうな感じ。
ショートカットをうまく利用して生徒が簡単にアクセスできるようにもう一工夫があるといいのかな
さらにショートカットを固定できるように,仕組みを自分の中でルールづけられれば,面白いのかもしれない。
とりあえず,昨日のものよりは改善していると思うので,コードを載せます。
HTAのお約束で,メモ帳とかに貼って,文字コードを忘れずにUTF-8にして,拡張子htaで保存します。それだけでたぶん使えます。
HTAは手軽でいい。次のVersionのWindowsでも生き残らせてくれないかなぁ ( ´Д`)=3
<!doctype html> <html> <head> <meta charset="utf-8"> <title>メッセージ</title> <!-- CSS --> <style type="text/css"> .title{background-color: orange;font-size: 20px;display: block;width: 100%;} dt{display:block;width: 80px; float: left;padding-left: 2px;padding-top: 2px; background-color:lime;} dd{display:block;width: 410px;margin-left: 85px;padding-left: 5px;padding-top: 2px; background-color: greenyellow;} .user{display: none;} .form{background-color: beige;display: block;width: 100%-4px;padding: 4px;} </style> <!--JScript--> <script> resizeTo(560,600); // FileSystemObject 用定数 var ForReading = 1; var ForWriting = 8; /** BBS のデータファイルのフルパス */ var thisName=location.pathname thisName=thisName.slice(thisName.lastIndexOf("\\")+1,thisName.lastIndexOf(".")); var BbsFile = ".\\bbs\\"+thisName+"bbs.txt"; var User=new ActiveXObject("WScript.Network").UserName; /** ファイルの読み込み */ function loadText() { var fso = new ActiveXObject("Scripting.FileSystemObject"); var bbs = fso.OpenTextFile(BbsFile, ForReading); var tmp=bbs.ReadAll(); bbs.Close(); return(tmp); } /** 投稿内容のロード */ function load() { var fso = new ActiveXObject("Scripting.FileSystemObject"); if (fso.FolderExists(".\\bbs")==false) fso.CreateFolder(".\\bbs"); if (fso.FileExists(BbsFile)==false){ var bbs = fso.OpenTextFile(BbsFile, ForWriting,true); bbs.WriteLine("<dt style='background-color:limegreen;'>名前</dt><dd style='background-color:limegreen;'>メッセージ</dd><span class='user'>ユーザー名</span>\r"); bbs.Close(); } document.getElementById("data").innerHTML=loadText(); } /** 投稿 */ function post() { var name=document.getElementById("name").value; var msg=document.getElementById("msg").value; var postData = "<dt>" + name + "</dt>" + "<dd>" + msg + "</dd>" +"<span class='user'>" + User +"</span>\r"; var fso = new ActiveXObject("Scripting.FileSystemObject"); var bbs = fso.OpenTextFile(BbsFile, ForWriting); bbs.WriteLine(postData); bbs.Close(); load(); document.getElementById("name").value=""; document.getElementById("msg").value=""; } </script> </head> <body onLoad="load();"> <div class="title">一言メッセージ</div> <span class="form"> 名前 <input type="text" id="name" size="14" value="" placeholder="Name"><br> メッセージ <input type="text" id="msg" size="50" value="" placeholder="Message"><br> <input type="button" id="post" value="送信" onClick="post()"> <input type="button" id="Reload" value="更新" onClick="load()"> </span> <dl id="data"></dl> </body> </html>
動作画面はこんな感じです。
試用後に再調整かな。
今度はアンケートに近いものが作れるようにしてみよう。
疑似掲示板(失敗) JScript & HTA → 成功かも
興味がない分野について,自分の知識が全くないことに気づかせてくれるJSciptの学習。
今日は掲示板ぽいのを作ることをしていました。
こちらの記事を参考に,コードも使わせてもらいながら,自分の環境で作る。
JQueryを自分の環境でいまのところきちんと動かせなかったので,けっこうコードは行き当たりばったりで作ってます。
JScriptの学習と思ってこつこつやっていました。
例によってHTAです。HTMLでは動作しません。
メモ帳にはりつけて,拡張子HTAで保存します。文字コードはUTF-8にしないと動かないようです。
追記 imihitoさんにコメントをいただいて,見直してみたらCloseに()が抜けていましたので修正しました。
失敗を忘れないためにも下のほうの駄文は残しております。コードは書き直しました。
<!doctype html> <html> <head> <meta charset="utf-8"> <title>メッセージ</title> <!-- CSS --> <style type="text/css"> dt{float: left;} dd{margin-left: 80px;} .user{display: none;} </style> <!--JScript--> <script> // FileSystemObject 用定数 var ForReading = 1; var ForWriting = 8; /** BBS のデータファイルのフルパス */ var BbsFile = "bbs.txt"; var User=new ActiveXObject("WScript.Network").UserName; /** ファイルの読み込み */ function loadText() { var fso = new ActiveXObject("Scripting.FileSystemObject"); var bbs = fso.OpenTextFile(BbsFile, ForReading); var tmp=bbs.ReadAll(); bbs.Close(); return(tmp); } /** 投稿内容のロード */ function load() { var fso = new ActiveXObject("Scripting.FileSystemObject"); if (fso.FileExists(BbsFile)==false){ var bbs = fso.OpenTextFile(BbsFile, ForWriting,true); bbs.WriteLine("<dt>名前</dt><dd>メッセージ</dd><span class='user'>ユーザー名</span>\r"); bbs.Close(); } document.getElementById("data").innerHTML=loadText(); } /** 投稿 */ function post() { var name=document.getElementById("name").value; var msg=document.getElementById("msg").value; var postData = "<dt>" + name + "</dt>" + "<dd>" + msg + "</dd>" +"<span class='user'>" + User +"</span>\r"; var fso = new ActiveXObject("Scripting.FileSystemObject"); var bbs = fso.OpenTextFile(BbsFile, ForWriting); bbs.WriteLine(postData); bbs.Close(); load(); document.getElementById("name").value=""; document.getElementById("msg").value=""; } </script> </head> <body onLoad="load();"> <h1>一言メッセージ</h1> <p> 名前 <input type="text" id="name" size="14" value="" placeholder="Name"> メッセージ <input type="text" id="msg" size="60" value="" placeholder="Message"> </p> <p> <input type="button" id="post" value="送信" onClick="post()"> ※エラーが出たら少し待ってもう一度 送信 を押してください。 </p> <dl id="data"></dl> </body> </html>
こんな画面になるとってもシンプルなもの。
送信ボタンを押せば投稿されるよ,ということと ユーザー名を裏で記録してるよ,というもの。
一人で試してても
こういうエラーがまぁまぁ出ます。書き込み時の競合なのかなーと思うけどテキストのファイルサイズもそんなに大きくないし,
なんでそれなりの確率でこいつが出てくるのか不思議です。できる範囲でCloseもやっているのになぁ。WriteLineの直後にClose書いたら拒否されるのでそこはやってません。
複数ウィンドウを開いて試すとさらにダメ。ということは実際の使用には現状はたえない状態のようです。元の記事の方とは書き込み回りも違いますし,そちらに
寄せていけば改善されるのだろうか。 ※追記 Close();をきちんとすることで改善されていると思われます。
とりあえず,この形で作りたかったので,その試しとして記録するとして,今度は各クライアントが一つのテキストを吐き出すようにして,あるフォルダにその小さいテキストを集める。
すでに存在する場合は上書きするという形にして,競合の可能性をなくす。
小さいテキストをかき集めて掲示板のデータにする,という形で今度は作ってみようと思います。
読み込みの際は問題にならないんじゃないかなと思うので,エラーを回避できるかなぁと思ったり。
明日はそれに挑戦してみよう。。
実際使っている授業支援ソフトが,アンケート機能が通信環境の安定性を損ねるということでなくなっています。
その代わりになるものを手にしたいと思っていますので,40名程度を相手にアンケートぽいものをサーバーレスで作ってみたいと思ってるところなんです。
そこまでたどり着くかどうかはさっぱりですが,楽しいですし,やってみたいところ。。
JScript mp3の再生について 書き残し
前回のタイマーで一番時間がかかった点の記録。
JavaScriptでmp3を鳴らすのはとても簡単だったのに,JScriptの場合はそうでなかった点。
というかそれに関する記述を探すのがとても大変でした。なので書き残し。
ちなみにわたしはDreamweaverを使ってJavascriptの学習をしています。。
Javascriptの場合はAudioオブジェクトがあるのでかなり楽でした。
var pu = new Audio(); pu.src = "pu.mp3"; pu.volume = 0.5; pu.play();
これだけで音が鳴らせます。volumeについては0~1の間で設定。ほんとにすごく簡単。
でも,このままではHTAで,つまりJScriptではと言っていいんでしょうか,鳴らせません。
そこでやってるのが
var pu= new ActiveXObject("MediaPlayer.MediaPlayer"); pu.Volume=-10000; //音量を0に pu.FileName = "pu.mp3"; pu.Volume=0; //音量最大に -10000~0 規定値 -600 pu.play();
Createobjectに相当するやつなんでしょう。これで似たようにかける。
Audioタグを使ったり,ライブラリを使う方法は難しそうでめんどくさそうで 見送りました。
こちらの問題点はFileNameを設定したタイミングかな,そこで音がいきなりなります。
なので一度Volumeを最小に相当する-10000にして,適当なタイミングで音量をもどして使っています。
ひたすら検索しまくって探してたどりついたので,元記事がもうわかりません。。
見つけたら貼ります。
ここを除けばけっこうあっさりできてた気がしますので,ほんと苦労した内容でした。
年が明けてしばらく経ちますが。
のんびりしてたらもう5日も経ってました。
最近はVBAからは離れていますが,仕事が始まればまたデータ処理で思い出すんだと思います。
VBAからはすこし離れていますが,しばらく前に興味を持ったJavaScriptの勉強をしているところです。
全然わからない → 他人のコードを切り貼りしたり ちょこっとずつ付け足していくとなんとなく物が作れるようになってきました。
とても役に立ちそうな言葉だと思いますし,ブラウザを基本とすれば大概いろいろつくれそうなものなんだなぁというところまでは来ています。
でも,ローカルのファイルの操作となると File API とかいうやつを使わないといけないんだなぁ 面倒だなぁと思いながらそれでもいろいろといじってると,
HTA に出会いました。HTML Applications ってやつですね。
Windows10では少なくとも使えるみたいです。現在の職場ではOSはWindows10なので,少なくとも数年はいける。
JavaScript自身は HTML5 と CSS とセットでたぶんずーっと使えそうな予感ですので,そちら側はブラウザを元とするものについてはいけそうです。
HTAになると,微妙に JScriptとかVBScriptになり,ちょこっとずつ仕様が変わるので,思った通りにいかないことも多々ありますが,
ローカルファイルにアクセスできる
セキュリティに関して制限が甘い(警告類があんまりでない)
htmlで気軽に書いてるのになんか立派なアプリケーションぽく見える
もちろんインストールとかいらない
など,私にとってはかなりの魅力を持ったもののようです。
数年戦えますし,JavaScriptの学習にも十二分にもなりますので,OfficeのVBAとJavaScriptと HTAで遊び続けてものにしようと思います。
JQueryもローカルにライブラリ落としとけば私の職場の環境でもつかえそうです。JQueryまで理解すればたぶん本職ではないプログラマには十分かなぁと思ったり。。
本はひたすら買い漁りました。かなり出費してしまいましたが,長く使える知識になってくれると思っています。
さて,作ったものを載せてみます。
元はPowerPointのVBAで作って授業中に使っていたタイマーと同じものなんですが,PowerPointってExcelのThisworkbookに相当するものがないので,他のスライドショーとの共存が難しいです。
基本はOneNote主体で授業を構成しているので,それでもいいんですが,PowerPointも使いたいよなぁと常々思っていました。
最初はブラウザで動くものをJavascriptで作り,満足していたんですが,表示の面でツールバーとかがいろいろ残るので不満が残るものが最初にできました。
CSSやJavascriptがフルに使えるという意味でそちらを優先するものも今後いろいろ試してはみますが,タイマーはコンパクトであってほしい。そこは譲れない。
なので,いろいろな制限をのむ形でHTAで作ってみました。 メモ帳に張り付けて 文字コードUTF-8で保存します。拡張子はhtaで。。
音もなるように作ってるんですが,音を鳴らすためにはどこからかmp3を拾ってきて 同じフォルダに pu.mp3 start.mp3 end.mp3 とリネームして入れてください。
www.kurage-kosho.info
こちらのページなどの音がおすすめかも。クレジット表示なしでも使っていいですよ,と書かれていますので,コンパクトさ優先の私にはありがたいです。
アプリケーションを聞いてきたら Microsoft HTML アプリケーションホスト みたいなやつを選んでください。
<!DOCTYPE HTML> <html lang="ja"> <HTA:APPLICATION SCROLL="no" NAVIGABLE="yes" CAPTION="yes" /> <head> <title></title> <meta http-equiv="content-type" content="text/html;charset=UTF-8" /> <!--CSS--> <style type="text/css"> a.Link{ text-decoration: none; display: block; width: 100%; height: 100%; } a.Timer{ text-decoration: none; font-size:160px; color:red; display: block; line-height: 1.1; font-family:"Comic Sans MS", "cursive"; text-align:center; } a:hover{background-color:yellow;} table { border-collapse: collapse } table td{ text-align:center; width:150px; height:50px; border:1px solid black; font-size: 40px; } </style> <!--JavaScript記述--> <script type="text/javascript"> var spanMyTime;//時間 を 表示 する SPAN var spanlog; var time0; var timer;//経過時間のTimer var timeval; var pu= new ActiveXObject("MediaPlayer.MediaPlayer"); pu.Volume=-10000; //音量を0に pu.FileName = "pu.mp3"; var endSound= new ActiveXObject("MediaPlayer.MediaPlayer"); endSound.Volume=-10000; //音量を0に endSound.FileName="end.mp3"; var startSound=new ActiveXObject("MediaPlayer.MediaPlayer"); startSound.Volume=-10000; startSound.FileName="start.mp3"; //初期処理(各種DOMを取得) function init() { timer=null; resizeTo(480, 290); document.body.style.overflow = "hidden"; spanMyTime = document.getElementById("mytime"); spanlog=document.getElementById("log"); var time = ['10:00', '8:00', '7:00', '6:00', '5:00','4:00', '3:00', '2:00', '1:00', '0:30', '0:20','0:10']; var timesec = ['600', '480', '420', '360', '300', '240', '180', '120', '60', '30', '20','10']; var html = ['<table>']; for (var c = 0; c < 4; c++) { html.push('<tr>'); for (var r = 0; r < 3; r++) { html.push('<td><a class="Link" href="#" onclick="startTimer(' + timesec[c+4*r] + ',true)">'); html.push(time[c + 4 * r]); html.push('</a></td>'); } } spanMyTime.innerHTML = html.join(''); spanlog.innerHTML=""; } function startTimer(tm,flg) { pu.Volume=0; //音量最大に -10000~0 規定値 -600 pu.stop(); endSound.Volume=0; //音量最大に endSound.stop(); startSound.Volume=0; startSound.play(); timeval = tm; if (flg==true) time0=tm; spanlog.innerHTML=""; // 既に 開始 し て いる 場合 は、 何 も し ない if (timer!= null) { stopTimer(); return; } spanMyTime.innerHTML = '<a class="Timer" href="#" onclick="stopTimer()">'+ timeConv(timeval) +'</a>'; timer = setInterval(interval, 1000); } function stopTimer() { if (timer!= null) { clearInterval(timer); } // timer に null を 代入 する timer = null; spanMyTime.innerHTML = '<a class="Timer" href="#" onclick="startTimer('+timeval+',false)">' + timeConv(timeval) + '</a>'; spanlog.innerHTML='<a href="#" onClick="init()"> BACK </a> <a href="#" onClick=startTimer('+time0+',false)> ReStart ' + timeConv(time0) + '</a>'; } function interval() { // 経過 時間 を 表示 timeval--; spanMyTime.innerHTML = '<a class="Timer" href="#" onclick="stopTimer()">' + timeConv(timeval) + '</a>'; if (timeval == 0) { clearInterval(timer); endSound.play(); timer=null; spanlog.innerHTML='<a href="#" onClick="init()"> BACK </a> <a href="#" onClick=startTimer('+time0+',false)> ReStart ' + timeConv(time0) + ' </a>'; spanMyTime.innerHTML='<a class="Timer" href="#" onclick="startTimer('+time0+')">' + timeConv(timeval) + '</a>'; } else { if (timeval % 5 == 0) pu.play(); if (timeval < 5) pu.play(); } } function timeConv(tm) { var fun; var byou; fun = Math.floor(tm / 60); byou = ("0" + tm % 60).slice(-2); return fun + ":" + byou; } </script> <!--JavaScript ここまで--> </head> <body onload="init()"> <span id="mytime"></span> <span id="log"></span> </body> </html>
ちなみに,音を鳴らすたびに微妙に時間はずれていきますので 10分のを回すと音によるのかもしれませんが3秒くらいずれました。
気になる方は使えません。私は気にならないのでたぶん使います。
あとはBase64とかいうやつで文字列に直せば音もソースに組み込めるんでしょうか,そんな知識はないのでやってはいませんが,いろいろと奥は深いんでしょうね。。
今後もいろいろ試してみようと思っているところです。
部品づくり 図形がどのセルの上にあるか
imihitoさんに教えていただいた application.caller TopLeftCell BottonRightCell これらはとても便利そう。
注意すべきは,自分で作り自分だけが使うときは問題ないけど少しだけ図形がずれる,ということがあると想定外の不具合はありそうです。
Altキー押しながらセルの上にきっちり図形を置くと,TopLeftCellは想定通り動きますが,BottomRightCellは右下のセルを返します。
自分の想定ではTopLeftCellのほうを使えばいい,となりますが,ほんのちょこっとずらされてしまうだけでだめになるはず。
なので,図形の真ん中の座標で判定させてみるテストをしてみました。
Sub test() Dim Sht As Worksheet: Set Sht = ActiveSheet Dim Shp As Shape: Set Shp = Sht.Shapes(Application.Caller) Dim CenterX As Long, CenterY As Long CenterX = Shp.Left + Shp.Width / 2 CenterY = Shp.Top + Shp.Height / 2 Dim Rng As Range: Set Rng = Sht.Range(Shp.TopLeftCell.Address & ":" & Shp.BottomRightCell.Address) Dim r As Range For Each r In Rng If CenterX >= r.Left And CenterX < r.Left + r.Width And CenterY >= r.Top And CenterY < r.Top + r.Height Then MsgBox r.Address Exit For End If Next
負荷を減らすべく,評価対象のセルの数を少なくできてたらいいな。
もしこれらで取得するセルを利用する場合は,セルを間違ったら大変なことになるはずなので,基本的には図形名等にセルアドレスを忍ばせて,それを利用することで想定外は無くすべきだと考えますが,次善の策としてはかなり有用だなぁと思います。
それにしてもCallerプロパティはいいですね。これは今後コード書くときに重宝する気がしています。
メモ
Excelで図形を作ってOnActionを使ってみようとしていたら,次の記事を見つけました。
Excel VBA を学ぶなら moug モーグ | 即効テクニック | OnActionで実行するプロシージャに引数を渡す
図形にマクロをつけて,引数もつけれると(;´▽`A``
これはいい。
軽くテストしてみました。
Sub test() Dim Sht As Worksheet: Set Sht = ActiveSheet Dim Rng As Range: Set Rng = Sht.Range("c5:e8") Dim c As Range For Each c In Rng With Sht.Shapes.AddLabel(msoTextOrientationHorizontal, c.Left, c.Top, c.Width, c.Height) .Name = c.Address(False, False) & "_BTN" .OnAction = "'test2 """ & .Name & """ '" '.OnAction = "'test2 ""印刷""'" End With Next End Sub Sub test2(Str As String) MsgBox Str End Sub
セルのシングルクリックイベントの代わりに図形をのせているので,各セルのleft,top,width,heightを使って図形を書き,それにOnActionをのっける。
セルのアドレスを捕まえることができるなら,いろいろとやれるのでそのためのものです。
testマクロを動かすと,
セルの上に図形をきれいにはりつけます。
無色透明にするなら .Fill.Visible=msoFalse をすればいいのかな。
これを実行すると,そのセルを選んだら(そこに貼り付けられている図形をクリックしたら)
このように,ちゃんとアドレスにしたがった値を返せます。
これはきっといいものな気がします。
onActionでマクロを貼り付けられた図形を動かすのはちょっと面倒なので,その点もいい感じ。
シートに貼る形のActiveXのリストボックスが,解像度が変わったり,タブレットで縦横表示が切り替わり続けると容易に表示が崩れたりと役立たずだったので,
リストボックス風なものを自分で実装したりしていました。
それを実現するためのいい手段が手に入った気がします。
追記 さらにメモ
のコメントのところから抜粋
参考にさせて頂き、助かりました。
第二引数の指定方法が分かりましたので、例示しておきます。
Sub AAAA(str1 As String, str2 As String)
.OnAction = "'AAAA ""引数1"", ""引数2""'"
きっといつか使う
さらにさらに追記
まぁこれも面白いわけですが,Powerpointの時もそうでしたが,セルに書く必要ないじゃないか という根本的なところにいきますね。。
セルにこだわらずに,加えた図形群でリストボックスぽいものをやる方法を考えていこう。