Knowledge
   

WideStudioプログラミング


2004/02/17

WideStudioで「Hello」

WideStudioで「Hello」
現在、SIPHAのパソコン側は、Visual Studioで作っています。でも、お金が大変なので、何かいいの無いかな〜って探していたら、「WideStudio」なるものを発見しました。す、すごい。これがフリー?とりあえず、「Hello」とやってみましたが、VBがC++な感じですね〜。他に使われている方いないのかな?まずはシリアル通信プログラムからですが、どうやってやったらいいんでしょう?もともとシリアル通信は、VCでもAPIでやってますので、同じようにやればいいんでしょうか?環境に慣れるのにちと時間要りそうですが(それはどのツールでも一緒)、今後、ちょっと使ってみて、いい感じでしたら報告したいと思います。

 

2004/02/24

WideStudio、その後

WideStudio、その後
20040224P00.JPG - 21,939BYTESごちゃごちゃ触ってみたり、ネットでいろいろ見てみるものの、イマイチ、感覚がわからないので、書籍を購入しました。とはいっても、家の周りの本屋では見当たらなかったので、「よし、amazon.co.jpとやらを使ってみよう」と、昨日思ったんですよ。んで、昨日のお昼頃オーダーしました。そうしたら、「もう届いている」ではありませんか!はや〜い。びっくりです。

 

2004/03/04

WideStudioでスプラッシュウィンドウらしきもの

WideStudioでスプラッシュ!
20040304P00.JPG - 12,853BYTESWideStudio、ちょっとプログラム作ってみました。とはいっても、「Helloなんとか」じゃないですよ。スプラッシュウィンドウもどき?(なのか本物なのかよくわかりませんが)を作ってみました。最初は違うだろ〜と声が聞こえてきそうですが、まずは形からです(笑)。かっこよくないといけませんから。

せっかくなので、オンラインマニュアルを読めばわかることはおいといて、ポイントを紹介させていただきます。

作ったものは…起動すると、メインのウィンドウ以外にもう1つ、起動表示用のビットマップを貼ったウィンドウを開き、1.5秒後に自動的に閉じるものです。よくアプリケーションでありますよね?起動するときに製品名とか表示されて、後ろでアプリケーションが起動処理をするやつ。アレです。いまのところ、これだ!という方法が良くわからないので、スプラッシュ風っていうのが正解なんでしょうか?

こんなふうに作ってみました。まずはアプリケーソンビルダを使います。

  1. プロジェクトを新規作成する。
  2. 新規ウィンドウを作る(SiphaMainと命名)。
  3. スプラッシュ表示用に普通にウィンドウを追加する(WinStartupSplashと命名)。
  4. スプラッシュ表示ウィンドウのプロパティをいじる。
      X/Y座標…適当
      横/縦幅…ビットマップファイルのサイズに合わせる。
      「背景画」…ビットマップファイルのファイルパス
      「タイトル属性」…枠
  5. スプラッシュ表示ウィンドウに「タイマー」を追加する(TimerExitSplashと命名)。
  6. タイマのプロパティをいじる。
      時間間隔…1500(たぶん、msecってことだと思うので、1.5秒だと思います)。
      継続…False(ウィンドウを閉じるために一発動けばいいので)
ここまでがWideStudioを操作して作った部分です。さて次はソースコード追加ですが、すべて「プロシージャ」から追加しています。やっていることですが、起動すると当然メインウィンドウが開きます。この時の、メインウィンドウの初期化イベントにて、スプラッシュウィンドウを開きます。次に、スプラッシュウィンドウの初期化イベントで、スプラッシュウィンドウ自身の位置を、デスクトップ中央に移動してタイマスタートします。んで、タイムアップしたらスプラッシュウィンドウ自身を、自分で見えなくします。
  1. SiphaMainにプロシージャ追加します。
      プロシージャ名称:StartUp(適当)、トリガ:INITIALIZE、関数名:ShowSplashWin
    この中でスプラッシュウィンドウを外部宣言。
      #include <WSCwindow.h>
      extern WSCwindow* WinStartupSplash;
    そして関数の中でスプラッシュウィンドウのプロパティを操作して「表示」にします。
      WinStartupSplash->setProperty(WSNvis, True );
  2. WinStartupSplashに、タイマ起動のためのプロシージャを追加します。
      プロシージャ名称:タイマ操作(適当)、トリガ:INITIALIZE、関数名:TimerStart
    この中で、タイマクラスを外部宣言します。
      #include <WSCvtimer.h>
      extern WSCvtimer* TimerExitSplash;
    そして、タイマクラスのプロパティを操作してスタートさせます。
      TimerExitSplash->setProperty( WSNrunning, True );
  3. WinStartupSplashに、ウィンドウを中央に持ってくるためのプロシージャを追加します。
      プロシージャ名称:ウィンドウ移動(適当)、トリガ:INITIALIZE、関数名:MoveWinStartupSplash
    WSappDevクラスのヘッダをインクルードします。これは、アプリケーションクラスと呼ばれるクラスで、WideStudioで作ったアプリケーションに必ずついてるクラスのようです。このクラスには、ディスプレイのサイズ情報とかも入っていますので、これを取得するのが目的です。
      #include <WSDappDev.h>
    そして、ウィンドウを操作するプログラムを書きます。ディスプレイのサイズと、スプラッシュウィンドウのサイズから、中央に表示するための座標を計算し、自分の座標を操作します。
      int nWSNx, nWSNy, nWork;

      WSDappDev* app = WSGIappDev();  // アプリケーションクラスの取得

      // スプラッシュウィンドウを中央に表示するための、ウィンドウ左上座標の計算
      nWSNx = app->getWidth()/2 - (int)(object->getProperty( WSNwidth ))/2;
      nWSNy = app->getHeight()/2 - (int)(object->getProperty( WSNheight ))/2;

      // ウィンドウを計算結果位置に移動する。
      object->setProperty( WSNx, nWSNx );
      object->setProperty( WSNy, nWSNy );
  4. 最後に、TimerExitSplashにプロシージャ追加します。タイムアップは、ACTIVATEでトリガがかかります。
      プロシージャ名称:OpeWindow(適当)、トリガ:ACTIVATE、関数名:CloseStartupSplash
    そして、WinStartupSplashウィンドウにアクセスするため、外部宣言を行います。…んでも、ここのところ、もっと違うやり方があるかもしれません。ちょっとこれは強引な気がします。
      #include <WSCwindow.h>
      extern WSCwindow* WinStartupSplash;
    んで、プロパティを操作して、非表示にします。これで「タイムアップでウィンドウが消える」という動作ができます。
      WinStartupSplash->setProperty( WSNvis, False );

こうやって考えてみると、実は、タイマのスタートって、INITIALIZEでかけてるのってまずいのかな?スプラッシュなので、構わないって感じですけど。ウィンドウが開いてからカウント開始するのが正しそうなので、別のトリガがいいのかもしれません。というわけで、さっそく「EXPOSE」に変えてみました。これは描画された時に発生するトリガです。「ウィンドウ表示=最初の描画が行われる→EXPOSEが発生する」と思いまして。このあたり、アプリケーションビルダでやると、めちゃ簡単です。マウスでちょいちょい。んで「実行」…あ、いい感じですね。スプラッシュの時はどっちでもいいんでしょうが、普通の時はこの方が良さそうです。

