(11/12/01~)

11/12/01

スレート PC プログラミング
 先日の TTouchKeyboard の雑談を転記。

ONKYO TW2A シリーズ
 12/09 に発売が延期された模様。

  TW2A-A25Z7CK
(店頭販売モデル)
TW2A-A25Z7D
(直販モデル)
TW2A-A25Z7H
(法人向けモデル)
TW2A-A25Z7PH
(法人向けモデル)
OS WindowsR 7 Home Premium 32ビット 正規版
Service Pack 1 (SP1) 適用済み
WindowsR 7 Professional 32ビット 正規版
Service Pack 1 (SP1) 適用済み
キーボード Bluetooth キーボード
専用ケース
デジタイザペン
価格 60,000円 前後 59,800円 ~ 60,000円 前後 70,000円 前後

 TW2A-A25Z7PH (法人向けモデル) を買う位なら、TW2A-A25Z7CK (店頭販売モデル) を購入して Windows Anytime Upgrade 買った方がよくないか?付属品と価格差的に。


11/12/08

TurboPower プロジェクト
 現状を調べてみました。前回調査は半年前です。

 Delphi 6 よりも前の環境/製品は省略しています。


11/12/12

Programming the iOS Accelerometer and Camera using Delphi and FireMonkey と DirectShow
 正直な話をすると、Windows のセンサーとかカメラ (WebCam) もやらずに iOS でやるのは順序が違うんじゃないかと思うのです。とりあえず Windows で出来ることをあらかた網羅してからやるべきかと...あ、いや Tim DelChiaro 氏の記事に問題がある訳じゃないですよ。

 Windows で WebCam を扱うには DSPack を使うのが簡単です...とはいえ、DirectShow そのものが面倒なので DSPack のサンプルをクラスでラッピングしてさらに簡単に使えるようにしてみました。

// -----------------------------------------------------------------------------
// DSPack を使ったカメラ (静止画) クラス
// -----------------------------------------------------------------------------
unit StillCam;

interface

uses
  SysUtils, Types, DSPack, DXSUtil, DirectShow9, Graphics, Jpeg;

type

  { TStillCamera }
  TStillCamera = class(TObject)
  private
    FActive: Boolean;
    FBaseDir: string;
    FDeviceIndex: Integer;
    FDevices: TStringDynArray;
    FFilter: TFilter;
    FFilterGraph: TFilterGraph;
    FSampleGrabber: TSampleGrabber;
    FSysDevEnum: TSysDevEnum;
    FVideoWindow: TVideoWindow;
    procedure SetActive(const Value: Boolean);
    procedure SetVideoWindow(const Value: TVideoWindow);
    procedure SetDeviceIndex(const Value: Integer);
  public
    constructor Create;
    destructor Destroy; override;                                               // 使用するカメラデバイスのインデックス
    property Devices: TStringDynArray read FDevices;                            // カメラデバイスの一覧
    procedure GetBitmap(var Bitmap: TBitmap);                                   // キャプチャ画像を Bitmap へ取り込み
    procedure Capture; overload;                                                // キャプチャ画像を連番で Jpeg 画像として保存
    procedure Capture(const FileName: TFileName); overload;                     // キャプチャ画像に名前を付けて Jpeg 画像で保存
    property Active: Boolean read FActive write SetActive;                      // カメラの有効/無効
    property BaseDir: string read FBaseDir write FBaseDir;                      // 画像保存先
    property DeviceIndex: Integer read FDeviceIndex write SetDeviceIndex;       // デバイス (カメラ) のインデックス
    property FilterGraph: TFilterGraph read FFilterGraph;                       // Fileter Graph
    property VideoWindow: TVideoWindow read FVideoWindow write SetVideoWindow;  // プレビュー用のビデオウィンドウ
  end;

implementation

{ TStillCamera }

constructor TStillCamera.Create;
// コンストラクタ
var
  i: Integer;
begin
  FBaseDir := '';
  FVideoWindow := nil;
  // FilterGraph
  FFilterGraph := TFilterGraph.Create(nil);
  with FFilterGraph do
    begin
      GraphEdit := True;
      LinearVolume := True;
      Mode := gmCapture;
    end;
  // Filter
  FFilter := TFilter.Create(nil);
  with FFilter do
    FilterGraph := FFilterGraph;
  // SampleGrabber
  FSampleGrabber := TSampleGrabber.Create(nil);
  with FSampleGrabber do
    FilterGraph := FFilterGraph;
  // Devices
  FDeviceIndex := -1;
  FSysDevEnum := TSysDevEnum.Create(CLSID_VideoInputDeviceCategory);
  if FSysDevEnum.CountFilters > 0 then
    begin
      SetLength(FDevices, FSysDevEnum.CountFilters);
      for i:=0 to FSysDevEnum.CountFilters-1 do
        Devices[i] := FSysDevEnum.Filters[i].FriendlyName;
      DeviceIndex := 0;
    end;
