所有者が描画するネイティブの「タブ コントロール」のタブ ( TPageControl
VCL では、そのアセンダントは適切に命名されていますが、クリエイティブな命名の理由は誰でも推測できます..) は、メッセージのTCustomTabControl
処理中に親コントロールによって描画されることが期待されます。 .WM_DRAWITEM
VCL は、メッセージをメッセージに変更し、CN_DRAWITEM
それをコントロール自体に送信することで、親から負担を取り除きます。このプロセスでは、VCL はそれ以上介入しません。OnDrawTab
メッセージ ハンドラーがユーザー コードによって割り当てられている場合は、メッセージ ハンドラーを呼び出し、適切なパラメーターを渡します。
したがって、タブの周囲に境界線を引くのは VCL ではなく、OS 自体です。また、明らかに、これはWM_DRAWITEM
メッセージの処理中に行われるのではなく、後の描画プロセスで行われます。WM_DRAWITEM
これは、ページ コントロールの親に空のハンドラーを配置することで確認できます。その結果、イベント ハンドラーで何をペイントしても、後で OS によって境界線が取得されます。
OS が描画するものを有効にしないようにしようとするかもしれません。結局のところ、デバイス コンテキスト (Canvas.Handle として) があります。残念ながら、このルートも行き止まりです。これは、VCL がイベント ハンドラーから戻った後、デバイス コンテキストの状態を復元するためです。
したがって、唯一の方法は、OnDrawTab
イベントの処理とCN_DRAWITEM
メッセージに対する操作を完全に放棄することです。以下のサンプル コードではインターポーザ クラスを使用していますが、任意の方法でコントロールをサブクラス化できます。が設定されていることを確認してくださいOwnerDrawn
。
type
TPageControl = class(comctrls.TPageControl)
protected
procedure CNDrawitem(var Message: TWMDrawItem); message CN_DRAWITEM;
end;
TForm1 = class(TForm)
..
..
procedure TPageControl.CNDrawitem(var Message: TWMDrawItem);
var
Color: TColor;
Rect: TRect;
Rgn: HRGN;
begin
Color := 0;
// draw in different colors so we see where we've drawn
case Message.DrawItemStruct.itemID of
0: Color := $D0C0BF;
1: Color := $D0C0DF;
2: Color := $D0C0FF;
end;
SetDCBrushColor(Message.DrawItemStruct.hDC, Color);
// we don't want to get clipped in the passed rectangle
SelectClipRgn(Message.DrawItemStruct.hDC, 0);
// magic numbers corresponding to where the OS draw the borders
Rect := Message.DrawItemStruct.rcItem;
if Bool(Message.DrawItemStruct.itemState and ODS_SELECTED) then begin
Inc(Rect.Left, 2);
// Inc(Rect.Top, 1);
Dec(Rect.Right, 2);
Dec(Rect.Bottom, 3);
end else begin
Dec(Rect.Left, 2);
Dec(Rect.Top, 2);
Inc(Rect.Right, 2);
Inc(Rect.Bottom);
end;
FillRect(Message.DrawItemStruct.hDC, Rect,
GetStockObject(DC_BRUSH));
// just some indication for the active tab
SetROP2(Message.DrawItemStruct.hDC, R2_NOTXORPEN);
if Bool(Message.DrawItemStruct.itemState and ODS_SELECTED) then
Ellipse(Message.DrawItemStruct.hDC, Rect.Left + 4, Rect.Top + 4,
Rect.Left + 12, Rect.Top + 12);
// we want to clip the DC so that the borders to be drawn are out of region
Rgn := CreateRectRgn(0, 0, 0, 0);
SelectClipRgn(Message.DrawItemStruct.hDC, Rgn);
DeleteObject(Rgn);
Message.Result := 1;
inherited;
end;
上記がここでどのように見えるかを次に示します。