というわけでわかったこと。

  • タイマ
    タイマ(WSCvtimer)は、setPropertyでスタートするとスタートする。
    タイマ(WSCvtimer)は、インターバルと一発のモードがある。
    タイマ(WSCvtimer)は、タイムアップでACTIVATEが発生する。

  • ディスプレイサイズ
    ディスプレイのサイズは、WSDappDevクラスから取得する。
    WSDappDevクラスは、グローバルな関数のWSGIappDev()でポインタを取得してから使用する。

  • getProperty()で値取得後の使用方法
    getProperty()で得てすぐ使おうとする場合は、単なる代入にするとか、ちゃんと型をキャストしないとダメ(これ、すごくはまりました。オペレータ演算子が思っていたのと違っていました)
    nWSNx = app->getWidth()/2 - (int)(object->getProperty( WSNwidth ))/2;…OK
    nWSNx = app->getWidth()/2 - object->getProperty( WSNwidth )/2;…NG

  • プログラミングについて
    −C++ベースだと思うのですが、実際に自分でコーディングする起動関数とかは、クラスではなさそう。
    −同じトリガに対して、いくつもトリガ関数を書くことができる。
    −各クラスの実体は、グローバルに宣言されている模様。
    −起動関数は、起動関数ごとにソースファイルができていくので、起動元のオブジェクト名などを短くしたような名前などを使用することで、ユニークになるよう意識した方が良さそう。
    −起動関数を、アプリケーションビルダから削除したからといって、作られたファイルが削除されるわけではない。
    −起動関数の名前は、WideStudioとかにありそうな名前を使うと、ビルドできないような…。
    −プロシージャ名称は日本語が使える。けど、何に影響(効果)しているのかはよくわからない。単なる整理のためなんだろうか? 
    −表示するウィンドウの右下に斜線がつく。リサイズできないウィンドウを作っても斜線がつく。これはいったいなんだろう?
  • 「ビルド」−「実行」とすると、作ったアプリケーションを実行できるけど、アプリの方で操作して終了すると、「ビルド」メニューの中身が、いつまでも「実行中止」になったまま。さみしい。

相変わらず、プロシージャの「プロシージャ名称」の意味がわからず、適当に名前付けていたりします。お作法は、今日の分に関してはだいぶわかってきたのですが、依然、やりたいことについてはわかっていないです。

ONO様…本の読破ですが、最初は「うっ」っと思いました。でも、最初…斜め読み、2回目は割とまじめ、後は必要に応じて、と読んでいたら、結構、楽しく読めましたよ。個人的には、もうちょっと仙人の会話が欲しかったです。すべてはわかりませんが、とっかかりと、大雑把な概念を理解するのであれば、なかなか良い本だと思います。

それにしても、ここはどこだ?日本語が通じないぞ?というわけで、これから数日は、WideStudioネタになるかな(笑)。

ではでは!

2004/03/12

WideStudioでメニュー付きウィンドウにハマル

うぅ、相変わらず出先のSISOです(しかも、いつもに増して忙しい)。トランジスタ技術(H8のおまけ付き)は、友人にメールして買ってもらいました(3冊程)。たぶん、シリアル通信のレベルコンバータは買わないといけなさそうです(って、買った人はきっと、もう確認されてますよね〜)。そういえば、GOLDENWORKSさんのところで、基板で売っているUSB-SERIALコンバータが紹介されていましたが、あれに一緒に組み込んじゃって、マイコンアクセス専用にしちゃってもよさそうですね〜。んで、ついでにUSBから5V取り出してマイコンに供給したらモバイルですね!電車の中でも、飛行機の中でもマイコンソフトを開発できそうです。今度やってみよう。

WideStudioでメニュー
20040312P00.JPG - 3,922BYTES実は、はまりました。^^; ウィンドウにメニューを追加するには、まず、WSCmenuAreaを追加します。これだけでは、プルダウンメニュー…Windowsで、アプリケーションの上の方についてる、クリックするとびよーんと出てくるメニュー…は出ません。これに、WSCpulldownMenuをさらに追加します。この操作は、どちらもアプリケーションビルダのオブジェクトボックスから操作して追加できます。

 

■ALT+Fでメニューが開かない…うぅ、マニュアル読みなさいって感じ。
20040312P01.JPG - 10,194BYTESFile(F)なんてやってみたんですが、ALT+Fでメニューが開きませぬ。うう。VCとかだと、FILE(&F)とか書くと、ショートカットキーになるんですが、違うようです…とマニュアルと本を読むこと10分。WSCpulldownMenuに「ショートカット」というプロパティがあるのを発見。ここに文字を設定しないといけないんですね〜。ここに「F」と書いておけばいいんですね!これでOKです。

 

■メニューに関連付けた実行関数が呼び出せない…うぅ、やっぱりマニュアル(以下略)
さて、というわけで、WSCpulldownMenuにプロシージャを追加(トリガは「NONE」とするようです)し、このWSCpulldownMenuのプロパティである「メニュー項目」に、「項目の表示文字列:実行イベントプロシージャ名:ショートカットキー,...」といった感じで書いて…と。ん?これで呼び出しができるのハズなのですが、書いてみたら、何も動かない…うぅ、どうして???と思ったら、「プロシージャ名」を書かないといけないんですね。「実行関数名」を書いてしまいました。みなさん、あそこに書くのは「実行関数名」ではなく、「プロシージャ名」です。マニュアルをよく読みなさい!って感じですね〜。でも、VC++とかやってる人は、結構、勘違いするんじゃないかな〜って思います。

2004/03/16

やっぱこれが欲しい!WideStudioでスライドバーを動的生成

WideStudioでスライドバー、しかも動的生成
20040316P00.JPG - 10,190BYTES…と書くと、すごそうだけど、将来きっとすごくなる機能の基礎技術研究として「スライドバーの動的生成」とイベントプロシージャの割り当てににチャレンジしてみました。う〜ん、よくわからないので、本を読むのとプログラマだったころの経験から、ごちゃごちゃと1時間半。ようやくできました。

画像で見ると、「トグルスイッチ」、「ラベル」、「スライドバー」という3つの部品で構成されている塊が、4つ表示されているのがわかると思います。これらは、アプリケーションビルダで作ったのではなく、プログラムにて動的に生成しており、スライドバーを動かすとその値がラベルに反映されるようになっています。さてさて、どうやって作ったかを解説してみたいと思います。いつもながら思うのですが、わかっている人には「しょうもないコード」です。でも、これもまたワタクシメの歴史なので、笑って許してください。

■まずはインクルードファイルとその他準備
とりあえず、アプリケーションビルダで何かウィンドウを作ります。このウィンドウの上に部品を並べるプログラムを書くことにします。そして、INITIALIZEトリガの実行関数を作ります。名前はなんでも好きなものをつけてください。今回は、この実行関数の中で生成することにします。というわけで生成されたコードの、#includeが並んでいる下に、今回、生成する部品である、トグルスイッチ(WSCvtoggle.h)、ラベル(WSCvlabel.h)、スライダ(WSCvslider.h)をインクルードするようにします。

  #include <WSCvtoggle.h>
  #include <WSCvlabel.h>
  #include <WSCvslider.h>

