2015-10-13 28 views
2

我想要创建一个“面板组件”来按住x按钮(实际上不是完全按钮,但您明白了)。关于创建“容器”组件的建议

它看起来像一个扫雷艇,你可以点击任何按钮,每个按钮都有相同的“全局点击”事件。但与发件人和按钮作为参数,如:Sender: TObject; Button: TButton)wherin发件人是面板组件,并按钮面板内的按钮。

到目前为止,我把水平方向的按钮数量和垂直方向的按钮数量分为两个属性。

property ButtonsHeight: Integer read fButtonsHeight write SetButtonsHeight; 
    property ButtonsWidth: Integer read fButtonsWidth write SetButtonsWidth; 

procedure TMultipleDrawPanel.SetButtonsHeight(const Value: Integer); 
begin 
    if Value < 1 then begin 
    raise Exception.Create('Mumarul minim de butoane este 1!'); 
    end; 
    InflateButtonsHeight(fButtonsHeight, Value); 
    fButtonsHeight := Value; 
end; 

而且这是在一个方向按钮的数量变化的伪代码:

procedure TMultipleDrawPanel.InflateButtonsHeight(oldValue, newValue: Integer); 
begin 
    if oldValue < newValue then begin 
    // free extra buttons 
    end else begin 
    // create new buttons 
    end; 
end; 

任何人都可以点我一些建议吗?

  1. 如何存储按钮列表?
  2. 如何在数字从较高值变为较低值时释放按钮? (以及如何创建新的,否则?)
  3. 我相信我需要覆盖resize方法。我有一些想法,但我没有得到那么多。
+2

通常这种事情作为单个组件而不是复合组件更好用 –

+0

使用TGridPanel并将按钮放置在单元格内。 –

+0

tgridpanel不是我所需要的。我在这里公开的“面板组件”只是冰山的顶部。 –

回答

0

是这样的吗?

unit ButtonPanel; 

interface 

uses 
    System.Classes, System.SysUtils, Vcl.Controls, Vcl.StdCtrls, System.Math; 

type 
    TCoord = record 
    Col: Integer; 
    Row: Integer; 
    end; 

    TCustomButtonPanel = class; 

    TButtonClickEvent = procedure(Sender: TCustomButtonPanel; 
    Coord: TCoord) of object; 

    TCustomButtonPanel = class(Vcl.Controls.TWinControl) 
    private 
    FColCount: Integer; 
    FOnClick: TButtonClickEvent; 
    FRowCount: Integer; 
    procedure ButtonClick(Sender: TObject); 
    function CoordFromIndex(Index: Integer): TCoord; 
    function CoordToIndex(Col, Row: Integer): Integer; 
    function GetButton(Col, Row: Integer): TButton; overload; 
    function GetButton(Index: Integer): TButton; overload; 
    function GetButtonCount: Integer; 
    procedure SetColCount(Value: Integer); 
    procedure SetRowCount(Value: Integer); 
    procedure SizeChanged; 
    protected 
    function CanResize(var NewWidth, NewHeight: Integer): Boolean; override; 
    procedure DoClick(Index: Integer); virtual; 
    procedure Resize; override; 
    procedure ValidateInsert(AComponent: TComponent); override; 
    property ButtonCount: Integer read GetButtonCount; 
    property Buttons[Col, Row: Integer]: TButton read GetButton; 
    property ColCount: Integer read FColCount write SetColCount default 5; 
    property OnClick: TButtonClickEvent read FOnClick write FOnClick; 
    property RowCount: Integer read FRowCount write SetRowCount default 5; 
    public 
    constructor Create(AOwner: TComponent); override; 
    end; 

    TButtonPanel = class(TCustomButtonPanel) 
    public 
    property ButtonCount; 
    property Buttons; 
    published 
    property ColCount; 
    property OnClick; 
    property RowCount; 
    end; 

implementation 

type 
    TButtonPanelButton = class(Vcl.StdCtrls.TButton); 

resourcestring 
    SInvalidControlType = 'Invalid control type for ButtonPanel child'; 

function Round(Value, Rounder: Integer): Integer; overload; 
begin 
    if Rounder = 0 then 
    Result := Value 
    else 
    Result := (Value div Rounder) * Rounder; 
end; 

{ TCustomButtonPanel } 

procedure TCustomButtonPanel.ButtonClick(Sender: TObject); 
begin 
    DoClick(TButton(Sender).Tag); 
end; 

function TCustomButtonPanel.CanResize(var NewWidth, NewHeight: Integer): Boolean; 
var 
    EdgeSize: Integer; 
