Delphi TGridPanelの比率制御|BeginUpdateで行列サイズを固定するカレンダーUI実装例
DelphiのTGridPanelを使うとコンポーネントをグリッド上に並べて配置することが出来ますが、
行や列の比率を思い通りに設定したい場合は、RowCollection / ColumnCollection に対して BeginUpdate() / EndUpdate() を使う必要があります。
これを使わないと、行列のサイズが自動調整されてしまい、意図したレイアウトが崩れてしまいます。
この記事では、TGridPanelの構造制御の基本と、比率固定の実例としてカレンダーUIを作成する手順を紹介します。
TGridPanel.RowCollection.BeginUpdate(); //グリッドパネルに行を追加 //グリッドパネルの行の高さの割合を設定 TGridPanel.RowCollection.EndUpdate();
TGridPanel.ColumnCollection.BeginUpdate(); //グリッドパネルに列を追加 //グリッドパネルの列の幅の割合を設定 TGridPanel.ColumnCollection.EndUpdate();
プロジェクトの作成と画面設計
Delphiを起動し、メニューから「ファイル」⇒「新規作成」⇒
「Windows VCLアプリケーション -Delphi(W)」をクリックしてプロジェクトを作成します。
「TPanel」と「TGridPanel」をフォームにドラッグ&ドロップします。
Panel1の上に「TComboBox」を2個ドラッグ&ドロップします。
ソースコードの記述
「コード」モードに切り替えて(F12を押す)、以下ソースコードをドラッグ&ドロップして貼り付けます。
「デザイン」モードに切り替えて(F12を押す)、左下ペインの「オブジェクト インスペクタ」を「イベント」タブに切り替えて以下の設定を行います。
- Form1.OnCreate に FormCreate を設定します。
- ComboBox1.OnChange に ComboBox1Change を設定します。
- ComboBox2.OnChange に ComboBox1Change を設定します。
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
Vcl.ExtCtrls, Vcl.StdCtrls, DateUtils, Vcl.Buttons;
type
TForm1 = class(TForm)
GridPanel1: TGridPanel;
Panel1: TPanel;
ComboBox1: TComboBox;
ComboBox2: TComboBox;
procedure FormCreate(Sender: TObject);
procedure ComboBox1Change(Sender: TObject);
private
{ Private 宣言 }
procedure CreateCalendar(GPanel:TGridPanel; y,m:Integer);
procedure SpeedButtonClick(Sender:TObject);
public
{ Public 宣言 }
end;
var
Form1: TForm1;
const Weeks:array[0..6] of String=
('日','月','火','水','木','金','土');
implementation
{$R *.dfm}
procedure TForm1.SpeedButtonClick(Sender: TObject);
var d:TDateTime;
begin
if Sender is TSpeedButton then
begin
d:=TDateTime(TSpeedButton(Sender).Tag);
ShowMessage(FormatDateTime('yyyy/mm/dd',d));
end;
end;
procedure TForm1.ComboBox1Change(Sender: TObject);
begin
CreateCalendar(
GridPanel1,
StrToInt(ComboBox1.Items[ComboBox1.ItemIndex]),
StrToInt(ComboBox2.Items[ComboBox2.ItemIndex])
);
end;
procedure TForm1.CreateCalendar(GPanel:TGridPanel; y,m:Integer);
var StartDate, EndDate, PreviousDate, NextDate, GPDate:TDateTime;
SButton:TSpeedButton;
Lbl:TLabel;
ColumnItem:TColumnItem;
RowItem:TRowItem;
DayCount, RowCount, Row,Col:Integer;
begin
//グリッドパネル上のコントロールを破棄
while GPanel.ControlCount>0 do GPanel.Controls[0].Free;
//年月の最初の日
StartDate:=EncodeDate(y,m,1);
//年月の最後の日
EndDate:=EndOfAMonth(y,m);
//カレンダーには日曜日から表示するので前月日付
PreviousDate:=StartDate-(DayOfTheWeek(StartDate) Mod 7);
//カレンダーには土曜日まで表示するので次月日付
NextDate:=EndOfAMonth(y,m)+(6-(DayOfTheWeek(EndDate) mod 7));
//グリッドパネル上に表示する総日数
DayCount:=trunc(NextDate-PreviousDate+1);
//行数(上部に曜日を表示するので+1する)
RowCount:=DayCount div 7 + 1;
//グリッドパネルのグリッドをクリア
GPanel.ColumnCollection.Clear;
GPanel.RowCollection.Clear;
//グリッドパネルに行を追加
GPanel.RowCollection.BeginUpdate();
for Row := 0 to RowCount-1 do
begin
RowItem:=GPanel.RowCollection.Add();
RowItem.SizeStyle:=TSizeStyle.ssPercent;
RowItem.Value:=100/RowCount;
end;
GPanel.RowCollection.EndUpdate();
//グリッドパネルに列を追加
GPanel.ColumnCollection.BeginUpdate();
for Col := 0 to 6 do
begin
ColumnItem:=GPanel.ColumnCollection.Add();
ColumnItem.SizeStyle:=TSizeStyle.ssPercent;
ColumnItem.Value:=100/7;
end;
GPanel.ColumnCollection.EndUpdate();
//TLabelで曜日をグリッドに配置
for Col := 0 to 6 do
begin
Lbl:=TLabel.Create(GPanel);
Lbl.Parent:=GPanel;
Lbl.Align:=alClient;
Lbl.Layout:=tlCenter;
Lbl.Caption:=Weeks[Col];
Lbl.Alignment:=taCenter;
Lbl.Font.Size:=12;
if Col=0 then Lbl.Font.Color:=clRed;
if Col=6 then Lbl.Font.Color:=clBlue;
GPanel.ControlCollection.AddControl(Lbl, Col, 0);
end;
//TButtonで日付のボタンを配置
GPDate:=PreviousDate;
for Row:=1 to RowCount-1 do
begin
for Col := 0 to 6 do
begin
SButton:=TSpeedButton.Create(GPanel);
SButton.Parent:=GPanel;
SButton.Align:=alClient;
SButton.Caption:=FormatDateTime('d', GPDate);
SButton.Tag:=Trunc(GPDate);//年月日を入れておく
SButton.StyleElements:=[seBorder];
SButton.Font.Size:=12;
SButton.OnClick:=SpeedButtonClick;
SButton.Font.Color:=clBlack;
if MonthOf(GPDate)<>m then
SButton.Font.Color:=clGray;
if GPDate=Date() then
begin
SButton.Font.Color:=clRed;
SButton.Font.Style:=[TFontStyle.fsBold];
end;
GPanel.ControlCollection.AddControl(SButton, Col, Row);
GPDate:=GPDate+1;
end;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var y, m, i:Integer;
begin
Panel1.Align:=alTop;
Panel1.Caption:='';
GridPanel1.Align:=alCLient;
GridPanel1.Caption:='';
//現在の年月を取得
y:=YearOf(Date());
m:=MonthOf(Date());
//前後10年分の値を設定
ComboBox1.Clear;
ComboBox1.Style:=csDropDownList;
for i := y-10 to y+10 do
begin
ComboBox1.Items.Add(IntToStr(i));
if i=y then
ComboBox1.ItemIndex:=ComboBox1.Items.Count-1;
end;
//月の設定
ComboBox2.Clear;
ComboBox2.Style:=csDropDownList;
for i := 1 to 12 do
begin
ComboBox2.Items.Add(IntToStr(i));
if i=m then
ComboBox2.ItemIndex:=ComboBox2.Items.Count-1;
end;
//カレンダーを表示する
CreateCalendar(
GridPanel1,
StrToInt(ComboBox1.Items[ComboBox1.ItemIndex]),
StrToInt(ComboBox2.Items[ComboBox2.ItemIndex])
);
end;
end.
実行する
メニューから「実行」⇒「実行」をクリックするとコンパイルと実行が行われ、カレンダーが表示されます。
ComboBox1の年やComboBox2の月を変更すると、カレンダーが切り替わります。
日付のボタンを押すと年月日がモーダルウィンドウで表示されます。
