Retro Menu

2024年4月24日更新
これは今では見かける事が無くなったメニューソフトです。
しかし、MS-DOS 全盛の頃は良く使われていました。
それをふと思い出してプロデルで再現してみたオリジナルです。


昔はハードディスクのおまけソフトとして付属していたり、
フリーソフトとしても結構な数が出回っていました。
シンプルなソフトですが多くの基本的な要素が含まれているので、
プロデル初心者の教材として最適だと思いました。
メニュー本体の仕組みから周辺のおまけ機能まで、
一つずつ取り上げて行く予定です。
[ 01 メニューとしての役割 ]
メニューなので外部ソフトを簡単に起動する事が使途になります。
外部ソフトを起動した後は邪魔にならないようにする必要がありますし、
その外部ソフトが終了後にはメニューをアクティブにする必要があります。
従って常駐ソフトの形態にしました。
[ 02 メニューボタンの生成 ]
先ずは外部ソフトを登録する為の多数のボタンが必要です。
その数が数十ともなれば全てを一画面に並べるのは現実的では有りません。
レトロメニューではタブ切り替え方式を採用して10×7を用意しました。
それを一つずつコーディングしていたのでは効率が悪いので、
レトロメニューでは動的生成方式を採用しました。
下記がその部分のコードになります。

メニューボタンを生成する時の手順
  最大釦数=10
  X=10
  Y=15
  W=300
  H=35
  番号を1から増やしながら10まで繰り返す
   ボタンというボタンをタブフレーム1の選択タブへ作る
    その位置と大きさを{X,Y,W,H}に変える
    その見た目を「標準」に変える
    その名前を「ボタン[番号]」に変える
    その内容を「[タイトル一覧(番号)]」に変える
    そのフォントを「メイリオ,14.25」に変える
    その背景色を「白」に変える
    そのクリックされた時の手順は、ボタンがクリックされた
    その右クリックされた時の手順は、右ボタンがクリックされた
   Y=Y+35
  繰り返し終わり
  タブフレーム1を更新する
 終わり


ここで「タイトル一覧」というのはボタンに表示する内容の配列です。
詳細は後ほど書きます。
[ 03 多様な実行形態に対応したデータ構造 ]
実行可能なプログラムを登録して起動させるだけならシンプルなのですが、
そのプログラムがバッチファイルだったり引数を伴っている事も有ります。
それ等全てに対応させる為の処理とメニューデータの構造が必要です。

ページ1
 メモ帳を起動,notepad.exe
 ペイント起動,mspaint.exe
 メモ帳を起動(bat),メモ帳起動.bat
 メモ帳(引数有り),notepad.exe;dummy.txt
 メニュー05,
 メニュー06,
 メニュー07,
 メニュー08,
 メニュー09,
 メニュー10,
 ページ2
 メニュー11,
 メニュー12,


検討した結果、レトロメニューで採用したのはこの様な構造の、
一行がボタン一つ分のデータになっている2カラム構成のCSV形式です。
第1カラムがボタンに表示する内容で第2カラムが実行内容です。
更に第2カラムを「;」で区切る事で引数を渡せるようになっています。
[ 04 メニューデータを処理する ]
メニューデータは至ってシンプルなので処理といっても簡単なものです。
読み込んだデータを「,」で区切って表示する部分とコマンド部分に分けて、
其々を配列に収めているだけです。

メニュー項目を分解する時の手順
  タイトル一覧は、{}
  コマンド一覧は、{}
  番号を1から増やしながら10まで繰り返す
   メニュー内容は、メニュー一覧(番号)
   メニュー内容を「,」で区切ってメニュー配列とする
   タイトル一覧にメニュー配列(1)を加える
   コマンド一覧にメニュー配列(2)を加える
  繰り返し終わり
 終わり

[ 05 動的生成されたボタンのイベント処理 ]
動的に生成されたボタンのイベントはどれも同じで、
「ボタンがクリックされた時の手順」に集約されています。
どのボタンがクリックされたかの判定と実行方法の選択は、
下記のようにして行いました。

