むしろ、チラシの裏。
GIMP2.6 がつくるビットマップは BitmapVer,3 規格を拡張した独自のファイル。
もともと、Ver,3 ではアルファチャンネルをサポートしておらず、扱えるようになったのは Ver,4 から。誰が始めたのかはわからないけど、先走っちゃったらしい。あるいは、マイクロソフトが泥縄したのかも。
Delphi 2009 以降の TBitmap がサポートしているのはこの形式。
GIMP2.8 がつくるビットマップは BitmapVer,5 規格に基づいた正式なファイル。
なんだけど、32ビット形式のビットマップが読めるソフトは独自規格が対象で、正式なファイルは表示がおかしくなる。と、言うか、Ver,3 以降のビットマップを編集できるソフトが見つからなかった。GIMP 自体、2.6 と 2.8 で互換性が無いし。
TBitmap もこちらには未対応。
つまり、GIMP2.8 が作る32ビット形式のビットマップは、マイクロソフトの規格に従っているため、ほかのソフトは対応していない。
とりあえずは、TBitmap の対応待ち。まあ、みんなして様子見してるから、正式なフォーマットが復旧しないのかもしれないけど。
CalcSizingState プロテクトメソッドをオーバーライドする。
たとえば、先頭の固定セルの幅を変えるなら、
procedure TStringGrid.CalcSizingState(X, Y: Integer; var State: TGridState;
var Index: Longint; var SizingPos, SizingOfs: Integer;
var FixedInfo: TGridDrawInfo);
begin
inherited;
if (ColWidths[0] - 2 <= X) and (X <= ColWidths[0] + GridLineWidth + 2) and (Y <= RowHeights[0]) then
begin
State := gsColSizing;
Index := 0;
SizingPos := ColWidths[0];
SizingOfs := ColWidths[0] - X;
end;
end;
State はリサイズする方向。Index はセルのインデックス。SizingPos はセルの境界位置。SizingOfs はセル境界とカーソル位置の差。
結局は Vcl.ComCtrls.TPageControl をオーナードローするのだけど、OnDrawTab イベントではタブの見た目を変えられない(外枠を描画してしまう)ので、CN_DRAWITEM メッセージを処理する。
このとき、タブの範囲全体を描画できるよう、クリッピングリージョンを解除してから描画して、描き終わったらタブの枠を描けないようにリージョンのサイズをゼロにするのがコツ。
procedure Form1.SubWndProc(var Message: TMessage);
var
TabCanvas: TCanvas;
Region: HRGN;
begin
FOlgWndProc(Message);
case Message.Msg of
CN_DRAWITEM:
begin
TabCanvas := TCanvas.Create;
try
TabCanvas.Handle := TWMDrawItem(Message).DrawItemStruct.hDC;
SelectClipRgn(TabCanvas.Handle, 0); //クリッピングリージョンを解除。
{ 好きな形状で描画。
タブの位置、インデックス、マルチラインを考慮して描き分ける。
めちゃくちゃ長くなるので省略 }
Region := CreateRectRgn(0, 0, 0, 0); //クリッピングリージョンのサイズをゼロに。
try
SelectClipRgn(TabCanvas.Handle, Region);
finally
DeleteObject(Region);
end;
finally
TabCanvas.Free;
end;
Message.Result := 1;
end;
end;
end;
TPageControl のウィンドウプロシージャを差し替える形なら上のようになるけど、かなり手間。
Vcl.ActnMenus.TActionMainMenuBar なら、アクションマネージャエディタから項目をドラッグアンドドロップで下位項目も作成できるけど、Vcl.ActnCtrls.TActionToolBar だとトップレベルの項目しか作成できないので、各項目の Items プロパティに下位項目を追加する。
具体的には、
1.フォームデザイナか構造ビューからドロップダウンメニューをつけたいボタン(TActionClientItem)を選択。
2.オブジェクトインスペクタで Items プロパティをダブルクリック。
3.ポップアップした編集ダイアログで下位項目を新規追加。
4.追加した項目の Action プロパティにアクションを割り当てる。
5.追加直後はボタンに反映されないので、保存して開きなおせば出来上がり。
ツリーノードに子ノードを追加する要領と同じなんだけど、専用のダイアログとかがないのでちょっと手間。
作成した下位項目は、TCustomDropDownButton を継承した TStandardDropDownButton, TThemedDropDownButton, TXPStyleDropDownBtn のいずれか(TActionManager.Style 次第)に結び付けられている。
なので、コードでメニューをドロップダウンするには、これの DropDownClick メソッドを使用する。
procedure TForm1.Action1Execute(Sender: TObject);
var
Pt: TPoint;
Item: TControl;
begin
Pt := ActionToolBar1.ScreenToClient(Mouse.CursorPos);
Item := ActionToolBar1.ControlAtPos(Pt, True);
if Item is TCustomActionControl then
begin
Pt.X := Item.Left + Item.Width - 4; //目見当。
Pt.Y := Item.Top + Item.Height div 2;
Item := ActionToolBar1.ControlAtPos(Pt, True);
if Item is TCustomDropDownButton then
TCustomDropDownButton(Item).DropDownClick;
end;
end;
大体こんな感じだけど、ドロップダウンボタンが右側にある前提なので、環境によってはうまくいかないかも。
Vcl.ComCtrls.TListView.Items と TTreeView.Items の更新は、描写処理が行われるまで保留される。
このため、 Visible = False だと表示されるまで更新されず、この間は HandleAllocated = False, Items.Count = 0 で、画面オブジェクトハンドルが解放されたままになる。
フォームを非表示にしている間にデスクトップテーマが変わった場合、フォームを表示するまでリストビューとツリービューからアイテムが読み出せない。読み方によっては、アクセス違反を起こすかも。
また、アイテムが読めないので Item.Data にもアクセスできない。何らかの値を設定していた場合、この状態で終了するとメモリリークを起こす。
フォームを非表示で動作するタスクトレイ常駐型のプログラムで、動作設定にリストビューを使っていると、誤動作のもとになる。
表示されていない間は描写しないのはいいとしても、アイテムを読めないのは不具合のような……。Vcl.StdCtrls.TCheckBox とかは平気なんだし。
ともあれ、Items を読み出す前に HandleNeeded を呼んで更新しておけば、誤動作は防げる。
手っ取り早いところで、
interface
type
TListView = class(Vcl.ComCtrls.TListView)
private
function GetItems: TListItems;
procedure SetItems(Value: TListItems);
published
property Items: TListItems read GetItems write SetItems;
end;
implementation
function TListView.GetItems: TListItems;
begin
HandleNeeded;
Result := inherited Items;
end;
procedure TListView.SetItems(Value: TListItems);
begin
HandleNeeded;
inherited Items := Value;
end;
というのをフォームの前に追加するのが楽かも。コピペで使いまわせるし。