たくさんの動的コンポーネント表示

解決


Syake  2005-07-12 00:57:25  No: 16281

皆様、こんにちは。
お知恵を拝借できれば幸いです。

var
  Form1: TForm1;
   arrEdt :array[0..499] of TEdit;
implementation
{$R *.dfm}

procedure TForm1.SetArrEdit(intType :Integer);
var
   i,intC,intR : Integer;
begin
   //適当に
   Panel1.Visible := False;
   for i := 0 to 499 do
   begin
      arrEdt[i].Width := 40;
      arrEdt[i].Height := 20;
      arrEdt[i].Parent := Panel1;
      if intType = 1 then
      begin
         if (i mod 2) = 0 then
         begin
            arrEdt[i].Visible := False;
         end else begin
            arrEdt[i].Visible := True;
         end;
      end else begin
         if (i mod 2) = 0 then
         begin
            arrEdt[i].Visible := True;
         end else begin
            arrEdt[i].Visible := False;
         end;
      end;
   end;
   intC := 0;
   intR := 0;
   for i := 0 to 499 do
   begin
      if intC = 20 then
      begin
         intC := 0;
         intR := intR + 1;
      end;
      arrEdt[i].Left := (intC * 40) + 8;
      arrEdt[i].Top := (intR * 20) + 8;
      intC := intC + 1;
   end;
   Panel1.Visible := True;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
   i :Integer;
begin
   for i := 0 to 499 do
   begin
      arrEdt[i] := TEdit.Create(Self);
   end
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
   i :Integer;
begin
   for i := 0 to 499 do
   begin
      arrEdt[i].Free;
   end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
   SetArrEdit(1);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
   SetArrEdit(2);
end;

で、Buton1とButon2の押し変え時にはPanelが一瞬消えて
から、ちょっとブランクがあって表示される感じになって
どうも、面白くありません。

で、StringGridでつかった
SendMessage(StringGrid1.Handle, WM_SETREDRAW, 0, 0);
・・・大量のデータ処理
SendMessage(StringGrid1.Handle, WM_SETREDRAW, 1, 0);
StringGrid1.Refresh;
みたに、消えてからまた再表示ではなく、処理後にぱっと
切り替わる具合には、ならんものかなと思ってます。

何か、良い方法はないものでしょうか?


Sayke  URL  2005-07-12 01:02:24  No: 16282

Panel1.Visible := False;
・・・
Panel1.Visible := True;
をしてるので、一瞬消えるのは当たり前で
これは、苦し紛れです。

なんとか、一気に描画されたような雰囲気に
ならんものかなと・・・・


一案  2005-07-12 02:08:28  No: 16283

1枚のPanel上ですべてのEditの表示を切り換えるのではなくて、
2枚のPanel上に偶数番、奇数番のEditを乗せて、2枚のパネルの
Visibleプロパティを切り換えたらどうかな…?
(EditのVisibleはすべてTrue。2枚のPanelは同じ位置)


いや〜  2005-07-12 02:18:04  No: 16284

500個も Edit 作ってる時点で回答書く気なくす


Syake  2005-07-12 02:46:06  No: 16285

ありがとうございます。

一案さん  すいません。<m(__)m>
先程、記した記述は一例で、再現しやすくする為です。
ので、実際は異なります。

Edit500個は無謀ですか?
極端な例だったかもしれませんでしたが、実際は192個です。
最も、EditだけではなくImageもShapeも少々乗せてます。
現状の手作業をプログラミングする過程で、手作業で利用
されている書式(検査票)と似せた形の入力形態及び表示形
式がすんなりするかななどと、考えた結果です。

目的や使用するタイミングはほぼ同一ですが、内容によって
若干入力形態(書式)が異なるため、実際に表示する個数や位
置を変えています。
それを切り替える時点での内容でした。


ひんと  2005-07-12 03:07:30  No: 16286

StringGrid は何百個も Cell があっても InplaceEdit はひとつだけ。
一度にひとつしか編集できないのだからひとつで十分