次に、トグルスイッチなどを生成した時に、実体を管理するためのポインタ配列を作ります。管理する対象は、「トグル」、「ラベル」、「スライダ」ですので、それぞれのクラスのポインタ配列とします。また、「何個管理する」といった情報は、あちこちで使いますので、#defineしておきます。そんなわけで、上記の#includeにつづいて、以下のようなソースを書きます。

  #define NUM_MAX 4
  WSCvtoggle* STM_aptglServoPls[NUM_MAX];
  WSCvlabel* STM_aplblServoDeg[NUM_MAX];
  WSCvslider* STM_apsldServoDeg[NUM_MAX];

まあ、こんな風に、いきなりグローバルにするとかっていうのは、なんとなく気が引けますが、他のサンプルとかを見ている限りではよさそう(WideStudioの中では悪くない?)な気がしますので、よしとします。相変わらず、お作法がつかめていませんが、こんな感じでしょう。余談ですが、イメージ的には、「C++クラスライブラリをベースとして、それをCでお気軽に呼び出して使う世界」な気がします。とても現実的で、とっかかりがいい感じですが、本当のところはどうなんでしょう?

■INITIALIZEの実行関数に生成機能を組み込む!(とりあえず)
今回は、INITIALIZEの実行関数に生成機能を組み込むことにしました。実際にアプリを組み出すと、違う場所の方がいいこともあるのですが、「基礎技術研究」ということで、一番お手軽な場所にしました。INITIALIZEの実行関数名は、initMain()にしてみました。中身は、NUM_MAX回ループして各部品を生成するだけです。というわけで、最初に書くコードはこんな感じです。ループして、カウンタに応じた名前(SERVO-00〜03)を作ります。

  int  nCnt;
  char szServoName[64];

  for( nCnt = 0; nCnt < NUM_MAX; nCnt++ ){
    sprintf( szServoName, "SERVO-%02d", nCnt );
    // ここからいろいろ書き足します。
  }

■部品の動的生成
それでは、まずはトグルスイッチの動的生成からいってみようと思います。

  STM_aptglServoPls[nCnt] = new WSCvtoggle( object, szServoName );
  STM_aptglServoPls[nCnt]->initialize();

このあたりは、サンプルソースを見て、「う〜ん、こうかなぁ」とやってみました。本を読むと「生成したらとにかくinitialize()」と、非常に楽しい文章で説明されています。さらに、WSCvtoggleのnewする時のパラメータ、まだよくわかっていません。どっかに少しだけ書いてあったような気がするのですが、1つめは親となるオブジェクト、2つめは「名称」だと思います。だとすると、1つずつ、名前を変えないといけないような気もするのですが、動的に生成する場合は、問題にならないようです(アプリケーションビルダでは、ソースを自動生成する都合上のものかな)。 そして、WSNuserValueを設定します。一見、何につかえるかわからないプロパティですが、ここに数値を入れておくと、後で取り出して使うことができます。イベントプロシージャの実行関数を1つで書いてしまう場合、この数値を使って識別をさせることができますので、ちゃんと数値を設定することにします。

  STM_aptglServoPls[nCnt]->setProperty( WSNuserValue, nCnt );

後は表示名です。このプロパティに設定した文字列が、トグルスイッチのところに表示されます。

  STM_aptglServoPls[nCnt]->setProperty( WSNlabelString, szServoName );

最後に、表示サイズや表示位置を設定します。ループにあわせて、Y座標がずれるようにしてあります。このあたりは趣味の問題なので、好きなように設定すればよいと思います。どれがどの値かは、アプリケーションビルダで試しに1つ部品を作ってみて、プロパティでいじくって確認してみてください。

  STM_aptglServoPls[nCnt]->setProperty( WSNx, 0);
  STM_aptglServoPls[nCnt]->setProperty( WSNy, nCnt*40 );
  STM_aptglServoPls[nCnt]->setProperty( WSNwidth, 100 );
  STM_aptglServoPls[nCnt]->setProperty( WSNheight, 18);
  STM_aptglServoPls[nCnt]->setProperty( WSNindicatorSize, 16 );
  STM_aptglServoPls[nCnt]->setProperty( WSNshadowThickness, 0 );

おっと。最後の最後に、「表示!」します。

  STM_aptglServoPls[nCnt]->setVisible(True);

同様に、ラベル、スライダも設定します。設定しているのは表示系ばかりですので、それぞれのプロパティについては、アプリケーションビルダで1つ作ってみて、確認してください。というわけで、以下のようになりました。

  STM_aplblServoDeg[nCnt] = new WSCvlabel( object, szServoName );
  STM_aplblServoDeg[nCnt]->initialize();
  STM_aplblServoDeg[nCnt]->setProperty( WSNuserValue, nCnt );
  STM_aplblServoDeg[nCnt]->setProperty( WSNlabelString, "0" );
  STM_aplblServoDeg[nCnt]->setProperty( WSNx, 100 );
  STM_aplblServoDeg[nCnt]->setProperty( WSNy, nCnt*40 );
  STM_aplblServoDeg[nCnt]->setProperty( WSNwidth, 50 );
  STM_aplblServoDeg[nCnt]->setProperty( WSNheight, 18);
  STM_aplblServoDeg[nCnt]->setProperty( WSNshadowThickness, 0);
  STM_aplblServoDeg[nCnt]->setVisible(True);

  STM_apsldServoDeg[nCnt] = new WSCvslider( object, szServoName );
  STM_apsldServoDeg[nCnt]->initialize();
  STM_apsldServoDeg[nCnt]->setProperty( WSNuserValue, nCnt );
  STM_apsldServoDeg[nCnt]->setProperty( WSNx, 0 );
  STM_apsldServoDeg[nCnt]->setProperty( WSNy, nCnt*40+18 );
  STM_apsldServoDeg[nCnt]->setProperty( WSNwidth, 150 );
  STM_apsldServoDeg[nCnt]->setProperty( WSNheight, 18);
  STM_apsldServoDeg[nCnt]->setProperty( WSNsliderSize, 16 );
  STM_apsldServoDeg[nCnt]->setProperty( WSNmaximum, 127 );
  STM_apsldServoDeg[nCnt]->setProperty( WSNminimum, -127);
  STM_apsldServoDeg[nCnt]->setProperty( WSNdragInterval, 1 );
  STM_apsldServoDeg[nCnt]->setProperty( WSNvalue, 0 );
  STM_apsldServoDeg[nCnt]->setVisible(True);