begin 
    Result := inherited CanResize(NewWidth, NewHeight); 
    EdgeSize := 2 * (BorderWidth + BevelWidth); 
    NewWidth := Round(NewWidth - EdgeSize, FColCount) + EdgeSize; 
    NewHeight := Round(NewHeight - EdgeSize, FRowCount) + EdgeSize; 
end; 

function TCustomButtonPanel.CoordFromIndex(Index: Integer): TCoord; 
begin 
    Result.Col := Index mod ColCount; 
    Result.Row := Index div ColCount; 
end; 

function TCustomButtonPanel.CoordToIndex(Col, Row: Integer): Integer; 
begin 
    Result := FColCount * Row + Col; 
end; 

constructor TCustomButtonPanel.Create(AOwner: TComponent); 
begin 
    inherited Create(AOwner); 
    ControlStyle := []; 
    FColCount := 5; 
    FRowCount := 5; 
    SizeChanged; 
end; 

procedure TCustomButtonPanel.DoClick(Index: Integer); 
begin 
    if Assigned(FOnClick) then 
    FOnClick(Self, CoordFromIndex(Index)); 
end; 

function TCustomButtonPanel.GetButton(Col, Row: Integer): TButton; 
begin 
    Result := GetButton(CoordToIndex(Col, Row)); 
end; 

function TCustomButtonPanel.GetButton(Index: Integer): TButton; 
begin 
    Result := TButton(Controls[Index]); 
end; 

function TCustomButtonPanel.GetButtonCount: Integer; 
begin 
    Result := ControlCount; 
end; 

procedure TCustomButtonPanel.Resize; 
var 
    ColWidth: Integer; 
    RowHeight: Integer; 
    Col: Integer; 
    Row: Integer; 
begin 
    inherited Resize; 
    ColWidth := ClientWidth div FColCount; 
    RowHeight := ClientHeight div FRowCount; 
    for Col := 0 to FColCount - 1 do 
    for Row := 0 to FRowCount - 1 do 
     Buttons[Col, Row].SetBounds(Col * ColWidth, Row * RowHeight, ColWidth, 
     RowHeight); 
end; 

procedure TCustomButtonPanel.SetColCount(Value: Integer); 
begin 
    if FColCount <> Value then 
    begin 
    FColCount := Max(1, Value); 
    SizeChanged; 
    end; 
end; 

procedure TCustomButtonPanel.SetRowCount(Value: Integer); 
begin 
    if FRowCount <> Value then 
    begin 
    FRowCount := Max(1, Value); 
    SizeChanged; 
    end; 
end; 

procedure TCustomButtonPanel.SizeChanged; 
var 
    I: Integer; 
    OldCount: Integer; 
    NewCount: Integer; 
    Button: TButton; 
begin 
    OldCount := ButtonCount; 
    NewCount := FColCount * FRowCount; 
    for I := OldCount - 1 downto NewCount do 
    GetButton(I).Free; 
    for I := OldCount to NewCount - 1 do 
    begin 
    Button := TButtonPanelButton.Create(Self); 
    Button.Tag := I; 
    Button.OnClick := ButtonClick; 
    Button.Parent := Self; 
    end; 
    AdjustSize; 
end; 

procedure TCustomButtonPanel.ValidateInsert(AComponent: TComponent); 
begin 
    inherited ValidateInsert(AComponent); 
    if not (AComponent is TButtonPanelButton) then 
    raise EInvalidInsert.Create(SInvalidControlType); 
end; 

end. 

我确信上面的代码提供了大量的学习材料,思考和定制空间。简而言之:

  • 滥用组件的Controls属性伸展其含义的按钮。因此,该控件不允许插入其他类型的控件。参见GetButtonGetButtonCount,ValidateInsert
  • 由于每个按钮具有相同的大小,并且组件完全充满按钮,因此组件的大小限制为按钮大小的倍数。见CanResize
  • 它重新引入了OnClick事件,因为面板自我不会被点击(它已充满按钮)。该事件有一个额外的参数,请参见ButtonClick,DoClick
  • 将2D列 - 行坐标映射到指数的线性阵列,请参阅CoordFromIndex,CoordToIndex
  • 按钮由Tag属性标识,请参阅SizeChanged其中创建按钮。

下一步是用虚拟方法重新设计这个方法,因为没有使用实际的TButton控件,但是按钮只是绘制了模仿。

玩得开心。

+0

tks alot.i获得ideea,我会进一步发展。 –