Basser  2005-07-12 03:21:34  No: 16287

>Panel1.Visible := False;
>・・・
>Panel1.Visible := True;
>をしてるので、一瞬消えるのは当たり前で
>これは、苦し紛れです。

上記の部分を以下のようにしてみてはどうでしょうか?

 LockWindowUpdate(Panel1.Handle)
 ・・・
 LockWindowUpdate(0);


メラトニン  2005-07-12 04:34:26  No: 16288

既出ですが、
環境が限られたPCで使うのを前提としても、
ウィンドウ(TEdit)を必要な数だけ作った時点で、
高速な切り替えは不可能だと思います。
もちろん、GUIアプリケーションの作成方法としては無作法ですし、
コーディングとしては手抜きと判断されても仕方ないと思います。
フォーカスを持つTEditだけを作成して、後は自力で描画した方が良いのではないでしょうか?


Syake  2005-07-12 05:00:36  No: 16289

皆様いろいろ、ありがとうございます。

確かに無作法で横着しとりました。
>フォーカスを持つTEditだけを作成して、後は自力で描画した方が良いのではないでしょうか?
これは、考えなかったわけではないのですが・・・
いやいや、おっしゃられる通りです。
もう一度見直します。
ありがとうございました。


メラトニン  2005-07-12 05:56:06  No: 16290

ちょっと面白そうなのでコンポーネント化挑戦してみます。


メラトニン  URL  2005-07-12 09:40:22  No: 16291

完成しました。
4時間か…結構かかりました。
http://www.studio-fe.hiroishi.org/files/VirtualEdites.zip
とりあえずでかいのでzipファイルを置いておきます。
リンク先の保障はないので、だらだらソースを掲載させていただきます。
そのうちDelphianWorldにでも投稿しておきます。


メラトニン  2005-07-12 09:41:39  No: 16292

//HVirtualEdites.pas

unit HVirtualEdites;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  StdCtrls, //for TEdit
  Themes    //for Xp Style
  ;

type
  //仮想Edit情報
  PVirtualEdit = ^TVirtualEdit;
  TVirtualEdit = record
    EditRect   : TRect;
    Text       : string;
    Visible    : boolean;
  end;

  TVirtualEdites = class(TCustomControl)
  private
    bufBmp   : TBitmap;
    EditList : TList;
    FColor   : TColor;
    FUpdate  : boolean;

    FFocusEdit      : TEdit;
    FFocusEditIndex : Integer;
    FFocusEditChanged: boolean;
    function InTheRect(X,Y:integer; ERect:TRect):boolean;
    function GetEditText(Index: integer): String;
    function GetEditHeight(Index: integer): Integer;
    function GetEditWidth(Index: integer): Integer;
    function GetEditLeft(Index: integer): Integer;
    function GetEditTop(Index: integer): Integer;
    function GetEditVisible(Index: integer): boolean;

    procedure ClearEdit;
    procedure EditChange(Sender:TObject);
    procedure EditExit(Sender:TObject);

    procedure Draw; //全体を描く
    procedure DrawEditRect(ERect:TRect);
    procedure DrawVirtualEdit(Index:integer);
    procedure SetColor(const Value: TColor);
    procedure SetEditText(Index: integer; const Value: String);
    procedure SetEditHeight(Index: integer; const Value: Integer);
    procedure SetEditWidht(Index: integer; const Value: Integer);
    procedure SetEditLeft(Index: integer; const Value: Integer);
    procedure SetEditTop(Index: integer; const Value: Integer);
    procedure SetEditVisible(Index: integer; const Value: boolean);
    procedure ShowFocusEdit; //フォーカスのあるEditを実体化

    procedure WMEraseBkGnd (var Msg: TMessage);       message WM_ERASEBKGND;
    procedure WMLButtonDown(var Msg: TWMLButtonDown); message WM_LBUTTONDOWN;
    procedure WMMouseMove  (var Msg: TWMMouseMove);   message WM_MOUSEMOVE;
    function GetFocusEditText: String;
    procedure SetFocusEditText(const Value: String);
  protected
    procedure Paint; override;
    procedure Resize; override;
  public
    procedure Add(VEdit:TVirtualEdit);
    procedure BeginUpdate;
    procedure Delete(Index:integer);
    procedure EndUpdate;

    constructor Create(AOwner: TComponent); override;
    destructor  Destroy;                    override;

    property Color      : TColor read FColor     write SetColor;
    property EditText   [Index:integer]: String  read GetEditText    write SetEditText;
    property EditTop    [Index:integer]: Integer read GetEditTop     write SetEditTop;
    property EditLeft   [Index:integer]: Integer read GetEditLeft    write SetEditLeft;
    property EditHeight [Index:integer]: Integer read GetEditHeight  write SetEditHeight;
    property EditWidth  [Index:integer]: Integer read GetEditWidth   write SetEditWidht;
    property EditVisible[Index:integer]: boolean read GetEditVisible write SetEditVisible;
    property FocusedEditIndex          : Integer read FFocusEditIndex write FFocusEditIndex;
    property FocusedEditText           : String  read GetFocusEditText write SetFocusEditText;
  end;