■イベントプロシージャの割り当て
さて、ここからが問題です(いや、今までの部分も難しかったんですが…)。スライダを動かしたら、ラベルに表示されている値を更新するという機能を付け加えます。いわゆるアレです。スライダをつまんで動かすと、スライダ位置を数値表示するやつです。普通にアプリケーションビルダから作る場合は、スライダからの「数値変化(WSEV_VALUE_CH)」のトリガを使って、ラベルの値を更新すればよいことになります。これと同じ事をすればよいのですが… 通常、実行関数はアプリケーションビルダから生成します。プロシージャイベントを作って、イベント決めて、云々すると、雛型のソースコードが生成されます。なにがわからなかったって、これを「手で勝手に作っていいものか?」ということに悩みました。 本を読んでいると、「作ってください」とは書いてあるのですが、どうやって作れとは書いてないんです。かといって、アプリケーションビルダからこういうものを作る機能も無さそうですし。というわけで、勇気を振り絞って、手で作りました。先に作りました、initMainのソースコードにちょこちょこっと追加しました。

 まずは、実行関数の方です。割と一般的で、普通のスライダサンプルプログラムもこんな感じだと思います。

void STM_opeSlideServoDeg( WSCbase* object )
{
  char  szDeg[64];
  int   nIdx, nDeg;

  nDeg = object->getProperty( WSNvalue );
  sprintf( szDeg, "%d", nDeg );
  nIdx = object->getProperty(WSNuserValue);
  STM_aplblServoDeg[nIdx]->setProperty( WSNlabelString, szDeg );
}

中身は簡単なものですが、先に説明しましたWSNuserValueが活躍しているのがわかると思います。この実行関数は、すべてのスライダから呼び出されます。そのため、どの人から呼び出されたかを認識しないといけないです。この行です。

  nDeg = object->getProperty( WSNvalue );

この実行関数が呼び出されるとき、objectという変数が渡されますが、これが、この関数を呼び出したオブジェクト(このケースの場合、具体的にはスライダのオブジェクトの1つ)のポインタになります。先の初期化で、WSNvalueに、固有の識別番号を入れていますので、これを取り出すことによってどのスライダから呼び出されたかがわかります。

よって、どのラベルを更新するかわかることになりますね! さて、この実行関数を、WSEV_VALUE_CHイベントが発生した時に呼び出されるように、生成したスライダオブジェクトに割り当てます。それには、以下のように、プロシージャを名称とトリガから生成、生成したプロシージャに実行関数を割り当て、そしてスライダにこれを追加するという形になります。

  WSCprocedure* ep = new WSCprocedure( "SERVO_DEG", WSEV_VALUE_CH );
  ep->setFunction( STM_opeSlideServoDeg, "STM_opeSlideServoDeg" );
  STM_apsldServoDeg[nCnt]->addProcedure( ep );

これをforループの、スライダを生成した後に実行するようにすればOKです。これで「スライダを動かすとラベルの値が変わる」という部品を、動的に生成することができるようになりました。それぞれの部品の表示位置や制御対象とするサーボの情報などを、定義ファイルとかで与えて、SIPHA-COREと通信できるようにすれば…うふっ。 

 

2004/03/21

WideStudio、どうやって画像埋め込む?

相変わらず異国の地のSISOです。ああ、思えば、ROBO-ONEが終わって約2ヶ月。ほとんどこんな生活をしております。しかも、先日、熱がでて寝込んでしまいました。こっちのメンバーにヘルプしてもらって初めて異国の病院に行きました。行ってみたら、全然日本と変わりませんでした。もっと早く行けばよかった。診断結果はただの風邪でした。今は、微妙にフラフラする気もしますが、久しぶりにたくさん寝ているので、そのせいかもしれません。というわけで、時間を見つけてWideStudioです。

なぜ、今、WideStudioか?それはですね、「仕事のおかげでロボットに触れない」→「時間が無い」→「いじける」→「引きこもる」…ではつまらないので、時間が無いのならば、時間をかけずに完成できるよう、開発環境を整えておく!という、非常に前向きなような、そうでないような、しょうがないからそうしているような作戦なのです。ほら、かっちょよくて使いやすいエディタとかあれば、動作データもさくさくできるかもしれないでしょ〜。

う〜む、画像が表示されない…
今日、WideStudioのアプリ作成練習しているフォルダ名を変更したんです。そしたらスプラッシュウィンドウに表示していたビットマップファイルが???表示されなくなってしまいました。ちょっと試してみたら、実行ファイルの中に画像データとかが入る訳ではないようで、プロパティで指定しているファイルを読み込むようになっているようです。

20040321P00.JPG - 6,742BYTESというわけで、とりあえずフルパスで記述していた画像ファイルのパスを相対(というかディレクトリ情報を抜いた)パスに変えました。左の画像は、WideStudioのアプリケーションビルダでプロパティを表示したところです。これで、とりあえず、実行ファイルと画像ファイルを同じフォルダに置いておけばいつも表示されるようになりました。

これ、実行ファイルに入れてしまう方法って無いんでしょうか?また調べてみようとは思いますが、これはこれで、ビルド無しで画像が入れ替えれていいような気がします。でも入れたいな〜。どなたかご存知じゃないでしょうか???