ボタンがクリックされた時の手順
  対象タブ番号は、「[選択タブ番号]」
  選択番号は、タイトル一覧から「[発生元の内容]」を探したもの
  番号は、選択番号(1)
  選択メニューは、コマンド一覧([番号])
  コマンド配列は、選択メニューを「;」で区切ったもの
  コマンド数は、コマンド配列の個数
  コマンド名は、コマンド配列(1)
  もし(コマンド名が空)なら手順を抜ける
  
  コマンド種類は、(コマンド名の拡張子だけ)の小文字
  もしコマンド種類が「」なら
   一覧は、[今の位置]のファイルの一覧
   結果は、一覧から「[コマンド名]」を探す
   もし[結果]が{}でないなら
    配列は、一覧([結果(1)])を「.」で区切ったもの
    コマンド種類は、配列(2)
   もし終わり
  もし終わり
  
  もし(コマンド数が1)なら
   引数は、「」
  そうでないなら
   引数は、コマンド配列(2)
  もし終わり
  メニューを格納する
  コマンド種類について分岐
   「」の場合
    もし引数が「」なら
     [コマンド名]をコマンド実行する
    そうでないなら
     「[コマンド名] [引数]」をコマンド実行する
    もし終わり
   「bat」の場合
    「[コマンド名] 引数」をコマンド実行する
   「cmd」の場合
    結果は、「[コマンド名] 引数」をコマンド実行する
    番号は、(結果の1文字目から1文字取り出したもの)のアスキー番号
    もし(番号が13でない)なら
     結果を表示する
    もし終わり
   「exe」の場合
    もし引数が「」なら
     [コマンド名]を起動して待つ
    そうでないなら
     [コマンド名]を[引数]として標準で起動して待つ
    もし終わり
   他の場合
    「不明なコマンドです。」を表示する
  分岐終わり
  待機する
  メニューを表示する
 終わり


コマンドの種類を拡張子から判別して処理を分けています。
また、コマンドを「;」で区切る事でプログラムと引数に分けています。
通常、選択されたボタンの判定はボタン番号で良いのですが、
不都合が有ったのか回りくどい方法を採っています。
それが何だったのか思い出せません。
[ 06 メニューへの登録方法 ]
単純構造のCSVファイルなのでメモ帳などで直接書き換えても良いのですが、
PCに不慣れな方にも簡単に使えるように専用のUIを用意しました。
メニューのボタン上で右クリックすると機能するようにしています。


右ボタンがクリックされた時の手順
  対象タブ番号は、「[選択タブ番号]」
  選択番号は、タイトル一覧から「[発生元の内容]」を探したもの
  番号は、選択番号(1)
  選択タイトルは、タイトル一覧([番号])
  選択メニューは、コマンド一覧([番号])
  
  コマンド配列は、選択メニューを「;」で区切ったもの
  要素数は、コマンド配列の個数
  もし(要素数>1)なら
   引数文字列は、コマンド配列(2)
  そうでないなら
   引数文字列は、「」
  もし終わり
  コマンド名は、コマンド配列(1)
  メニューエディタのタイトルを「メニュー登録」に変える
  メニューエディタのメニュータイトルの内容を選択タイトルに変える
  もし(コマンド名が空でない)なら
   メニューエディタの内容を「メニュー登録」に変える
   コマンド種類は、(コマンド名の拡張子だけ)の小文字
   もしコマンド種類が「」なら
    一覧は、[今の位置]のファイルの一覧
    結果は、一覧から「[コマンド名]」を探す
    もし[結果]が{}でないなら
     例外監視
      配列は、一覧([結果(1)])を「.」で区切ったもの
     発生した場合
      エラー音を鳴らす
      メニューエディタを表示する
      手順を抜ける
     監視終わり
     コマンド種類は、配列(2)
    もし終わり
   もし終わり
   
   メニューエディタのプログラムパスの内容をコマンド名に変える
   メニューエディタのコマンドライン引数の内容を引数文字列に変える
   もし(コマンド種類が「bat」)なら
    メニューエディタのチェックボックス1の内容を、
     「バッチファイル編集」に変える
   そうでないなら
    メニューエディタのチェックボックス1の有効を×に変える
   もし終わり
  もし終わり
  呼出元は、「メニュー」
  メニューエディタを表示する
 終わり