implementation

uses Types;

{ TVirtualEdites }

procedure TVirtualEdites.Add(VEdit:TVirtualEdit);
//Edit追加
var
  PEdit:PVirtualEdit;
begin
  New(PEdit);
  PEdit.EditRect:=VEdit.EditRect;
  PEdit.Text    :=VEdit.Text;
  PEdit.Visible :=VEdit.Visible;

  EditList.Add(PEdit);

  FFocusEditIndex:=EditList.Count-1; //追加されたEditにフォーカスIndexを与える

  //再描画
  Draw;
  Repaint;
end;

procedure TVirtualEdites.BeginUpdate;
begin
  FUpdate:=True;
end;

procedure TVirtualEdites.ClearEdit;
//Editを一括クリア
var
  i:integer;
begin
  for i:= EditList.Count-1 downto 0 do
    Delete(I);
end;

constructor TVirtualEdites.Create(AOwner: TComponent);
begin
  inherited;
  FColor  :=clBtnFace;
  FUpdate :=False;

  bufBmp  :=TBitmap.Create;
  EditList:=TList.Create;

  FFocusEditIndex:=-1;
  FFocusEdit:= TEdit.Create(self);
  FFocusEdit.Hide;
  FFocusEdit.Parent :=Self;
  FFocusEdit.OnChange:=EditChange;
  FFocusEdit.OnExit  :=EditExit;
end;

procedure TVirtualEdites.Delete(Index: integer);
//Edit削除
var
  VEdit:PVirtualEdit;
begin
  VEdit := EditList.Items[Index];
  Dispose(VEdit);
  EditList.Delete(Index);
end;

destructor TVirtualEdites.Destroy;
begin
  ClearEdit;     //中身を消去
  EditList.Free; //開放
  inherited;
end;

procedure TVirtualEdites.Draw;
var
  i:integer;
begin
if FUpdate=True then exit;
  bufBmp.Canvas.Font.Assign(Font);
  bufBmp.Canvas.Pen.Color:= FColor;
  bufBmp.Canvas.Brush.Color:= FColor;
  bufBmp.Canvas.Rectangle(0,0,bufBmp.Width,bufBmp.Height);
  for i:= 0 to EditList.Count-1 do
    DrawVirtualEdit(i);
end;

procedure TVirtualEdites.DrawEditRect(ERect: TRect);
var
  thDetails: TThemedElementDetails;