く、クラスってどうやって追加するの?
こ、これがわかりません。普通にCの関数として、コードを足していくのはわかるのですが、クラス(ただのクラス)を追加しようとしたら、ソースコード中の"class"宣言をしているところで、コンパイルが引っかかってしまいます(invalid use of undefined type `struct <anonymous>って言われるんです)。WideStudioって、C++ライブラリ上でC関数を構築していくようなイメージがあるから、classを入れようとすると、何かおまじないがいるのかなぁ…。

ま、まさか、これがおまじないか…

SACdefFileというクラスを定義しようとしていたんですが、これのソースファイルをSACdefFile.h、SACdefFile.cppとしていました。そしたら上記のエラーに引っかかっていたんですが、これを、SSACdefFile.hとSSACdefFile.cppにしたら通ってしまいました。ソースファイル名の頭に「S」を追加して、名前を変えてみたわけです。不思議です。でも、SACdefFileSrc.h、SACdefFileSrc.cppとやってもダメなんですよね〜。お作法かなぁ。

ちなみに、自分で独自に作成したソースコードをコンパイルの対象に入れるには、「プロジェクト」−「プロジェクトの設定」にて「コンパイル」タブを開いて、「追加オブジェクト」にオブジェクトファイル名を追加すればいいです。先の、SSACdefFileの例で行くと、SSACdefFile.oと書いてやればOKです(「SSACdefFile.cpp」では無いのでご注意)。

ファイルの内容をリスト表示
20040321P01.JPG - 23,098BYTESというわけで、せこせこと作っていたのは、テキストファイルを読み込んでリスト表示するだけのプログラム。いやいや、これが将来は、定義ファイルを読み込むプログラムに発展していくわけでして(^^;。

んでまあ、とりあえず、ファイルを読み込んでWSClistDataクラスにWSCstringをがばがばとnewしてくっつけて読み込んでやって、それを試しにWSClistで表示してみたら、左上のようになってしまいました。なんか変でしょ?表示がかけています。これは悩みました。なぜだろう?なぜだろう?

実は、ファイルから読み込んだ時に、「改行コード」が入ったままになっていて、それをWSClistにそのままaddItem()していました。もし、同じような表示になった方がいましたら、「改行コードを削除」してやればOKですよ。んで、左下になりました。

ちなみに、改行コードを削除するには、WSCstringクラスに便利な関数がありまして、delLineFeed()で一発で外れます。なかなか便利です。

setPropertyはすごい!
もう1つおまけなんですが、前回、紹介したスライドバーの動的生成のところで、スライドバー実行関数をお見せしましたが、あの中で、ラベルに数値表示するために、数値を文字列変換しているところがありましたが、その後の調べで、あれは無くてもいいことがわかりました。直接、setProperty()で数値を指定すると、ちゃんと文字列として設定してくれます。C++の、なんとかっていう機能(すいません、忘れました)ですね!というわけで、以下のようになります。

void STM_opeSlideServoDeg( WSCbase* object )
{
  int   nIdx, nDeg;

  nDeg = object->getProperty( WSNvalue );
  nIdx = object->getProperty(WSNuserValue);
  STM_aplblServoDeg[nIdx]->setProperty( WSNlabelString, nDeg );
}

 

2004/03/24

EXCEL+VBも結構イケてて、目からウロコ

スライダーネタで、おかださん(OKADA Official Site)から、メールを頂きました。おかださんのモーションデータ作成ツールって、な、なんとExcel+VBなのね…。現物見て、びっくりしました。詳細は、おかださんのHPを参照してください。見ると、そうかExcelさえあれば、フリーツールと組み合わせて、いい感じのものができてしまうではないか〜というのがわかってしまいました。

実は、以前、ホームページの方は拝見させて頂いていたのですが、「VBで」というところだけ覚えていまして、Excelの方は忘れていました。「ロボット製作のページ」−「R2N-series製作日記」の下のほうにあります。ExcelからVBでシリアル通信ライブラリを呼び出して、User Formで作った操作画面です。よく考えると、これも結構、アリだなぁって思ってしまいました。ほら、Excelって、表計算ソフト。動作データって、ほとんど表だったり、計算いっぱいだったりするわけですし、初期データなどもセルに書いておいて、コアにシリアルでアクセス。実は、なかなか良いんではないかと、思うわけです。

ここから第2のポイントで、今日のお題なんですが、各スライドバーとその受け関数を、割と単調にコーディングされていまして、これについて、「簡単ではまった」(邪道と思いつつ始めたら、意外に簡単であったという意味だと思います)とのコメントを頂きました。そこで、SISOは考えました。

わらひは、いきなり複雑なことをやろうとしている気がする…

といわけで、WideSudioでも、同じようなことができるというのをおかださんにアピールしつつ、こっそりExcel路線もおもしろいと思いつつ、単純なスライドバーの生成をやります(最初からそうしなさいって感じですよね〜)。ひょっとしたら、正式採用かな?ま、今は、小手試し期間です(^^;

単純にサーボ制御用スライドバーを作るには?
20040324P00.JPGとにかく、左のようなウィンドウを作りましょう。ちょと見にくいですが、左上に「トグルスイッチ」、右に「ボタン」、下に「スライダー」が貼ってあります。それが2組貼ってあります。「オブジェクトボックス」からぽいぽいすればできます。大きさ、デザインは好みでOKです。名称は、それぞれ以下のようにしました。

トグル:tglServoDegCtl00、tglServoDegCtl01
ボタン:btnServoDegCtl00、btnServoDegCtl01
スライダ:sldServoDegCtl00、sldServoDegCtl01

前回、ボタンではなく、ラベルを使用していたのですが、今は、気分でボタンにしています。「押すと原点復帰」とかしたらおもしろいかな?と思いまして。また、ボタンだと、ラベルと違って表示にグラデーションが使えるので、デザイン的な理由もあったりします(笑)。

後は、スライダにVALUE-CHのイベントプロシージャをつけます。1つめは、SDCmovSlider00、2つめはSDCmovSlider01とします。そうすると、ソースコードが生成されます。SDCmovSlider00を例に…

まずは#includeの次に、

#include <WSCvbtn.h>
extern WSCvbtn* btnServoDegCtl00;

を追加します。次に、関数の中身として、次の1行を追加します。

btnServoDegCtl00->setProperty( WSNlabelString, (int)object->getProperty( WSNvalue ));

20040324P01.JPGSDCmovSlider01の方も同様にしてください(ただし00は01にしてくださいね)。これで、スライダを動かすと、ボタン上の数値がぐりぐり変わるソフトができます。サーボの個数分だけ、これを繰り返して作ればOKです。一見大変そうですが、やってみると、それほどでもないです。う〜む。意外でした。あれこれ考えるよりは楽かも。しかも、WideStudioは、プロパティで「ユーザー設定値」というのが設定できるので、これを駆使すればさらに楽ができるかも…。んで、できあがりはこんな感じです。

ところで、以前、スプラッシュウィンドウの時に紹介した、ウィンドウにグラフィックファイルを貼り付ける機能の話、覚えていますか?あれとこれを組み合わせると、お楽しみの…これができます。う〜ん、なかなかきれいにできました。

20040324P02.JPG

 

2004/03/30

WideStdio、InspectorWindowでもカッコよく(裏技?)

本日は、最近発見した、ちょっとしたWideStudioの小技を紹介します。

へ、編集しちゃってもいいのかな?
20040330P00.JPG - 31,115BYTES

WideStudioでごちょごちょと、新SIPHA TERM画面を作っていますが、部品を作っているうちに、Inspector(アプリケーションビルダの左側に表示されてるオブジェクトのツリーウィンドウ)に並んでいるオブジェクトの順番が気に入らなくなることがありませんか?

どうも、作っている順番に表示されていくようでして、「あ、あのボタン忘れた」とか言って追加すると、下のほうに来てしまいます。実は、プロポをエミュレーションする画面を作っていたんですが、画面上のボタンの順番に並んでいないと、どうもやりにくい!というわけで、ちょちょっとWideStudioの定義ファイルをのぞいてみました。

ふむふむ。「ウィンドウ名.win」(たぶん、メインウィンドウと呼ばれる単位だと思います)というファイルにオブジェクト情報があるようですね。テキストファイルなので、エディタで「えい」と開けば内容を確認することができます。よくみると、この中に定義してある順番で表示されているようです。「#OBJ」で始まっている行が1オブジェクトの定義順のようです。

「むむむ、ひょっとしてこれの順番を入れ替えれば…」、たぶん正規技じゃないと思いますので、ファイルをコピってバックアップしておいてください。また、WideStudioは終了させておいてください。

WideStudioの動きを良く見ていると、このファイルをアプリケーションビルダでまず作り、ビルド時に、「ウィンドウ名.cpp」と「ウィンドウ名.h」いうファイルを自動生成し、この中にオブジェクト生成のソースコードが生成されるようですね。おまけ情報としては、これらのファイルをいくら編集しても、ビルドのたびに戻ってしまうのでダメ、ということになります。そっとしておいてあげましょう。 というわけで、「ウィンドウ名.win」の中身をエディタでちょいちょいと入れ替えてWideStudioを再起動…お、変わりました。これで、気にせずオブジェクトをぐいぐい追加できます(^^)。別に結果には何も影響を与えないのですが、気分気分!これで気分上々です。 というわけで、小技でした。

 WideStudio、オブジェクトがごちゃごちゃする時はFormに貼り付けちゃえ
20040330P01.JPG - 12,692BYTES部品化?ぽくもう1つ整理技です。いいのか悪いのかはよくわかんないんですが…1つのウィンドウにいろいろオブジェクトを貼り付けていくと、だんだん、Inspectorに表示される量も増えてきますし、なんだかわかんなくなってくる時があります。そんな時は、あらかじめWSCformを貼り付けておき、その上にボタンなどのオブジェクトを配置するといいです。

左の画面は、「プロポエミュレータ」を作ろうと思って作った画面なんですが、左右の9個組みボタンは、1つのFormオブジェクト上に配置してあります。こうすると、Inspectorには9個ずつ階層化して表示されるようになります。これだけでも結構気分がいいのですが、さらに!1つ作って、コピーすれば、もう1組の9個ボタンウィンドウを作れることが発覚。ぶらぼ〜!

そ、そして、まだ利点があります。全体の表示座標を変える時に「おお、Formに貼り付けておいてよかった〜」というのをさらに実感しました。う〜ん、楽チン。つ〜のも、それぞれのボタンの大きさはあまり変えないのですが、全体のレイアウトを見直すときに、表示座標を変えたいときがあります。実際にあったのは、大元のウィンドウサイズを変えたときです。「うぅ、でかかった」なんて時ウィンドウを小さくすると、全体の部品配置もバランスよく見直したりするわけですが、こんな時、Form上に配置してあると、Formの座標をずらすだけで、ボタンが9個組で移動してくれます。というのも、Form上に配置する場合、それぞれのボタン表示座標は、Formの左上が(0,0)の原点になります(各ボタンがFormの子供になるわけですね)。そんなわけで、Formさえ移動すればいいのです。 というわけで、いいか悪いか良くわからないですが、オススメ!のやり方です。

 

2004/06/01

WideStudioで「タブ画面」

WideStudioのWSCindexForm
20040601P00.JPG

「う〜ん、こまこましたウィンドウが増えてやだなぁ〜。」設定系のウィンドウを作っていると、こんなぼやきが出る時があります。そこで、てぃろりろりん♪「いんでっくすふぉぉむぅぅ」

「タブ画面」ってご存知です?実は、正式になんと呼ぶのかは知らないのですが、Windowsとかの設定画面によくある、上の方のインデックスみたいなところをクリックすると、同じウィンドウ上でいくつかの設定画面を切り替えられるアレです。これをWideStudioでやってみたのですが、すごく簡単!

オブジェクトボックスから貼り付けたいウィンドウへ、「WSCindexForm」をドラッグ&ドロップします。
プロパティで、「メニュー項目」を編集します。サンプルとして、「INDEX01,INDEX02」と入力してみました。ここを、「,」区切りで入力していくと、タブ(WideStudioの場合はインデックスと呼ぶのかな?)が増えていきます。そして、インデックスフォーム上に部品を追加していきます。これは、タブを選択しておいてから、普通に「オブジェクトボックス」からドラッグ&ドロップをするだけです。
以上です。

20040601P01.JPG20040601P02.JPG

後は、ビルドすれば「あこがれのタブウィンドウ!」ができますよ。すごい簡単でブラボーです。さて、注意点です。「プロパティ」の「ユーザー設定値」(WSNuserValue)を見てください。よくみると、「INDEX01」に貼り付けた部品の設定値は「1」、「INDEX02」に貼り付けた部品の設定値は「2」になっています。これは、部品を貼り付けるときに、ビルダが自動的に割り振ったもので、どうやら、WSCindexFormは、この設定値によってどのインデックスにどの部品を割り付けるかを判定しているようです。

というわけで、WSCindexFormを使うと「ユーザー設定値」によってなんかする、というプログラムが書けなくなりますので、要注意です。できれば別にして欲しかったトコロではありますが、それにしても、う〜む、WideStudio、よくできてるな〜。

 

2004/10/13

WideStudioでのデバッグ

久しぶりの更新です。例によって出張していまして…。日本は涼しいです。ちょっと風邪気味。 さて、今日は超久しぶりのWideStudioネタです。

最近、SIPHA TERMの改良を始めました。久しぶりに触るので半分忘れかけていますが、開発時、急いで作っていたため、いろいろアップできなかった情報があることを思い出しました。そんなわけで、ぼちぼちと思い出しがてら、小技みたいなものをアップしていこうと思います。

WideStudioでTRACE表示
みなさん、WideStudioでデバッグする時、どのようにされていますか?WideStudioにはgdbというデバッガがあるのですが、使い方がよくわからなくて、もっぱらトレース表示を使用しています。

WideStudioには、WSGFtrace( WSCstring )という、グローバル宣言されている関数がありまして、これを呼び出すと、TRACEウィンドウに文字列を表示してくれます。

TRACEウィンドウの出し方ですが、プログラム実行時に「ビルド」−「トレース実行」とすることによりTRACEというウィンドウが開きます。自分でWSGFtrace()を埋め込まなくても、ウィンドウにはアプリケーションビルダで設定したイベントがずらずらと表示されるようになっています。そういうわけで、最初からTRACE表示をさせておくと見づらいので、ここぞ!という時に、「start」を押します。そうすると、イベントとともに、WSGFtrace()で設定した文字列が表示されます。

では、どうやって実装するかやってみます。

サンプルプログラムの作成とトレースウィンドウの表示
まずは、今回の実験台となるプログラムを作ります。適当にウィンドウが1つあるだけのプログラムを作ってみてください。プロジェクトを作って、新規ウィンドウを追加しただけのものです。

これに、マウス押下イベント処理を追加してみます。「プロシージャ」で、「プロシージャの追加」をします。

20041013P00.JPG - 15,430BYTES

マウス押下イベントは、「MOUSE-PRESS」という起動トリガになります。名前は適当ですが、いつもこんな感じでつけています。MOUSE-PRESSだから「XMP」、もしACTIVATEだったら「XAC」なんてのを後ろにつけています。ちなみに「X」は「実行(Execution)」ということでつけています。

これで「作成」を押したら、そのまま「ビルドオール」してください。で、ここからがミソ。プログラムを実行するときに、「トレース実行」を選択します。

20041013P01.JPG - 22,810BYTES

これです。これで実行すると、トレースウィンドウ付きでプログラムが実行されます。そして、実行すると、次のような状態になります。ちょっと見づらいですが、左下にあるのが今回作ったウィンドウで、後ろにでっかくでているのがトレースウィンドウです。「start」と「cancel」ボタン(なぜに小文字?)が右下にあるのがわかると思います。

20041013P02.JPG - 8,456BYTES

それでは、さっそく、実感してみましょ。「start」を押してマウスで、プログラムで作ったウィンドウの方をクリックしてみると…

20041013P03.JPG - 10,653BYTES

お、何か表示されましたね!ちょっと上の画面では見づらいので、拡大したものを下に載せます。

20041013P04.JPG - 13,605BYTES

はい、こんな感じで表示されています。なになに?WTSwin(今回作ったウィンドウ)が<マウス押下>イベントプロシージャ−を実行して、スタートしてエンドですか、ふむふむ。

このように、TRACEウィンドウでは、イベントプロシージャの実行状態などが表示されます。で、ここが本題ですが、このウィンドウにはプログラムからも表示をさせることができます。それが、先に書きました、WSGFtrace()です。

WSGFtrace()でTRACEウィンドウに表示
というわけで、プログラムからこのTRACEウィンドウに文字列を表示してみます。先ほど追加したプロシージャに、WSGFtrace()を追加してみます。プログラムは、こんな感じになります。

//----------------------------------------------------------
//Function for the event procedure
//----------------------------------------------------------
void WTSwin_XMP(WSCbase* object){
    //  WSGFtrace()による、直接表示
    WSGFtrace( "トレース表示\n" );
}

WSGFtrace()の引数は、WSCstringで宣言されていますが、このように文字列を渡しても大丈夫です。のあたりは、C++のOperator演算子がどうたらこうたらのような話だったと思いますので省略します(単に説明できるほど詳しくないだけ…)。では、さっそく「ビルドオール」して、「トレース実行」してみてください。「start」を押すのも忘れないで下さいね。

20041013P05.JPG - 12,936BYTES

3行目に、無事、「トレース表示」と表示されています。こんな感じでTRACEウィンドウに文字列を表示します。例えば、内部処理でのちょっとした結果の表示などに使えます。また、WSGFtrace()は、TRACEウィンドウが無ければ、何も動作しないようになっていますので、不要になったからといって削除する必要は無く、そのまま埋め込んでおいても大丈夫です。

もっと便利にTRACE表示
でも、ちょっと不便だと思いませんか?やっぱ、「printfデバッグ」という言葉があるように(いい言葉かどうかはちょっと…)、printfのように使えるものが欲しいですね!そんなあなたにこんな関数はどうでしょ?(最初、TRACE()にしようと思ったんですが、Visual C++でも、同じ名前のものがありますし、WideStudioの中でも近そうなものがあったので、あえてやめました)

//----------------------------------------------------------
//  TRACEウィンドウへの書式付表示
//      引数    const char *        書式(表示文字列)
//              [, argument]...     表示引数
//              (printfと同様)
//----------------------------------------------------------
void tracePrintf( char* szForm, ... )
{
    char szData[128];
    va_list vaParam;

    va_start( vaParam, szForm );
    vsprintf( szData, szForm, vaParam  );
    WSGFtrace( szData );

    va_end( vaParam );
}

とりあえずテストということで、先ほどのイベントプロシージャ実行関数のソースファイルに書き込んじゃってください。また、va_listとかがわからない方は、いわゆるCの標準関数ですので、がんばって調べてみてください。

//----------------------------------------------------------
//Function for the event procedure
//----------------------------------------------------------
void WTSwin_XMP(WSCbase* object){
    //  WSGFtrace()による、直接表示
    WSGFtrace( "トレース表示\n" );

    //  tracePrintf()による書式付表示
    tracePrintf( "トレース表示 %d %d %d %s\n", 1, 2, 3, "TEST" );
}

じゃ、「ビルドオール」して「トレース実行」してみましょ。

20041013P06.JPG - 14,498BYTES

おお、ちゃんと出ました。これでprintf()と同じイメージで使えます。便利ですので、お試しくださいな。また、もし、もっといいデバッグ方法を知っていらっしゃる方がいましたら、ぜひ教えてください。

 

2005/01/09

WideStudioでStatic Linkのアプリケーション作成

WideStudio v3.80-7
現在、SIPHA TERMソースコードの復旧中なわけですが、ついでということで、WideStudioも最新版(V3.80-7)にバージョンアップしました。v3.70と比較すると、ライブラリが増えているような気がします。何気に気になったのが「スタティックリンク(DLL無し)」というオプション。これは、「プロジェクト設定」の「リンク」タブの中にあるのですが、ひょっとして、実行ファイルだけで動かせるようになるリンク設定(ダイナミックリンクを使用しない)かな〜と思って試してみたら、そのとおりでした。

ちょっと前に、「Wide Studioで作ったアプリケーションって、どのDLLが必要なんだろう?」と思って少し調べていたんですが、これを使えば、WideStudioがインストールされていないWindowsにアプリを入れても動作できます。うちのLibretto L1は、Dual Bootにしてあって、何にも追加DLLが入ってない方のWindowsがあるので、そこで試してみたところ、バッチリ動作しました。

き、気づかなかった…
ん?そういえば、前のWideStudio (v3.70)のリンクタブも。同じレイアウトだったような気がします。でも、あの時はこのオプションに気づきませんでした。なぜでしょう???というわけで、もう一度、バージョンダウンをして確認してみました。

20050109P00.JPG - 11,724BYTES

これは、v3.80のリンクタブですが、リンク方式□「スタティックリンク(DLL無し)」と書いてありますこれにチェックを入れると、スタティックリンクのアプリケーションを作成することができます。じゃあ、V3.70の方はどうなっていたかといいますと

20050109P01.JPG - 12,214BYTES

なんと、こういう表示になっています。この状態が「ダイナミックリンク設定」です。今思えば、試しに押してみてもよかったチェックボックスですが、ちと難しかったです…。でもチェックボックスって、「チェックするとその状態になる説明文が書いてある」のが多いと思うので、気が付きませんでした。ちなみに、ここの動き、なかなか凝ってまして、チェックすると…

20050109P02.JPG - 12,253BYTES

テキストが「スタティックリンク(DLL無し)」に変わります。

ダイナミックリンクライブラリについて
フリーソフトとかで、「VBのランタイムを入れないとダメだよ〜」とか聞いたことありませんか?WideStudioに限らず、アプリケーションが起動するときに共通のライブラリを動的に読み込んで実行するタイプのものがあります。
この仕組みのことをダイナミックリンク(ライブラリ)なんていうそうなんですが、これを使うと、ライブラリを他のアプリケーションと共有できるのでディスクの節約をすることができます。また、実行プログラム本体も小さくなり、ダウンロードも早くなります。しかし、もし、そのライブラリがパソコンに入ってないと、そのプログラムは動作できません。Visual C++なんかですと、MFCライブラリなどがあります。

対して、スタティックリンクでアプリケーションを作成すると、アプリケーションのサイズは大きくなりますが、パソコン毎のライブラリインストール状態を気にしなくてよくなります。 気になる実行ファイルのサイズですが、SIPHA TERMで試してみたところ、380Byteのプログラムが3.6MByteになりました。実行ファイルのサイズが大きくなったとはいえ、実際に、小さいサイズのアプリを起動しても、恐らく同じだけWideStudioのDLL(ダイナミックリンクライブラリ)がロードされるわけなのでパフォーマンスに差は無いと思われます。ちなみにZIPで圧縮してみたら1.2MByteぐらいにはなりました。WideStudioでプログラムを作って人に配布する場合は、スタティックリンクにしておいた方が手堅そうですね。

 

2005/01/11

WideStudioで、読み込んだ画像ファイルに合わせてウィンドウサイズ調整

リブレットL1は、画面サイズが1280x600
知ってはいたけど、Libretto L1の画面サイズは1280x600です。そんなわけで、1024x768に最適化されたSIPHA TERMは全部表示することができません。 Librettoの方で表示モードを切り替えてもいいのですが、スクロールするようになるだけなので操作感はイマイチ。というわけで、一番問題になる、 サーボのスライダ操作画面を、読み込んだ画像ファイルサイズに合わせてリサイズする機能を組み込む事にしました。 もう少し良いやり方としては、イメージクラスがあるので、そこに読み込んでスクロールウィンドウもつけて云々という のがあるのですが、今回は、画像サイズにあわせるほうが使いやすいかな〜と思っちゃったので、ウィンドウそのものを あわせこむ方でやってみました。

# 何気に勢いでやってしまいましたが、後で、どっちでもよかったかな?と思ったことはヒミツ。

背景画にあわせてウィンドウサイズを変更するには?

結構簡単に…できたにはできたのですが、実は「あまり自信が無い」です。もし、間違っていたらよろしくお願いいたします。

さて、ざくっと要点解説ですが、TSC16もそうなんですが、画像データ、基本的にはウィンドウの背景画として読み込ませています。ウィンドウのプロパティで、「背景画」というのがありますが、これをプログラムで操作しています。TSC16の場合は直接ソースコードで指定していますが、この項目にsetProperty()すれば画像ファイルを動的に読み込むことができます(簡単〜♪)。

さて、WideStudio、ヘルプファイルを読むと、どうやら画像扱うためには「WSDimage」というクラスを通じて扱うようになっているようです。また、その画像元ネタは、「WSGIappImageSet」というプログラム内でグローバルに宣言されている(WideStudioでアプリケーションを作成すると、そのアプリケーションに自動的に引っ付いていると理解しておいてください)画像管理オブジェクト?から引っ張ってくるようです。

そんなわけで、まずはこんなコードで初期化されます。

WSDimage* pimgBasePic;
                                        // test.jpg のイメージインスタンスを取得。
pimgBasePic = WSGIappImageSet()->getImage( "test.jpg" );

これで、「イメージインスタンス」とやらが取得できますので、ここからサイズ情報を取り出し、自ウィンドウのウィンドウサイズを変更します。まずはサイズ取得です。サイズ取得用のメソッドが用意されていますので、以下のようなコードでさらっと読み出すことができます。

unsigned short	usWidth, usHeight;

usWidth = (unsigned short)pimgBasePic->getImageWidth();   // 画像横幅の取得
usHeight = (unsigned short)pimgBasePic->getImageHeight(); // 画像高さの取得

後は、この値を使って、自ウィンドウのプロパティを操作するだけです。

object->setProperty( WSNwidth, usWidth );                 // ウィンドウサイズの設定
object->setProperty( WSNheight, usHeight );               // ウィンドウサイズの設定

object->setProperty( WSNbackPixmap, "test.jpg" );         // 背景画の設定

「object」というのは、自分自身のクラスポインタです…と書くとややこしいのですが、簡単に言うと、 WideStudioでイベントプロシージャを記述すると、自動的にこの「object」というポインタが渡されるコードが生成されるのですが、呼び出し元の情報(ポインタ)がセットされるようになっています。

そこで、呼び出し元を操作したい場合は、このポインタを使って操作します。「object」の型は「WSCbase」というクラスで、プロパティ操作等のメソッドを含んだクラスです。よって、プロパティ操作をする場合、このクラスポインタをそのまましようすればOKです。

このように、WideStudioの場合、ウィンドウに対する操作は、ほとんど「setProperty」を実行することで行うことができます。つまり、ビルダの「プロパティ」ウィンドウから手入力であれこれしていることを、そのままプログラムで「setProperty」と書いていくだけで、同じことをすることができます。

プログラムコードと操作が直感的につながりやすいので、WideStudioで「いいなぁ〜」と思っている点の1つです。ところで、このプログラム、なんとなく無駄に2回も画像ファイルにアクセスしている気がするので、本当は、もっと良いやり方がありそうな気がします。う〜ん。

 

2005/01/20

WideStudioでマウスボタンをチェック

今日からROBO-ONEエントリー開始ですね!うちの進捗は、メカは、まだ未完成ですが、部品加工はほとんど終わっているので、週末ぐらいには形ができるかな〜ぐらいです。最近まで、SIPHA TERMのソースコード復活をやっていたので、そのまま、SIPHA TERMを改良してたりします。最近、しばらくプログラム触っていないと、プログラムの作り方を忘れてしまうんで、一気に!という感じです。そんなわけで、その中から出てきたTOPICをおひとつ。

マウスボタンチェック
20050120P00.JPG - 6,2884BYTES「マウスボタンチェック」…ボタン部品を作っておいて、ACTIVATEイベントプロシージャさえ書けば、あたりまえのようにボタン入力のプログラムを作ることができるのですが、ボタンを押すときに、ちょっと特別な機能を呼び出したい場合(例えば、左ボタンでボタンを押すと、1つだけサーボ信号オフ、右ボタンで押すと全部オフとか)、マウスボタンの判定をしたくなる時があります。

これまた、結構簡単だったので、やり方を紹介します。

WideStudioでは、「最後に押したマウスボタンを取り出す」機能があります。これを普通にボタンが押された時に呼び出される処理に追加してやればOKです。

具体的には、WSDmouseというクラスを使用します。

まずは、マウスのグローバルインスタンスを取得します。「???」な感じですが、SISOもよくわかってないです。きっと、アプリケーション中に、マウスを管理しているインスタンスとやらがあり、そこにアクセスするためには、まずは取得するということだと思って使っています。

WSDmouse* mouse = WSGIappMouse();

はい。これでマウスのグローバルインスタンスが取得できます。そして、後は判定するだけです。状態の取得は、getTargetBtn()を使用しますが、この返り値は次のように定義されています。

WS_MOUSE_BTN1	左ボタン
WS_MOUSE_BTN2	中ボタン(ホイール)
WS_MOUSE_BTN3	右ボタン

後はこれをSWITCH文などで振るようにコーディングするだけですね!ボタンが押された時の結果を表示するラベルを、"vlabClickStatus"という名前で作ってそこのところをコーディングすると、次のような感じになります。

WSDmouse* mouse = WSGIappMouse();

switch( mouse->getTargetBtn()){
case WS_MOUSE_BTN1:					//	左ボタン
    vlabClickStatus->setProperty( WSNlabelString, "左ボタン" );
    break;
case WS_MOUSE_BTN2:					//	中ボタン
    vlabClickStatus->setProperty( WSNlabelString, "中ボタン" );
    break;
case WS_MOUSE_BTN3:					//	右ボタン
    vlabClickStatus->setProperty( WSNlabelString, "右ボタン" );
    break;
}

最後に、ヘッダファイルのインクルードと、ラベル部品の外部宣言も忘れずにしておきます。これでばっちりです。
全プログラムのダウンロード

「これでいいのかな〜」なんてちょっと思ったりしますが、今のところ、大丈夫そうなので、きっと大丈夫でしょう。もし間違ってたら連絡お願いいたします。

 


SISO-LAB Knowledge