ファンクションボタンにも同様の機能を用意しました。
[ 07 おまけ機能について ]
おまけ機能とはメニューとは直接関係が無い時計やカレンダ、
システムリソース等の各種情報を表示する機能の事です。
アナログ時計やカレンダがランチャに必要だったのかは分かりませんが、
現在より極端にシステムリソースが少なかった時代なので、
メモリの使用状況等は重要でした。
レトロメニューでは極最近まで凝った物を表示していましたが、
おまけの機能なのでカレンダは用意されたコントロールに変更し、
アナログ時計もシンプルな物に変更しました。

アナログ時計を実装する為に必要となるコントロール等は、
タイマーとキャンバスなのでこれ等を使った事が無い方は読み飛ばして、
基本的な使い方を理解してから再チャレンジして下さい。
また、三角関数の知識も必要です。

現在の時刻を取得する時の手順
  現在時刻は、今の時刻
  時刻配列は、現在時刻を「:」で区切ったもの
  現在時は、時刻配列(1)
  現在分は、時刻配列(2)
  現在秒は、時刻配列(3)
 終わり


これが時刻を取得する為の手順になります。

針を動かす時の手順
  もしHX=0でなければ
   例外監視
    時針を消す
   発生した場合
    //
   監視終わり
   例外監視
    分針を消す
   発生した場合
    //
   監視終わり
   キャンバス1を更新する
  もし終わり
  時針角は、[(現在時を12で割った剰り*30)+(現在分/2)-90]
  分針角は、[現在分*6-90]
  HX=([時針角]度のコサイン)*60
  HY=([時針角]度のサイン)*60
  MX=([分針角]度のコサイン)*70
  MY=([分針角]度のサイン)*70
  キャンバス1へ線を描いて時針とする
  時針の位置と大きさは、{100,100,HX,HY}
  時針の線色を黒に変える
  時針の太さを5に変える
  キャンバス1へ線を描いて分針とする
  分針の位置と大きさは、{100,100,MX,MY}
  分針の線色を黒に変える
  分針の太さを3に変える
  キャンバス1を更新する
 終わり


こちらはキャンバス上に時計の針を表示する為の手順です。
これ等の手順をタイマーを使って一定時間毎に走らせています。
時計の文字盤はキャンバスの背景画像として表示しています。
[ 08 システムリソースの表示 ]
システムリソース関係はプロデルで用意された機能で取得可能です。
レトロメニューでは限りあるウィンドウ スペースを有効に使うべく、
グラフ内に文字列を表示するように工夫しました。
当初、タイマーはアナログ時計とは別の物を用意していましたが、
現在はタイミングを取る事で一つに集約しています。
[ 09 電力使用率の表示 ]
以前は電力の使用率などは気に掛けた事は無かったのですが、
2022年3月の節電要請が切っ掛けで変わりました。
最初はフリーで公開されているAPIを利用していたのですが、
途中から機能しなくなってしまったので自前で作る事にしました。

電力使用率を取得する時の手順
  デイコードは、今日を「yyyyMdd」に整えたもの
  R=3
  C=6
  電力会社名について分岐
   「北海道電力」の場合
    サイトは、「北海道電力のデータのサイトアドレス」
   「東北電力」の場合
    サイトは、「東北電力のデータのサイトアドレス」
   「中部電力」の場合
    サイトは、「中部電力のデータのサイトアドレス」
   ' 以下省略
  分岐終わり
  もし(サイトが「」)なら
   「電力使用率を取得できませんでした」を「エラー」として、
   警告アイコンで表示する
   手順を抜ける
  もし終わり
  
  結果は、HTTPで「[サイト]」を取得したもの

  行内容は、結果から[R]行目を一行だけ
  取得配列は、行内容を「,」で区切ったもの
  電力使用率は、取得配列([C])
  [電力使用率]を返す
 終わり


当初はWebスクレイピングの手法で取得していたのですが、
後にCSVデータを配布していると分かり変更しました。
中国電力は単独でのデータ配布を行っていないので取得できません。
何れにしても会社の方針変更等でサイトが変更になると機能しなくなります。