begin
  ERect.Bottom:= ERect.Top + FFocusEdit.Height; //わざと入れてます嫌ならコメントアウト

  if ThemeServices.ThemesEnabled then
  begin
    thDetails := ThemeServices.GetElementDetails(TThemedEdit(3));
    //ERect     := ThemeServices.ContentRect(bufBmp.Canvas.Handle, thDetails,ERect);
    ThemeServices.DrawElement(bufBmp.Canvas.Handle, thDetails, ERect);
  end else begin
    bufBmp.Canvas.Brush.Color:=clWindow;
    bufBmp.Canvas.Rectangle(ERect);
    DrawEdge(bufBmp.Canvas.Handle,ERect,EDGE_SUNKEN,BF_RECT); //EDGE_ETCHED EDGE_BUMP
  end;
end;

procedure TVirtualEdites.DrawVirtualEdit(Index:integer);
var
  Text : string;
  ERect: TRect;
begin
if PVirtualEdit(EditList.Items[Index]).Visible=False then exit;
if (PVirtualEdit(EditList.Items[Index]).EditRect.Left > Width) or
   (PVirtualEdit(EditList.Items[Index]).EditRect.Top  > Height) then
   exit; //余計な描画はしない

  DrawEditRect(PVirtualEdit(EditList.Items[Index]).EditRect);
  //文字を描く
  Text := PVirtualEdit(EditList.Items[Index]).Text;
  ERect:= PVirtualEdit(EditList.Items[Index]).EditRect;
  //ちょっと無理があるかも…
    ERect.Top  := ERect.Top  + 3;
    ERect.Left := ERect.Left + 3;
    ERect.Bottom := ERect.Top + FFocusEdit.Height;
  bufBmp.Canvas.Brush.Color:=clWindow;
  DrawText(bufBmp.Canvas.Handle,PChar(Text),Length(Text), ERect, DT_LEFT);
end;

procedure TVirtualEdites.EditChange(Sender: TObject);
begin
  PVirtualEdit(EditList.Items[FFocusEditIndex]).Text:= FFocusEdit.Text;
  FFocusEditChanged:=True;
end;

procedure TVirtualEdites.EditExit(Sender: TObject);
begin
  if FFocusEditChanged=True then
    Draw;
  FFocusEdit.Hide;
  FFocusEditChanged:=False;
end;

procedure TVirtualEdites.EndUpdate;
begin
  FUpdate:=False;
  Draw;
  Repaint;
end;

function TVirtualEdites.GetEditHeight(Index: integer): Integer;
begin
  Result:=  PVirtualEdit(EditList.Items[Index]).EditRect.Bottom -
            PVirtualEdit(EditList.Items[Index]).EditRect.Top;
end;

function TVirtualEdites.GetEditLeft(Index: integer): Integer;
begin
  Result:=  PVirtualEdit(EditList.Items[Index]).EditRect.Left;
end;

function TVirtualEdites.GetEditText(Index: integer): String;
begin
  Result:= PVirtualEdit(EditList.Items[Index]).Text;
end;

function TVirtualEdites.GetEditTop(Index: integer): Integer;
begin
  Result:=  PVirtualEdit(EditList.Items[Index]).EditRect.Top;
end;

function TVirtualEdites.GetEditVisible(Index: integer): boolean;
begin
  Result:=  PVirtualEdit(EditList.Items[Index]).Visible;
end;

function TVirtualEdites.GetEditWidth(Index: integer): Integer;
begin
  Result:=  PVirtualEdit(EditList.Items[Index]).EditRect.Right -
            PVirtualEdit(EditList.Items[Index]).EditRect.Left;
end;

function TVirtualEdites.GetFocusEditText: String;
begin
  Result:=GetEditText(FFocusEditIndex);
end;

function TVirtualEdites.InTheRect(X, Y: integer; ERect: TRect): boolean;
begin
  if (X >= ERect.Left)   and
     (X <= ERect.Right)  and
     (Y >= ERect.Top)    and
     (Y <= ERect.Top + FFocusEdit.Height ) then   //TEditの仕様にあわせる
     //(Y <= ERect.Bottom) then
     Result:=True
     else
     Result:=False;
end;

procedure TVirtualEdites.Paint;
begin
if FUpdate=True then exit;
  inherited;
  if bufBmp<>nil then
    Canvas.Draw(0,0,bufBmp);
