-
Кстати, еще одна написанная за час кнопка: unit ArgoMenuButton;
interface
uses
Classes, Graphics, Buttons;
type
TArgoMenuButton = class(TSpeedButton)
private
FStartColor: TColor;
FEndColor: TColor;
FUseGradientFill: Boolean;
procedure SetEndColor(const Value: TColor);
procedure SetGradientFill(const Value: Boolean);
procedure SetStartColor(const Value: TColor);
protected
procedure Paint; override;
public
procedure Assign(Source: TPersistent); override;
published
property StartColor: TColor read FStartColor write SetStartColor;
property EndColor: TColor read FEndColor write SetEndColor;
property UseGradientFill: Boolean read FUseGradientFill
write SetGradientFill;
end;
implementation
uses
Windows, HSGradient;
procedure CalcButtonLayout(Canvas: TCanvas; const Client: TRect;
const Offset: TPoint; const Caption: string; Layout: TButtonLayout; Margin,
Spacing: Integer; var GlyphPos: TPoint; var TextBounds: TRect;
BiDiFlags: LongInt);
var
TextPos: TPoint;
ClientSize, GlyphSize, TextSize: TPoint;
TotalSize: TPoint;
begin
if (BiDiFlags and DT_RIGHT) = DT_RIGHT then
if Layout = blGlyphLeft then Layout := blGlyphRight
else
if Layout = blGlyphRight then Layout := blGlyphLeft;
ClientSize := Point(Client.Right - Client.Left, Client.Bottom -
Client.Top);
GlyphSize := Point(0, 0);
if Length(Caption) > 0 then
begin
TextBounds := Rect(0, 0, Client.Right - Client.Left, 0);
DrawText(Canvas.Handle, PChar(Caption), Length(Caption), TextBounds,
DT_CALCRECT or BiDiFlags);
TextSize := Point(TextBounds.Right - TextBounds.Left, TextBounds.Bottom -
TextBounds.Top);
end
else
begin
TextBounds := Rect(0, 0, 0, 0);
TextSize := Point(0,0);
end;
if Layout in [blGlyphLeft, blGlyphRight] then
begin
GlyphPos.Y := (ClientSize.Y - GlyphSize.Y + 1) div 2;
TextPos.Y := (ClientSize.Y - TextSize.Y + 1) div 2;
end
else
begin
GlyphPos.X := (ClientSize.X - GlyphSize.X + 1) div 2;
TextPos.X := (ClientSize.X - TextSize.X + 1) div 2;
end;
if (TextSize.X = 0) or (GlyphSize.X = 0) then
Spacing := 0;
if Margin = -1 then
begin
if Spacing < 0 then
begin
TotalSize := Point(GlyphSize.X + TextSize.X, GlyphSize.Y + TextSize.Y);
if Layout in [blGlyphLeft, blGlyphRight] then
Margin := (ClientSize.X - TotalSize.X) div 3
else
Margin := (ClientSize.Y - TotalSize.Y) div 3;
Spacing := Margin;
end
else
begin
TotalSize := Point(GlyphSize.X + Spacing + TextSize.X, GlyphSize.Y +
Spacing + TextSize.Y);
if Layout in [blGlyphLeft, blGlyphRight] then
Margin := (ClientSize.X - TotalSize.X + 1) div 2
else
Margin := (ClientSize.Y - TotalSize.Y + 1) div 2;
end;
end
else
begin
if Spacing < 0 then
begin
TotalSize := Point(ClientSize.X - (Margin + GlyphSize.X), ClientSize.Y -
(Margin + GlyphSize.Y));
if Layout in [blGlyphLeft, blGlyphRight] then
Spacing := (TotalSize.X - TextSize.X) div 2
else
Spacing := (TotalSize.Y - TextSize.Y) div 2;
end;
end;
case Layout of
blGlyphLeft:
begin
GlyphPos.X := Margin;
TextPos.X := GlyphPos.X + GlyphSize.X + Spacing;
end;
blGlyphRight:
begin
GlyphPos.X := ClientSize.X - Margin - GlyphSize.X;
TextPos.X := GlyphPos.X - Spacing - TextSize.X;
end;
blGlyphTop:
begin
GlyphPos.Y := Margin;
TextPos.Y := GlyphPos.Y + GlyphSize.Y + Spacing;
end;
blGlyphBottom:
begin
GlyphPos.Y := ClientSize.Y - Margin - GlyphSize.Y;
TextPos.Y := GlyphPos.Y - Spacing - TextSize.Y;
end;
end;
with GlyphPos do
begin
Inc(X, Client.Left + Offset.X);
Inc(Y, Client.Top + Offset.Y);
end;
OffsetRect(TextBounds, TextPos.X + Client.Left + Offset.X, TextPos.Y + Client.Top + Offset.Y);
end;
procedure DrawButtonText(Canvas: TCanvas; const Caption: string;
TextBounds: TRect; State: TButtonState; Flags: LongInt);
begin
with Canvas do
begin
Brush.Style := bsClear;
if State = bsDisabled then
begin
OffsetRect(TextBounds, 1, 1);
Font.Color := clBtnHighlight;
DrawText(Handle, PChar(Caption), Length(Caption), TextBounds,
DT_CENTER or DT_VCENTER or Flags);
OffsetRect(TextBounds, -1, -1);
Font.Color := clBtnShadow;
DrawText(Handle, PChar(Caption), Length(Caption), TextBounds,
DT_CENTER or DT_VCENTER or Flags);
end else
DrawText(Handle, PChar(Caption), Length(Caption), TextBounds,
DT_CENTER or DT_VCENTER or Flags);
end;
end;
function DrawButton (Canvas: TCanvas; const Client: TRect;
const Offset: TPoint; const Caption: string; Layout: TButtonLayout;
Margin, Spacing: Integer; State: TButtonState; Transparent: Boolean;
BiDiFlags: LongInt): TRect;
var
GlyphPos: TPoint;
begin
CalcButtonLayout(Canvas, Client, Offset, Caption, Layout, Margin, Spacing,
GlyphPos, Result, BiDiFlags);
DrawButtonText(Canvas, Caption, Result, State, BiDiFlags);
end;
procedure TArgoMenuButton.Assign(Source: TPersistent);
begin
if Source is TSpeedButton then
begin
BoundsRect := TSpeedButton(Source).BoundsRect;
Action := TSpeedButton(Source).Action;
Flat := TSpeedButton(Source).Flat;
Transparent := TSpeedButton(Source).Transparent;
Font := TSpeedButton(Source).Font;
AllowAllUp := TSpeedButton(Source).AllowAllUp;
end else
inherited;
end;
procedure TArgoMenuButton.Paint;
var
PaintRect: TRect;
GradientFill: THSGradientFill;
begin
if (csDesigning in ComponentState) or not
(Fstate in [bsDown,bsExclusive]) then
inherited
else begin
Canvas.Font := Self.Font;
Canvas.Font.Color := clYellow;
Canvas.Brush.Color := $00804000;
PaintRect := Rect(0, 0, Width, Height);
if UseGradientFill then
begin
GradientFill := THSGradientFill.Create;
try
GradientFill.Style := gsVertical;
GradientFill.StartColor := FStartColor;
GradientFill.EndColor := FEndColor;
GradientFill.FillRect(Canvas, PaintRect);
finally
GradientFill.Free;
end;
end
else
Canvas.FillRect(PaintRect);
DrawButton (Canvas, PaintRect, Point(0,0), Caption, Layout, Margin, Spacing,
FState, Transparent, DrawTextBiDiModeFlags(0));
end;
end;
procedure TArgoMenuButton.SetEndColor(const Value: TColor);
begin
if FEndColor <> Value then
begin
FEndColor := Value;
Invalidate;
end;
end;
procedure TArgoMenuButton.SetGradientFill(const Value: Boolean);
begin
if FUseGradientFill <> Value then
begin
FUseGradientFill := Value;
Invalidate;
end;
end;
procedure TArgoMenuButton.SetStartColor(const Value: TColor);
begin
if FStartColor <> Value then
begin
FStartColor := Value;
Invalidate;
end;
end;
end.
-
> Класс !!! > Проиндексировав картинки можно сокатить код
Класс это в смысле плохо или хорошо?
Что значит проиндексировать?
-
> Что значит проиндексировать?
Класс - это всё написано с толком и расстановкой, без лишних излишеств
Про индексацию я показал в [8], а в [9] полная реализация того о чём я говорил
-
> property ImageHot: TPicture index mbsHot read GetImage write > SetImage;
Вот такая конструкция у меня не захотела компилироваться на D2006
function GetImage (Index: Integer): TBitmap; procedure SetImage (Value: TBitmap; Index: Integer); ... property DisabledImage: TBitmap index 3 read GetImage write SetImage;
-
> Вот такая конструкция у меня не захотела компилироваться > на D2006
Видимо дело в этом: An access method for a property with an index specifier must take an extra value parameter of type Integer. For a read function, it must be the last parameter; for a write procedure, it must be the second-to-last parameter (preceding the parameter that specifies the property value). When a program accesses the property, the property’s integer constant is automatically passed to the access method. Вот что получилось: unit KMultiImageButton;
interface
uses
SysUtils, Classes, Controls, Buttons, Graphics, Types, Messages;
type
TMultiImageButtonStates = (mibsNormal, mibsDown, mibsHover, mibsDisabled);
TKMultiImageButton = class(TGraphicControl)
private
FImages: array [TMultiImageButtonStates] of TPicture;
FButtonState: TMultiImageButtonStates;
protected
function GetImage(const Index: TMultiImageButtonStates): TPicture;
procedure SetImage(const Index: TMultiImageButtonStates; const Value: TPicture);
procedure SetButtonState(const AState: TMultiImageButtonStates);
procedure Paint; override;
procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
procedure MouseDown(Button: TMouseButton;
Shift: TShiftState; X, Y: Integer); override;
procedure MouseUp(Button: TMouseButton;
Shift: TShiftState; X, Y: Integer); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property Caption;
property Action;
property ImageNormal: TPicture index mibsNormal read GetImage write SetImage;
property ImageDisabled: TPicture index mibsDisabled read GetImage write SetImage;
property ImageDown: TPicture index mibsDown read GetImage write SetImage;
property ImageHover: TPicture index mibsHover read GetImage write SetImage;
property OnClick;
property OnDblClick;
property OnMouseDown;
property OnMouseEnter;
property OnMouseLeave;
property OnMouseMove;
property OnMouseUp;
property OnMouseWheel;
property OnMouseWheelDown;
property OnMouseWheelUp;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('KSoftWare', [TKMultiImageButton]);
end;
procedure TKMultiImageButton.CMMouseEnter(var Message: TMessage);
begin
SetButtonState(mibsHover);
end;
procedure TKMultiImageButton.CMMouseLeave(var Message: TMessage);
begin
SetButtonState(mibsNormal);
end;
constructor TKMultiImageButton.Create(AOwner: TComponent);
var
I: TMultiImageButtonStates;
begin
inherited;
for I := Low(TMultiImageButtonStates) to High(TMultiImageButtonStates) do
FImages[I] := TPicture.Create;
end;
destructor TKMultiImageButton.Destroy;
var
I: TMultiImageButtonStates;
begin
for I := Low(TMultiImageButtonStates) to High(TMultiImageButtonStates) do
FImages[I].Free;
inherited;
end;
function TKMultiImageButton.GetImage(const Index: TMultiImageButtonStates): TPicture;
begin
Result := FImages[Index];
end;
procedure TKMultiImageButton.MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
inherited;
SetButtonState(mibsDown);
end;
procedure TKMultiImageButton.MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
inherited;
SetButtonState(mibsNormal);
end;
procedure TKMultiImageButton.Paint;
begin
if csDesigning in ComponentState then
with Canvas do
begin
Pen.Style := psDash;
Brush.Style := bsClear;
Rectangle(0, 0, Width, Height);
end;
Canvas.Font := Self.Font;
with GetImage(FButtonState) do
Canvas.StretchDraw(ClientRect, Graphic);
Canvas.TextOut(0, 0, Caption);
end;
procedure TKMultiImageButton.SetButtonState(
const AState: TMultiImageButtonStates);
begin
if not Enabled then
begin
FButtonState := mibsDisabled;
Exit;
end
else
if FButtonState <> AState then
FButtonState := AState;
Invalidate;
end;
procedure TKMultiImageButton.SetImage(const Index: TMultiImageButtonStates;
const Value: TPicture);
begin
FImages[Index].Assign(Value);
if FButtonState = Index then
Invalidate;
end;
end. Еще с Enable/Disabled не разобрался, а так вроде работает :)
-
А, забыл, как правильно координаты теста вычислять? где подсмотреть?
-
Так Enabled то же победил: procedure TKMultiImageButton.CMEnabledChanged(var Message: TMessage);
begin
if Enabled then
SetButtonState(mibsNormal)
else
SetButtonState(mibsDisabled);
inherited;
end; Нормально? Кроме кординат текста незнаю как сделать его фон прозраным.
-
> Кроме кординат текста незнаю как сделать его фон прозраным.
Ввести свойство Transaparent ?
При рисовании текста сказать Canvas.Brush.Style := bsClear, а потом собстна текст рисовать ?
-
> При рисовании текста сказать Canvas.Brush.Style := bsClear, > а потом собстна текст рисовать ?
Да, получилось.
А что с координатами? Можно конечно текст по центру делать, но интересно понять как делается в кнопке, а я там капался так и не понял :(
-
Кстати DoubleClick работает только ели не назначен просто Click. Наверно надо доп. обработку делать
Опять же где бы посмотреть пример?
-
procedure TKMultiImageButton.CMEnabledChanged(var Message: TMessage);
const AState: array[boolean] of TMultiImageButtonStates = (mibsDisabled,mibsNormal);
begin
inherited;
SetButtonState(AState[Enabled]);
end;
procedure TKMultiImageButton.SetButtonState(AState: TMultiImageButtonStates);
var P: TPoint;
begin
if not Enabled then AState := mibsDisabled;
if fButtonState = AState then Exit;
if FButtonState = mibsDisabled then begin
GetCursorPos(P);
P := ScrennToClient(P);
if PtInRect(P,ClientRect) then
if csLButtonDown in ControlState
then AState := mibsDown
else AState := mibsHover
else AState := mibsNormal;
FButtonState := AState;
Invalidate;
end;
-
> А что с координатами? Можно конечно текст по центру делать, > но интересно понять как делается в кнопке
RTFS: Buttons.pas - там все подробно написано. С картинками
-
DimaBr © (01.04.08 16:40) [30]
> if FButtonState = mibsDisabled then begin > GetCursorPos(P); > P := ScrennToClient(P); > if PtInRect(P,ClientRect) then > if csLButtonDown in ControlState > then AState := mibsDown > else AState := mibsHover > else AState := mibsNormal; > FButtonState := AState; > Invalidate; > end;
Непонятно, зачем при недоступной кнопке менять ее State ?
-
> DimaBr © (01.04.08 16:40)
SetButtonState(AState[Enabled]); Не понял. Это типа если True, то 1, а если False, то 0? Но у меня же (mibsNormal, mibsDown, mibsHover, mibsDisabled); SetButtonState Не понял, зачем манипуляции с координатами курсора?
-
Кстати а при Disabled надо же еще и цвет Caption'a менять? На какой? Или может это сделано где то в предке?
-
> Кстати а при Disabled надо же еще и цвет Caption'a менять? > На какой? Или может это сделано где —то в предке?
Предок у тебя TGraphicControl - он про текст ничего не знает. При рисовании текста проверяй State, в зависимости от него устанавливай Canvas.Font.Color - собственно, в Buttons.pas все это подробно расписано.
-
> С картинками
CalcButtonLayout ? Мне кажется это слишком сложно. Сделал так: ControlMiddle.X := Width div 2;
ControlMiddle.Y := Height div 2;
TextMiddle.X := Canvas.TextWidth(Caption) div 2;
TextMiddle.Y := Canvas.TextHeight(Caption) div 2;
Canvas.Brush.Style := bsClear;
Canvas.TextOut(ControlMiddle.X — TextMiddle.X, ControlMiddle.Y — TextMiddle.Y, Caption); + может Offset добавлю. Глиф мне не нужен и писать задом наперед тоже. Нормально?
-
Если кнопка БЫЛА недоступной и вдруг стала доступной, при этом мышка находится на ней, то она должна быть mibsHover
-
> Если кнопка БЫЛА недоступной и вдруг стала доступной, при > этом мышка находится на ней, то она должна быть mibsHover
Не могу представить ситуацию
-
> [38] Игорь Шевченко © (01.04.08 17:11)
Форма, прогрессбар и кнопка. Идет какой либо процесс (прогрессбар бежит) и одна кнопка Ок, Которая не доступна пока идет процесс, а пользователь мышь держит на ней и ждет.... :о)
|