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の時もそうでしたが,セルに書く必要ないじゃないか という根本的なところにいきますね。。
セルにこだわらずに,加えた図形群でリストボックスぽいものをやる方法を考えていこう。
トグル入力のコード Excel VBA
ブログ名前詐欺中です。 今取り組んでることのための部品。
キーボードを使わずタブレットだけで作業をする。
複雑なインターフェースは準備できない。 でも簡単な入力方法を実装したい。
いつも思いつくのは,お風呂に入ってるときや,帰宅,出勤時。
考えを変えるタイミングって大事ですね。
さて,とても単純なヤツデス。
Sub クリック入力(Add As String, Min As Long, Max As Long) Dim Rng As Range: Set Rng = ActiveSheet.Range(Add) Rng.Value = Rng.Value + 1 If Rng.Value > Max Then Rng.Value = Min End Sub Sub Sht1_E5() Call クリック入力("e5", 0, 5) End Sub Sub Sht1_E6() Call クリック入力("e6", 0, 1) End Sub
(´▽`) '`,、'`,、 ミジカイ
私は雑な人間ですが,さすがに,上のSSはわざとちょっとずれてるのをスルーしています。
E5,E6のセル上にボタンにするための透明な図形をのせて,それらに Sht1_E5 Sht1_E6をマクロ登録しています。
動画とらないで大丈夫ですよね。。あまりにも短いコードですから。。
クリックするたびに数値が1ずつ増え,最大値を超えると最小値になるよ,というコードです。
Excelのリスト入力は便利なんですけど,キーボードやマウスが使えない時ってあれってかなりちっちゃい。
その時のためのインターフェースとして考えてみました。明日実装してみよう。。
毎年この時期はデータ処理。。
教員をしていると,入試の時期が必ず来ます。
そろそろ,また今年の分の調整をし始めないといけません。
思えば,様々なアドバイスをいただき始めたのも,データ処理をどうするか,という話の頃から。
とてもありがたいことです。以前とはコードの書き方もけっこう変化しました。
そして,私はいつも同じ付近に考え方を戻して,いろんなことを気分でやるので,今回はある意味ふりだしに戻った感が否めません。
ですが,VBA組める同僚はほとんど出会わない職場ですので,他の人でも見てわかる,とか,自分が中身を忘れてもみればわかる・・・
そのようなものを求めるのもしょうがないのかなぁと思います。
Infomentさんのブログで配列のソートに取り組まれています。
PowerPointでものづくりをするときは否応なしにそっち方向でやっていかないといけないので,とても楽しみに様子を見させてもらってます。
わたしは,とりあえず今年は一時ワークシートを作ってそこで作業する,という方向に戻して考えようということにしました。
Stopでもそのあたりに入れておけば,ソートの途中経過など確認しやすいから,というのもありますね。
とりあえずてきとーに組んだのがこちら。Excel VBAです。
Function ソート(ソース As Variant, ParamArray Keys()) As Variant Dim Data As Variant, 行数 As Long, 列数 As Long If TypeName(ソース) = "Range" Then 行数 = ソース.Rows.Count 列数 = ソース.Columns.Count Data = ソース.Value Else 行数 = UBound(ソース, 1) 列数 = UBound(ソース, 2) Data = ソース End If Dim TempSht As Worksheet Set TempSht = ThisWorkbook.Worksheets.Add Dim s As Worksheet, No As Long, flg As Boolean Do No = No + 1 flg = False For Each s In ThisWorkbook.Worksheets If s.Name = "作業用一時シート" & Format(No, "00") Then flg = True Next Loop Until flg = False TempSht.Name = "作業用一時シート" & Format(No, "00") Dim SObj As Sort, TempRng As Range, i As Long, j As Long Set TempRng = TempSht.Range(TempSht.Cells(1, 1), TempSht.Cells(行数, 列数)) TempRng.Value = Data Set SObj = TempSht.Sort With SObj .SortFields.Clear .SetRange TempRng .Header = xlYes For i = 0 To UBound(Keys) - 1 Step 2 .SortFields.Add Key:=TempRng.Cells(1, Keys(i)), Order:=Switch(Keys(i + 1) = True, xlAscending, Keys(i + 1) = False, xlDescending) Next .Apply End With ソート = TempRng.Value Application.DisplayAlerts = False TempSht.Delete Application.DisplayAlerts = True End Function Function 抽出(ソース As Variant, flg As Variant, ParamArray Keys()) As Variant Dim i As Long, j As Long, k As Long, l As Long, Flg2 As Boolean Dim 行数 As Long, 列数 As Long, tmp() As Variant 行数 = UBound(ソース, 1) 列数 = UBound(ソース, 2) If flg = True Then ReDim tmp(1 To 行数, 1 To UBound(Keys) + 1) For i = 1 To UBound(ソース, 1) k = 1 For l = 0 To UBound(Keys) tmp(i, k) = ソース(i, Keys(l)) k = k + 1 Next l Next i Else ReDim tmp(1 To 行数, 1 To 列数 - UBound(Keys) - 1) k = 1 For j = 1 To UBound(ソース, 2) Flg2 = True For l = 0 To UBound(Keys) If j = Keys(l) Then Flg2 = False Next If Flg2 = True Then For i = 1 To UBound(ソース, 1) tmp(i, k) = ソース(i, j) Next k = k + 1 End If Next End If 抽出 = tmp End Function Sub テスト() Dim ret As Variant ret = 抽出(ソート(Sheet1.Range("a1").CurrentRegion, 8, True, 5, True), True, 5, 6, 7, 9) Sheet4.Cells(1, 1).Resize(UBound(ret, 1), UBound(ret, 2)).Value = ret Stop End Sub Sub テスト2() Dim a As Variant: a = Sheet1.Range("a1").CurrentRegion.Value Dim b As Variant: b = 抽出(a, False, 2, 3) Stop End Sub
自分用メモが主のブログでもありますので,説明とかいろいろと省きまくりなのはスルーしてほしいところです。
一時シートをつくり,そこにデータを放り込んでソートオブジェクトにおまかせ,というやつです。
あと,ソートの結果の一部を利用したり,または,ほとんど利用するんだけど,数列分は消したいという作業をよくやるので,抽出する関数も用意しています。
Sheet1のデータを取り込んで,一部抽出したり,ソート結果をさらに抽出する,という作業を テスト や テスト2
とかでやってみてますが,見た目にはまともに動いてそうでした。。
結局,速いアルゴリズムが優れたソートを自分はあまり実装できず,できてバブルソートだったりするので,
ExcelならSortオブジェクト使い倒してしまえ,という気分で作ったものです。
いくつキー与えてもやってくれるし,このマクロ組んでたら,Sortにcustomorderが使えるというのに今更ながらに知って驚いたり,
やっぱりいろいろと気楽にやってみるもんだなぁと思ったところです。。
--
わたしがいる学校ではそろそろ文化祭。
同僚に突然仕事を振られて,準備期間ほんのちょっとなのに 販売で使うシステムを組まされたりしています。
かなり以前に,小さなテキストメモみたいなものを吐き出して共通に見れるフォルダに放り込み,それをデータとして使う,,というシステムを作ったことがありました。
きちんとルール作りをすれば,データはその1KB程度のテキストがたくさん存在するだけであり,Excelが固まってもデータはほとんど消えることなく,
システムも小さくて済む。とても気楽に多人数でデータを扱えるシステムができている気がしています。
まさかこんなところで日の目を見るとは思わないものづくりでしたが,いつどんなものが役に立つかわからないものだなぁと思う。
思いつきは役に立とうが立つまいが一度は形にして,蓄積していけばいつか時間がないときにささっと対応できるなぁ,と2年ほど前の自分をほめつつ,
極めて短い準備期間なので,不具合をとても不安にも思いつつ作業しているところです。。
ひと段落しています。(VBAコード一切ありません)
とりあえず,作った教材を紹介する,という機会が終わりました。
仕事で人にものを説明することを日々やっている割に,やはり緊張するものですね。
また,PowerPoint2016のノートPCとPowerPoint2013のタブレットで動作確認をし,さらに直前に,
説明する電子黒板と同じ状態であろう,隣の部屋の電子黒板で動くことを確認していたのに,
実際説明するとき(PowerPoint2013でした),途中でマクロが止まってΣ(・ω・ノ)ノ!びっくりしました。
こういうとこは,さすが自分だな・・(;´▽`A``と思う次第。。
疑問なのは,普段スライドショーの完遂が優先され,コードエラーを直接吐かず沈黙するPowerPointが
エラーを吐いて止まったこと。。
どういう状態だったのか興味があります。確かめようはありませんが。。
いい経験ですね。やはり,動かす機械で確認をとっておかないといけないです。
一部,思い通りにいかなかったとはいえ,その部分はどちらかといえば枝葉の部分で主幹部分ではなかったので,
軽くスルーしてしまいました。
自分の適当さをそこでも感じたところです。
・・・
終わったし,何かまた何か作ってみよう。何に手を出そうか。。
( ´ー`)フゥー...