privateで宣言された変数にアクセスする方法


Hoshi  2008-01-09 20:50:48  No: 29230

デフォルトのVCLに手を加えたくてソースを見たところ、Privateに宣言された変数に直接アクセスできれば、やりたいことが実現できることがわかりました。
このPrivateで宣言された変数(例:FFixedColor)にアクセスする裏技はありませんでしょうか。


う〜ん...  2008-01-09 21:03:36  No: 29231

そんなワザがあったら Privateの意味がなくなると思うけど。


もにゃ  2008-01-09 21:13:58  No: 29232

そういう時は、
デフォルトのVCLをコピー&改編して
自分のプロジェクトファイルのあるフォルダにおけば、
優先的に参照されますよ。


KHE00221  URL  2008-01-09 21:28:52  No: 29233

投稿できないぞなぜだ・・・仮名なんてはいってないのに


KHE00221  2008-01-09 21:31:17  No: 29234

THKCustomGrid(StringGrid1).FFixedColor := clRed;
StringGrid1.Invalidate;

日本語いれなと駄目か?


KHE00221  URL  2008-01-09 21:33:14  No: 29235

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;

ソースだけ(英字だけ)のっけると投稿できないのかここは・・・


あれ...  2008-01-09 21:49:21  No: 29236

↑コレだけじゃ、赤くならないけど...
赤くするコードも書かなくちゃダメなの?


KHE00221  2008-01-09 21:52:30  No: 29237

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 なので他のバージョンの場合
書き換える必要があります


あっ  2008-01-09 22:06:30  No: 29238

FFixedColor: TColor;
これ↑以外の変数は必要ないだろうと思って省いたのが悪かったみたい...
ほかの変数も書いたら、赤くなった。
なんで使わない変数も必要なのかな...


KHE00221  2008-01-09 22:29:21  No: 29239

THackCustomGrid(StringGrid1).FFixedColor は

StringGird1の THackCustomGridのFixedColorが設定されている
位置にアクセスします。

THackCustomGrid = class(TCustomControl)
private
  FFixedColor: TColor;
end;

だと StringGird1.FFixedColor の位置とは異なってしまうために
色が変化しません。

FAnchor: TGridCoord; の領域に書き込んでしまっています。


Mr.XRAY  2008-01-10 06:54:27  No: 29240

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部が利用
できるというわけです.


あの...  2008-01-10 18:17:51  No: 29241

>TMyStringGrid(StringGrid1).FixedColor := clRed;
この↑FixedColorは、Publishedのプロパティなので、TMyStringGridに
キャストしなくても、普通にアクセスできますよね(^^ゞ
でも、この方法では、Privateな FFixedColorにはアクセスできません。
FixedColorと
FFixedColorをカンチガイしましたか?


うんと  2008-01-10 19:54:38  No: 29242

D6 のヘルプの「アクセスの制御」によれば private フィールドには、別ユニットに
定義された派生クラスからはアクセスできません。protected フィールドと勘違い
されたのでは?


Mr.XRAY  2008-01-11 03:04:32  No: 29243

>定義された派生クラスからはアクセスできません。protected フィールドと勘違い
されたのでは?

ありゃ,失礼しました.ゴメンなさい. (^_^;;


Hoshi  2008-01-11 04:31:32  No: 29244

いろいろとありがとうございます。
やりたかったのは、DBGridのセルの位置をハッキリさせるため、
FixedRowとFixedColの色を変えたかったのです。
新たなColumnに入ったときに、ColumnsのTitleのColorを変えて、
もとのColumnの色を元にもどせば上手くいったのですが、
Rowはできませんでした。

どうもありがとうございました。


KHE00221  URL  2008-01-11 04:52:42  No: 29245

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;


moru  2008-02-19 04:01:49  No: 29246

いつもお世話になっています。

>DBGridのFixedに色を付けるのでしたら
>DrawCell を Override すればできますよ
上のOverrideの方法を具体的に教えていただけませんでしょうか?

何が悪いのかコンパイルできません。
よろしくお願いします。


万能財布  2008-02-19 09:31:58  No: 29247

>何が悪いのかコンパイルできません。

真琴:「"コンパイルできない"って言ってるけど、どんなコード書いたのかなぁ」
広海:「この上のサンプルコードを書き加えただけなんじゃないの?」
海都:「そうかな? もし、そうならコンパイル出来ないのは当たり前…、こうしなくちゃ」

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と置き換え? あっホント色変わった、これスッゴク便利」
広海:「オレは万能細胞よりか、万能財布の方がイイけどね」
真琴:「万能財布? ナニそれ」
広海:「いくら使ってもぉ、中のカネが減らないのが万能財布、…そんなの欲しいよなぁ」
春子:「さッすが、ヒロミくんらしい発想、…スゴイわ」
広海:「だよね、ネネッ、みんなもソウ思うよね」
真琴:「あのねェ、それって、誉められてるんじゃなくて…」


moru  2008-02-19 17:20:13  No: 29248

万能財布さん、ありがとうございました。
>type
>  TDBGrid = class(DBGrids.TDBGrid)
まさにこの部分をどう記述すれば良いのか分かりませんでした。

CreateClone()については、下のサイトでも拝見させていただいていて、万能財布さんのソース含めこれから試してみたいと思います。
http://www.geocities.jp/asumaroyuumaro/program/tips/replacecompo.html


moru  2008-02-19 17:21:13  No: 29249

そういえば、便乗質問失礼しました。


KHE00221  2008-02-19 18:43:54  No: 29250

TDBGrid = class(DBGrids.TDBGrid)
  public
   procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); override;
  end;

を  TForm1 = class(TForm) の前に配置すれば Clone は不要

ただし全ての TDBGrid が変更されるけど

個別にしたい場合には Clone を作らないと駄目だけど


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加