end;

procedure TVirtualEdites.Resize;
begin
  inherited;
  if bufBmp<>nil then
  begin
    bufBmp.Height:=Height;
    bufBmp.Width :=Width;
    Draw;
  end;
end;

procedure TVirtualEdites.SetColor(const Value: TColor);
begin
  if FColor <> Value then
  begin
    FColor := Value;
    Draw;
    Repaint;
  end;
end;

procedure TVirtualEdites.SetEditHeight(Index: integer;
  const Value: Integer);
begin
if PVirtualEdit(EditList.Items[Index]).EditRect.Bottom -
  PVirtualEdit(EditList.Items[Index]).EditRect.Top <> Value then
  begin
    PVirtualEdit(EditList.Items[Index]).EditRect.Bottom:=
      PVirtualEdit(EditList.Items[Index]).EditRect.Top +
      Value;
    Draw;
    Repaint;
  end;
end;

procedure TVirtualEdites.SetEditLeft(Index: integer; const Value: Integer);
var
  i:Integer;
begin
  i:= PVirtualEdit(EditList.Items[Index]).EditRect.Right -
      PVirtualEdit(EditList.Items[Index]).EditRect.Left;
  if i<>Value then
  begin
    PVirtualEdit(EditList.Items[Index]).EditRect.Left    :=Value;
    PVirtualEdit(EditList.Items[Index]).EditRect.Right   :=Value + i;
    Draw;
    Repaint;
  end;
end;

procedure TVirtualEdites.SetEditText(Index: integer; const Value: String);
begin
  if PVirtualEdit(EditList.Items[Index]).Text<>Value then
  begin
    PVirtualEdit(EditList.Items[Index]).Text:=Value;
    Draw;
    Repaint;
  end;
end;

procedure TVirtualEdites.SetEditTop(Index: integer; const Value: Integer);
var
  i:Integer;
begin
  i:= PVirtualEdit(EditList.Items[Index]).EditRect.Bottom -
      PVirtualEdit(EditList.Items[Index]).EditRect.Top;
  if i<>Value then
  begin
    PVirtualEdit(EditList.Items[Index]).EditRect.Top    :=Value;
    PVirtualEdit(EditList.Items[Index]).EditRect.Bottom :=Value + i;
    Draw;
    Repaint;
  end;
end;

procedure TVirtualEdites.SetEditVisible(Index: integer;
  const Value: boolean);
begin
  if PVirtualEdit(EditList.Items[Index]).Visible  <>  Value then
  begin
    PVirtualEdit(EditList.Items[Index]).Visible    :=Value;
    Draw;
    Repaint;
  end;
end;

procedure TVirtualEdites.SetEditWidht(Index: integer;
  const Value: Integer);
begin
if  PVirtualEdit(EditList.Items[Index]).EditRect.Right<>
    PVirtualEdit(EditList.Items[Index]).EditRect.Left +
    Value
  then
  begin
    PVirtualEdit(EditList.Items[Index]).EditRect.Right:=
      PVirtualEdit(EditList.Items[Index]).EditRect.Left +
      Value;
    Draw;
    Repaint;
  end;
end;

procedure TVirtualEdites.SetFocusEditText(const Value: String);
begin
  SetEditText(FFocusEditIndex,Value);
end;

procedure TVirtualEdites.ShowFocusEdit;
var
  ERect:TRect;
begin
  if FFocusEditChanged=True then
    Draw;

  FFocusEdit.Hide;

  if (FFocusEditIndex < 0) or
     (FFocusEditIndex > EditList.Count-1) then
     begin
       exit;
     end;
  ERect:=PVirtualEdit(EditList.Items[FFocusEditIndex]).EditRect;

  //わざと高さ制限を設けています
  FFocusEdit.SetBounds( ERect.Left,
                        ERect.Top,
                        ERect.Right  - ERect.Left,
                        FFocusEdit.Height);
  FFocusEdit.Text := PVirtualEdit(EditList.Items[FFocusEditIndex]).Text;
  FFocusEdit.Show;
  FFocusEdit.SetFocus;

  FFocusEditChanged:=False;
