Lazarus特練 タイマーアプリを作ってみる(3)

TBitmapに一旦描画して、BitBltでListBox.Canvasに転送するつもりで、コンパイルしてみたら問題が起きました。
BitBltはWindowsユニットに入ってるんだと思うんですけど、Windowsをusesすると、DrawItemのイベントハンドラを定義するだけでコンパイルエラーになってしまいます。
他にも、TBitmapも、Graphics.TBitmapってわざわざ言わないと、Windows.TBitmapとごっちゃになるらしく。もう。
あぁそうか。と気づいて

uses (略),Windows;

ってしてたのを

uses Windows,(略);

に直したらエラーが起きなくなりました。デフォルトだとWindowsがusesされてないので、末尾に付け加えたんですけど、順序に問題があったようです。
じゃぁ、どこならいいのかと思って、Graphicsの後に動かしてみたんですが、大丈夫。あれてなもんで、コンパイルエラーが間違いなく起きた末尾に移動。大丈夫。なんだかねじれが取れちゃったみたいです。
でも、一番初めに移動しておくことにします。

***
結論からいうと、BitBlt使うとすっごく遅いです。ListBoxのCanvasに直接描いていったほうが早い。ちょっとびっくりしました。Delphiでもそうだったかな?覚えてないです。

今更ですけど、エディタじゃなし、ちらついても我慢できる気がしてきました。ちらつき撲滅はすごい勉強になるけれども、これをやりだすと泥沼過ぎて前に進まない罠です。動くものを作って、それが気に入ったらちらつかせない努力、がきっと正解です。

***
そんなこんなで、中身は全然タイマーしてないですけど、お手本に似た感じなるように座標をベタ打ちして見た目だけ似せてみました。

procedure TForm1.LBoxDrawItem(Control: TWinControl; Index: Integer;
ARect: TRect; State: TOwnerDrawState);
var
LRect: TRect;
LText: String;
LStyle: TTextStyle;
begin
//TCanvas.TextRectで指定できるスタイル。Delphi6には絶対なかった。
//WinAPIでいうところのDrawTextExで指定できる内容。
//指定したRectの中で上下左右の寄せ具合を指定できます。
//上下の中央に描画するための座標計算が要らないのが幸せ。
FillChar(LStyle, SizeOf(LStyle), 0);
LStyle.Alignment := taLeftJustify;
LStyle.Layout := tlCenter;
LStyle.SingleLine := False;
LStyle.Clipping := True;
LStyle.ExpandTabs := False;
LStyle.ShowPrefix := False;
LStyle.Wordbreak := False;
LStyle.Opaque := True;
LStyle.SystemFont := False;
LStyle.RightToLeft := False;

//まずは背景塗りつぶし。このイベントが呼び出された時点で
//選択か非選択かでCanvas.Brush.ColorとCanvas.Font.Colorが
//すでに設定されてるのでそれをそのまま使います。
LRect := ARect;
LBox.Canvas.FillRect(LRect);

//次にImageListに取り込んだ時計とかのアイコンを描画
//テストなのでアイコンは3つを順繰りに表示
Images.Draw(LBox.Canvas, ARect.Left + 16, ARect.Top + 16,
Index mod 3);

//それからカウントダウンのところを描画
LRect.Left := LRect.Left + 88;
//文字をでかく太くします。
LBox.Canvas.Font.Size := LBox.Canvas.Font.Size + 4;
LBox.Canvas.Font.Style := LBox.Canvas.Font.Style + [fsBold];
LText := '04:47:57';
LBox.Canvas.TextRect(LRect, LRect.Left, LRect.Top, LText, LStyle);

//右端の3行を描画するためにStringList.Textで渡してます。
LRect.Left := LRect.Left + 96;
//文字を元に戻してます。
LBox.Canvas.Font.Size := LBox.Canvas.Font.Size - 4;
LBox.Canvas.Font.Style := LBox.Canvas.Font.Style - [fsBold];
FStrBuf.Text := LBox.Items[Index];
FStrBuf.Add('2012/05/17 15:00:00');
FStrBuf.Add('Bells1');
//Trim(FStrBuf.Text)にしないと最後の空行が邪魔します。
LBox.Canvas.TextRect(LRect, LRect.Left, LRect.Top, Trim(FStrBuf.Text), LStyle);
end;


こんな感じ。一番上はお手本です。2行目以降はListBoxに描画してます。


ところで、ImageList.Drawの最後の引数にFalse(指定しなければTrueになってます)を渡すと、白黒で描画してくれます。いわゆるDisable状態。ということは3つも画像が要らないということで。


よく見ると、アイコンだけ下に寄ってるみたいです。文字は勝手にやってくれますけど、アイコンは自分で高さを決めてるから失敗してます。
(Rect.Bottom - Rect.Top) div Images.Height
か何かで縦位置決めないと行けないです。

それはそうと、、ImageList.Drawの最後の引数は、True/FalseでEnable/Disableを切り替える以外に、TGraphicsEffectという構造体を渡せるようです。話ずれますけど次回はこれを試してみます。

続く。
関連記事
スポンサーサイト