以下に実際に調べたアドレスを載せておきます。
北海道電力:https://denkiyoho.hepco.co.jp/area/data/juyo_01_[デイコード].csv
東北電力 :https://setsuden.nw.tohoku-epco.co.jp/common/demand/juyo_02_[デイコード].csv
中部電力 :https://powergrid.chuden.co.jp/denki_yoho_content_data/juyo_cepco003.csv
北陸電力 :https://www.rikuden.co.jp/nw/denki-yoho/csv/juyo_05_[デイコード].csv
東京電力 :https://www.tepco.co.jp/forecast/html/images/juyo-d1-j.csv
関西電力 :https://www.kansai-td.co.jp/yamasou/juyo1_kansai.csv
四国電力 :https://www.yonden.co.jp/nw/denkiyoho/juyo_shikoku.csv
九州電力 :https://www.kyuden.co.jp/td_power_usages/csv/juyo-hourly-[デイコード].csv
沖縄電力 :https://www.okiden.co.jp/denki2/juyo_10_[デイコード].csv

[ 10 天気予報の表示 ]
天気予報表示に関しては提供元のサービス打ち切り等で何回か変更しています。
現在の「wttr.in」に変えてからも変更せざるを得ない状況が有りました。
当初は「curl wttr.in/chofu_1pqt_lang=ja.png」のようにしていました。
この方法だと画像で取得できるので文字化け等は無く良かったのですが、
今は一時的に画像オプションが使えなくなっているようです。
仕方が無いので「curl wttr.in/chofu?1qT」のように変更して、
テキストで取得してスペースに収まるように成形して表示しています。
[ 11 動的生成メニューの再考 ]
既に前回までに主要な内容に関しては書きました。
今回は核となる動的生成メニューに関しての追記です。

この5回目で押されたボタンを特定するのにボタンの内容を利用しています。
「そうした理由を思い出せない」と書きました。
「タイトル一覧という配列が有ったから利用した」というのが有力ですが、
コメントを残していないので本当のところは分かりません。

通常はボタンの名前で分岐させれば良いのですが、
レトロメニューではコマンド種類でも分岐させる必要が有ったので、
単純に押されたボタンの番号だけが必要だったのかも知れません。
尚、番号を取得するだけなら下記の方法でも可能です。
 方法1:「番号は、[発生元の名前を「ボタン」で区切ったもの](2)」
 方法2:「番号は、(発生元の縦-15+35)/35」
要するに押されたボタンオブジェクトは「発生元」で取得できるので、
そこから好きな方法で特定すれば良いだけの事です。

動的生成メニューは下記サンプルの方が理解が早いです。

メイン画面を表示する
 待機する

 メイン画面とは
  ウィンドウを継承する
  はじめの手順
   初期化する
   //貼り付けた部品に対する操作をここに書きます
  終わり
  初期化する手順
   //自動生成された手順です。ここにプログラムを書き加えても消える場合があります
   この内部領域大きさを{196,230}に変える
   この内容を「メイン画面」に変える
  終わり

  開いた時の手順
   左端=20
   上端=10
   釦幅=160
   釦高さ=30
   キャプションは、「menu.dat」から読み込んだもの
   キャプション一覧は、キャプションを[改行]で区切ったもの
   釦数は、キャプション一覧の個数
   動的にボタンを生成する
  終わり

  動的にボタンを生成する時の手順
   値を1から[釦数]まで増やしながら繰り返す
    動的ボタンというボタンを作る
     その位置と大きさを{左端,上端,釦幅,釦高さ}に変える
     動的ボタンの名前を「ボタン[値]」に変える
     動的ボタンの内容を[キャプション一覧(値)]に変える
     その移動順を[値]に変える
     そのドラッグドロップを×に変える
    上端=上端+35
   繰り返し終わり
  終わり

  動的ボタンがクリックされた時の手順
   表示内容は、発生元の内容
   [発生元の名前]について分岐
    「ボタン1」の場合
     「[発生元の名前]:[表示内容]が押されました。」を表示する
    「ボタン2」の場合
     「[発生元の名前]:[表示内容]が押されました。」を表示する
    「ボタン3」の場合
     「[発生元の名前]:[表示内容]が押されました。」を表示する
    「ボタン4」の場合
     「[発生元の名前]:[表示内容]が押されました。」を表示する
    「ボタン5」の場合
     「[発生元の名前]:[表示内容]が押されました。」を表示する
    「ボタン6」の場合
     「[発生元の名前]:[表示内容]が押されました。」を表示する
     自分を閉じる
   分岐終わり
  終わり
 終わり


上記サンプルで利用している「menu.dat」の内容を以下に載せておきます。

キャプション1
 キャプション2
 キャプション3
 キャプション4
 キャプション5
 終 了


以上です。何かありましたらディスカッションでお待ちしています。