end;

procedure TVirtualEdites.WMEraseBkGnd(var Msg: TMessage);
begin
  Msg.Result:=0;
end;

procedure TVirtualEdites.WMLButtonDown(var Msg: TWMLButtonDown);
var
  i:Integer;
begin
  inherited;
  //フォーカスを作る
  for i:=EditList.Count-1 downto 0 do
  begin
    if InTheRect(Msg.XPos,Msg.YPos,PVirtualEdit(EditList.Items[i]).EditRect) = True then
    begin
      if PVirtualEdit(EditList.Items[i]).Visible=True then
      begin
        FFocusEditIndex:=i;
        ShowFocusEdit;
        exit; //その場で抜ける
      end;
    end;
  end;
end;

procedure TVirtualEdites.WMMouseMove(var Msg: TWMMouseMove);
var
  i:Integer;
begin
  inherited;
  //カーソル処理
  for i:=EditList.Count-1 downto 0 do
  begin
    if InTheRect(Msg.XPos,Msg.YPos,PVirtualEdit(EditList.Items[i]).EditRect) = True then
    begin
      Cursor:= crIBeam;
      exit; //その場で抜ける
    end;
  end;
  Cursor:=crDefault;
end;

end.


メラトニン  2005-07-12 09:42:21  No: 16293

//使い方(サンプル)
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls,
  HVirtualEdites;  //これ追加 HVirtualEdites.pas

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Panel1: TPanel;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private 宣言 }
    VirtualEdites1 : TVirtualEdites;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var i,p:integer;
    VEdit:TVirtualEdit;
begin
  VirtualEdites1:=TVirtualEdites.Create(self);
  VirtualEdites1.Parent:=Panel1;
  VirtualEdites1.Align:=alClient;
  VirtualEdites1.BeginUpdate;
  for i:=0 to 4 do
    for p:= 0 to 100 do
    begin
      VEdit.Text    := 'Edit'+ IntToStr(i*100+p);
      VEdit.Visible := True;
      VEdit.EditRect:= Rect(i*100,p*20,i*100+80,p*20+15);
      VirtualEdites1.Add(VEdit);
    end;
  VirtualEdites1.EndUpdate;
end;

procedure TForm1.Button1Click(Sender: TObject);
var i,p:integer;
begin
  VirtualEdites1.BeginUpdate;
  for i:=0 to 4 do
    for p:= 0 to 100 do
    begin
      if i mod 2 = 0 then
      VirtualEdites1.EditVisible[i*100+p]:=True
      else
      VirtualEdites1.EditVisible[i*100+p]:=False;
    end;
  VirtualEdites1.EndUpdate;
end;

procedure TForm1.Button2Click(Sender: TObject);
var i,p:integer;
begin
  VirtualEdites1.BeginUpdate;
  for i:=0 to 4 do
    for p:= 0 to 100 do
    begin
      if i mod 2 = 0 then
      VirtualEdites1.EditVisible[i*100+p]:=False
      else
      VirtualEdites1.EditVisible[i*100+p]:=True;
    end;
  VirtualEdites1.EndUpdate;
end;

end.


メラトニン  2005-07-12 09:42:58  No: 16294

てゆーか、インターネット探せばありそうな気がしてきました…


Syake  2005-07-12 18:15:47  No: 16295

メラトニンさん
ありがとうございます。
お礼が遅くなりました。
さ〜て、自前で描画作業するか・・・と作業中にふと掲示板を見て気付きました。

う〜む、これは・・・・\(^o^)/
サンプルを実行しましたが、素晴らしいです。
いやいや、お手数をお掛けしてすいませんでした。
まだまだ未熟者ですので大変助かります。
参考にし色々、学習させてもらいます。
ありがとうございました。


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

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






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