end;

destructor TStillCamera.Destroy;
// デストラクタ
begin
  FFilterGraph.ClearGraph;
  FFilterGraph.Active := False;
  FSysDevEnum.Free;
  FSampleGrabber.Free;
  FFilter.Free;
  FFilterGraph.Free;
  inherited;
end;

procedure TStillCamera.SetActive(const Value: Boolean);
// カメラの有効/無効
begin
  if FActive = Value then
    Exit;
  if FDeviceIndex = -1 then
    Exit;
  FFilterGraph.ClearGraph;
  FFilterGraph.Active := False;
  if Value then
    begin
      FFilter.BaseFilter.Moniker := FSysDevEnum.GetMoniker(FDeviceIndex);
      FFilterGraph.Active := True;
      with FFilterGraph as ICaptureGraphBuilder2 do
        RenderStream(@PIN_CATEGORY_PREVIEW, nil, FFilter as IBaseFilter, FSampleGrabber as IBaseFilter, FVideoWindow as IBaseFilter);
      FFilterGraph.Play;
    end;
  FActive := Value;
end;

procedure TStillCamera.SetDeviceIndex(const Value: Integer);
// デバイス (カメラ) のインデックスを設定
begin
  if FDeviceIndex = Value then
    Exit;
  FDeviceIndex := Value;
end;

procedure TStillCamera.SetVideoWindow(const Value: TVideoWindow);
// プレビュー用のビデオウィンドウを設定
begin
  FVideoWindow := Value;
  if Assigned(FVideoWindow) then
    FVideoWindow.FilterGraph := FFilterGraph;
end;

procedure TStillCamera.GetBitmap(var Bitmap: TBitmap);
// キャプチャ画像を Bitmap へ取り込み
begin
  FSampleGrabber.GetBitmap(Bitmap);
end;

procedure TStillCamera.Capture;
// キャプチャ画像を連番で Jpeg 画像として保存
begin
   Capture(FormatDateTime('"img"YYYYMMDDHHNNSS".jpg"', Now));
end;

procedure TStillCamera.Capture(const FileName: TFileName);
// キャプチャ画像に名前を付けて Jpeg 画像で保存
var
  Bitmap: TBitmap;
  Jpeg: TJpegImage;
  dFileName: TFileName;
begin
  Bitmap := TBitmap.Create;
  Jpeg := TJPEGImage.Create;
  try
    FSampleGrabber.GetBitmap(Bitmap);
    Jpeg.Assign(Bitmap);
    dFileName := FileName;
    if FBaseDir <> '' then
      dFileName := IncludeTrailingPathDelimiter(FBaseDir) + dFileName;
    Jpeg.SaveToFile(dFileName);
  finally
    Jpeg.Free;
    Bitmap.Free;
  end;
end;
end.

 使い方は、Button ([Standard] カテゴリ) と VideoWindow ([DSPack] カテゴリ) をフォームに貼って、

uses
  ..., StillCam; 


...

type
  TForm1 = class(TForm)
    VideoWindow1: TVideoWindow;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
    StillCamera: TStillCamera;
  public
    { Public 宣言 }
  end;

...  

procedure TForm1.FormCreate(Sender: TObject);
begin
  StillCamera := TStillCamera.Create;
  StillCamera.VideoWindow := VideoWindow1;
  StillCamera.Active := True;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  StillCamera.Capture;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  StillCamera.Free;
end;

 ボタンを押すと実行ファイルのある場所に日付の連番で *.jpg を生成します。このクラスでもそこそこ実用的なのですが、もうちょっと凝ってみると面白いと思います。ちょっと仕事がテンパってるので、それはまたの機会にでも...。

明日
 ん?明日は 11/12/13 か。また "鉄ちゃんの日" なのか?


11/12/17

TTouchKeyboard とファンクションキー
 Delphi XE2 の Update3 がリリースされ、"タッチパネルの場合、フレームの上に載せた TTouchKeyboard はキーを押しても反応しない" という QC#97941 も修正されたようですし、もう一つ TTouchKeyboard のサンプルを (...まぁ、欲を言えばサポート期間が切れていないのだから、XE にもバックポートして欲しいのですけどね)。

 今日は、業務アプリによくあるファンクションキーを作ってみたいと思います。基本的なカスタムタッチキーボードの作り方は 11/26 以降の雑談を読んで下さい。キーボードレイアウト XML ファイル (FUNCTIONKEYBOARD.xml) はこうなります。

