デフォルトのVCLに手を加えたくてソースを見たところ、Privateに宣言された変数に直接アクセスできれば、やりたいことが実現できることがわかりました。
このPrivateで宣言された変数(例:FFixedColor)にアクセスする裏技はありませんでしょうか。
そんなワザがあったら Privateの意味がなくなると思うけど。
そういう時は、
デフォルトのVCLをコピー&改編して
自分のプロジェクトファイルのあるフォルダにおけば、
優先的に参照されますよ。
投稿できないぞなぜだ・・・仮名なんてはいってないのに
THKCustomGrid(StringGrid1).FFixedColor := clRed;
StringGrid1.Invalidate;
日本語いれなと駄目か?
THackCustomGrid = class(TCustomControl)
private
FAnchor: TGridCoord;
FBorderStyle: TBorderStyle;
FCanEditModify: Boolean;
FColCount: Longint;
FColWidths: Pointer;
FTabStops: Pointer;
FCurrent: TGridCoord;
FDefaultColWidth: Integer;
FDefaultRowHeight: Integer;
FFixedCols: Integer;
FFixedRows: Integer;
FFixedColor: TColor;
end;
//StringGrid1.FixedColor := clRed;
THackCustomGrid(StringGrid1).FFixedColor := clRed;
StringGrid1.nvalidate;
ソースだけ(英字だけ)のっけると投稿できないのかここは・・・
↑コレだけじゃ、赤くならないけど...
赤くするコードも書かなくちゃダメなの?
THackCustomGrid = class(TCustomControl)
private
FAnchor: TGridCoord;
FBorderStyle: TBorderStyle;
FCanEditModify: Boolean;
FColCount: Longint;
FColWidths: Pointer;
FTabStops: Pointer;
FCurrent: TGridCoord;
FDefaultColWidth: Integer;
FDefaultRowHeight: Integer;
FFixedCols: Integer;
FFixedRows: Integer;
FFixedColor: TColor;
end;
は BDS2006の TCustomGrid なので他のバージョンの場合
書き換える必要があります
FFixedColor: TColor;
これ↑以外の変数は必要ないだろうと思って省いたのが悪かったみたい...
ほかの変数も書いたら、赤くなった。
なんで使わない変数も必要なのかな...
THackCustomGrid(StringGrid1).FFixedColor は
StringGird1の THackCustomGridのFixedColorが設定されている
位置にアクセスします。
THackCustomGrid = class(TCustomControl)
private
FFixedColor: TColor;
end;
だと StringGird1.FFixedColor の位置とは異なってしまうために
色が変化しません。
FAnchor: TGridCoord; の領域に書き込んでしまっています。
private部にアクセスするには,次のような方法もあります.
どうやらTStringGridのFixedColorの例らしいので...
type
TForm1 = class(TForm)
StringGrid1: TStringGrid;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
TMyStringGrid = TStringGrid;
var
Form1: TForm1;
implementation
{$R *.dfm}
// TStringGirdのprivate部のFixedColorを設定する
procedure TForm1.Button1Click(Sender: TObject);
begin
TMyStringGrid(StringGrid1).FixedColor := clRed;
end;
つまり,private部を使用するユニットに
TMyStrigGrid = TStringGrid;
のように,TStringGridの派生クラスを定義します(クラス名は任意).
これは決してインチキな方法ではなく,同じユニット内のprivate部にはアクセス可能
という原理を利用しています.
この場合,TMyStringGridはTStringGridと全く同じ内容ですから,そのprivate部が利用
できるというわけです.
>TMyStringGrid(StringGrid1).FixedColor := clRed;
この↑FixedColorは、Publishedのプロパティなので、TMyStringGridに
キャストしなくても、普通にアクセスできますよね(^^ゞ
でも、この方法では、Privateな FFixedColorにはアクセスできません。
FixedColorと
FFixedColorをカンチガイしましたか?
D6 のヘルプの「アクセスの制御」によれば private フィールドには、別ユニットに
定義された派生クラスからはアクセスできません。protected フィールドと勘違い
されたのでは?
>定義された派生クラスからはアクセスできません。protected フィールドと勘違い
されたのでは?
ありゃ,失礼しました.ゴメンなさい. (^_^;;
いろいろとありがとうございます。
やりたかったのは、DBGridのセルの位置をハッキリさせるため、
FixedRowとFixedColの色を変えたかったのです。
新たなColumnに入ったときに、ColumnsのTitleのColorを変えて、
もとのColumnの色を元にもどせば上手くいったのですが、
Rowはできませんでした。
どうもありがとうございました。
DBGridのFixedに色を付けるのでしたら
DrawCell を Override すればできますよ
手抜きでテキスト描画してませんが
procedure TDBGrid.DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState);
begin
inherited;
if (ACOL = 0) or (AROW = 0) then
begin
Canvas.Brush.Color := $FF0000;;
Canvas.FillRect(ARect);
end
else
if ARow = Row then
begin
Canvas.Brush.Color := $FF8800;
if gdSelected in AState then Canvas.Brush.Color := $AA8800;
Canvas.FillRect(ARect);
end;
end;
いつもお世話になっています。
>DBGridのFixedに色を付けるのでしたら
>DrawCell を Override すればできますよ
上のOverrideの方法を具体的に教えていただけませんでしょうか?
何が悪いのかコンパイルできません。
よろしくお願いします。
>何が悪いのかコンパイルできません。
真琴:「"コンパイルできない"って言ってるけど、どんなコード書いたのかなぁ」
広海:「この上のサンプルコードを書き加えただけなんじゃないの?」
海都:「そうかな? もし、そうならコンパイル出来ないのは当たり前…、こうしなくちゃ」
type
TDBGrid = class(DBGrids.TDBGrid)
public
procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); override;
end;
procedure TDBGrid.DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState);
begin
inherited;
if (ACol > 0)and(AROW = 0) then begin
Canvas.Brush.Color := $DD88FF;
InflateRect(ARect, -1, -1);
Canvas.FillRect(ARect);
Canvas.TextOut(ARect.Left + 2, ARect.Top + 2, Fields[ACol-1].FieldName);
end else
if ARow = Row then begin
Canvas.Brush.Color := $FF8800;
if gdSelected in AState then Canvas.Brush.Color := $AA8800;
Canvas.FillRect(ARect);
if ACol = 0 then
Canvas.TextOut(ARect.Left + 3, ARect.Top + 2, '>')
else
Canvas.TextOut(ARect.Left + 2, ARect.Top + 2, Fields[ACol-1].DisplayText);
end else
if ACol = 0 then begin
Canvas.Brush.Color := $FF88BB;
InflateRect(ARect, -1, -1);
Canvas.FillRect(ARect);
end;
end;
真琴:「ねぇ、カイトさん、新しいクラスの宣言で、同じ"TDBGrid"の名前を使ってもいいの?」
海都:「普通は別名の方がイイけどね、DBGrids.TDBGridのように書けば同じ名前でも大丈夫」
真琴:「あれ?…カイトさん、このコード書き足してみても、色変わらないよ、エラーは出ないけど」
広海:「ウソ、教えてるンじゃないのぉ? アンタもタマには冗談こいたりして」
海都:「オレはお前とは違うの、茶化すンじゃないよ」
春子:「新しいクラスを動的に作成して、元の DBGrid1と入れ換えればイイのよね? カイトさん」
海都:「そう、新コンポにするよりは、動的生成の方がラクだと思うよ」
真琴:「でもぉ…、動的生成って、フォームに貼り付けるわけイカナイでしょ? それも面倒じゃない?」
海都:「そういう時こそ、クローン関数の出番、いわゆる万能細胞のようなもの」
真琴:「えっ、万能細胞? あっ、最近ニュースで言ってたよね、京大の教授が世界で初めて作ったって」
海都:「ま、そこまでスゴクはないけど、貼り付けたどんなTControlとも入れ換えが出来て、便利な関数だよ」
type
TCloneClass = class of TControl;
function CreateClone(Origin: TControl; CloneClass: TCloneClass): TControl;
var
Stream: TStream;
begin
result := CloneClass.Create(Origin.Owner);
Stream := TMemoryStream.Create;
try
with TWriter.Create(Stream, $1000) do try
Root := Origin.Owner;
WriteSignature;
WriteComponent(Origin);
WriteListEnd;
finally
Free;
end;
with TReader.Create(Stream, $1000) do try
Root := Origin.Owner;
// Owner := Origin.Owner;
Parent := TControl(Origin).Parent;
Origin.Free;
Position := 0;
BeginReferences;
try
ReadSignature;
ReadComponent(result);
FixupReferences;
finally
EndReferences;
end;
finally
Free;
end;
finally
Stream.Free;
end;
end;
海都:「置き換えは、FormのOnCreateハンドラに、CreateClone(DBGrid1, TDBGrid);と書くだけ」
真琴:「それだけで、フォームに貼り付けたDBGrid1と置き換え? あっホント色変わった、これスッゴク便利」
広海:「オレは万能細胞よりか、万能財布の方がイイけどね」
真琴:「万能財布? ナニそれ」
広海:「いくら使ってもぉ、中のカネが減らないのが万能財布、…そんなの欲しいよなぁ」
春子:「さッすが、ヒロミくんらしい発想、…スゴイわ」
広海:「だよね、ネネッ、みんなもソウ思うよね」
真琴:「あのねェ、それって、誉められてるんじゃなくて…」
万能財布さん、ありがとうございました。
>type
> TDBGrid = class(DBGrids.TDBGrid)
まさにこの部分をどう記述すれば良いのか分かりませんでした。
CreateClone()については、下のサイトでも拝見させていただいていて、万能財布さんのソース含めこれから試してみたいと思います。
http://www.geocities.jp/asumaroyuumaro/program/tips/replacecompo.html
そういえば、便乗質問失礼しました。
TDBGrid = class(DBGrids.TDBGrid)
public
procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); override;
end;
を TForm1 = class(TForm) の前に配置すれば Clone は不要
ただし全ての TDBGrid が変更されるけど
個別にしたい場合には Clone を作らないと駄目だけど
ツイート | ![]() |