<keyboard keyboardname="Function" keyboardtype="Function" width="848" height="56" minwidth="480" minheight="32" rowheight="48">
        <row topmargin="4" bottommargin="4">
                <key vk="112" caption="F1"  publishedname="Func01" width="48" height="48" leftmargin="6" rightmargin="2" fontsize="10" stretch="true"/>
                <key vk="113" caption="F2"  publishedname="Func02" width="48" height="48" leftmargin="2"                 fontsize="10" stretch="true"/>
                <key vk="114" caption="F3"  publishedname="Func03" width="48" height="48" leftmargin="2"                 fontsize="10" stretch="true"/>
                <key vk="115" caption="F4"  publishedname="Func04" width="48" height="48" leftmargin="2"                 fontsize="10" stretch="true"/>
                <key vk="116" caption="F5"  publishedname="Func05" width="48" height="48" leftmargin="6"                 fontsize="10" stretch="true"/>
                <key vk="117" caption="F6"  publishedname="Func06" width="48" height="48" leftmargin="2"                 fontsize="10" stretch="true"/>
                <key vk="118" caption="F7"  publishedname="Func07" width="48" height="48" leftmargin="2"                 fontsize="10" stretch="true"/>
                <key vk="119" caption="F8"  publishedname="Func08" width="48" height="48" leftmargin="2"                 fontsize="10" stretch="true"/>
                <key vk="120" caption="F9"  publishedname="Func09" width="48" height="48" leftmargin="6"                 fontsize="10" stretch="true"/>
                <key vk="121" caption="F10" publishedname="Func10" width="48" height="48" leftmargin="2"                 fontsize="10" stretch="true"/>
                <key vk="122" caption="F11" publishedname="Func11" width="48" height="48" leftmargin="2"                 fontsize="10" stretch="true"/>
                <key vk="123" caption="F12" publishedname="Func12" width="48" height="48" leftmargin="2" rightmargin="4" fontsize="10" stretch="true"/>
        </row>
</keyboard>

 普通に VK_F1 ~ VK_F12 を返すキーボードです。

uses
  ...Keyboard, KeyboardTypes;

  ...

type
  TTempTouchKeyboard = class(TCustomTouchKeyboard);
  TForm1 = class(TForm)
  ...  

procedure TForm1.FormCreate(Sender: TObject);
begin
  TouchKeyboard1.Align  := alBottom;
  TouchKeyboard1.Layout := 'Function';
  TouchKeyboard1.Height := 36;
  TTempTouchKeyboard(TouchKeyboard1).Buttons[ 0].Caption := 'F1: 登録';
  TTempTouchKeyboard(TouchKeyboard1).Buttons[11].Caption := 'F12: 終了';
end;

 実行時にファンクションキーボードに変更します。

 こんな感じですね。多少の不満は残るかもしれませんが、簡単にファンクションメニューを実現できるのは大きなメリットだと思います。


11/12/18

怠け者の理論
 つい最近知ったのだけれど、"プログラマの三大美徳" というのがあるそうな。

   リンク先の記事の "怠慢" はちょっとニュアンスが違うと思う...原文の意味のままでいいんじゃないかと。

全体の労力を減らすために手間を惜しまない気質。
この気質の持ち主は、役立つプログラムを書いてみんなの苦労を減らしたり、同じ質問に何度も答えなくてもいいように文書を書いたりする。
よって、プログラマーの第一の美徳である。

 無駄...確かにキライだなぁ。だから、"QC / 青 QC / RAID の仕組み" は大嫌いです。QC 情報を見てバグを把握する作業は苦ではないのですが、QC 見ても載ってなくてレポートすると RAID との重複だったり、青 QC にあって既に FT 期間を終えているのに一般的には青 QC が見えないために、同じ QC が何度も登録されては重複扱いされたりするのを見ると、その度に 「どうにかならんもんか...」 と思います。

プチコン (Nintendo DS)
 うは、こんなのあったのか。でも、比較演算子が BASIC らしくない (等価が "==" だったり) なぁ。そういや、Google Go も全体的には C / C++ みたいなのに、代入演算子が ":=" だったり、変数宣言が変数名が先で型が後だったりするっけな...1.0 はまだなんだっけ?


 BACK   古いのを読む   新しいのを読む