-
Итак, задача написать свою кнопку-картинку. То есть такая кнопка похожа на TImage, но мы задаем не одну картинку, а несколько (для разных состояний кнопки). В другой моей ветке: http://pda.delphimaster.net/?n=3&id=1206102762DVM дал пример такой кнопки, но там все сделано на основе TBitmap, я хотел бы иметь возможность загружать картинки разных форматов. Требования к кнопке: 1. Возможность задавать разные картинки для разных состояний: Обычная, Не активная, Нажатая, мышь над кнопкой 2. Возможность использоватеь разные форматы картинок из пункта 1. 3. Наличие Caption, которое бы работало так же как и в TButton. 4. Наличие Font. 5. Наличие Action. Тоже должно работать как в обычной кнопке. Вопросы: 1. Кого выбрать родителем? 2. Правильно ли я понял, что если я для картинок буду использовать TPicture, то смогу использовать разные форматы? 3. Action, Caption и Font уже есть у TControl. Если я просто открою к ним доступ, будут лиони работать или придется еще что-то сделать? 4. Код каких компонентов смотреть, в качестве примера? Я например не очень представляю как рисовать картинки, где искать пример? В TImage? 5. Любые замечения. ЗЫ DimaBr пишу свой компонент :).
-
1. Если кнопка будет "реальной", то есть иметь окно (её например можно найти WinAPI и нажать с другого приложения) то родитель TCustomControl, если просто рисунок - TGraphicsControl 2. Правильно, только количество форматов не много (BMP, ICO, EMF, WMF), для изысканных нужно будет подключать библиотеки или свои свои наработки. 3. Action - да, Сарtion & Font - используя их вы будите отрисовывать свой заголовок на кнопке. 4. Например TSpeedButton 5. Замечания Можно не писать кнопку с нуля, а взять готовую и дополнить её. Например, возьмите TSpeedButton, перекройте procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
procedure Paint; override;
-
> для изысканных нужно будет подключать библиотеки или свои > свои наработки.
Я так понял, что, чтобы подключить доп формат (готовый) то нужно просто скачать соотв модуль (например TPNGImage с torry) и в TypeLib прописать путь. После этого он доступен для выбора в диалогах загрузки картинки, так? Я просто не оч. понимаю как этот механизм работает.
1. Если кнопка будет «реальной», то есть иметь окно (её например можно найти WinAPI и нажать с другого приложения) то родитель TCustomControl, если просто рисунок TGraphicsControl Ясно. Наверно окно как раз ненужно.
> Можно не писать кнопку с нуля, а взять готовую и дополнить > её. > Например, возьмите TSpeedButton, перекройте
О, наверно это то, что надо. Я наверно понижу видимость некоторых свойств. Glyph, Flat например. Это оч. плохо? Чем нибудь грозит?
-
Понизить видимость нельзя
-
> Понизить видимость нельзя
Как нельзя? перемещю соотв свойства в protected и все.
-
А зачем нужен FDrawing в Paint у TImage?
-
Я вот думаю, может по аналогии с кодом DVM сделать так: 1. Добавляю поле FCurrentImage: TPicture; 2. Рисование взять из TImage var
Save: Boolean;
begin
if csDesigning in ComponentState then
with inherited Canvas do
begin
Pen.Style := psDash;
Brush.Style := bsClear;
Rectangle(0, 0, Width, Height);
end;
try
with inherited Canvas do
StretchDraw(DestRect, CurrentImage.Graphic);
finally
end;
end; А вот сам это CurrentImage менять при надобности. Только вот где его менять правильно? Или Надо проверять все состояния в Paint и рисовать нужную картинку? И еще. Как выводит Caption? Я что-то в TSpeedButton ненайду. Просто TextOut?
-
Кулибин. Компонентов таких написано море.
-
Код DVM - я бы сказал не очень. Рисовать в MouseUp - извращение. ActualBmp.Assign(Bmp); - тоже не ахти... Моё предложение. Заводим несколько свойства типа TPicture для разных состояний TMyButtoState = (mbsUp, mbsHot, mbsDown, mbsDisabled);
private
fImages: array[TMyButtoState] of TPicture;
property ImageHot: TPicture index mbsHot read GetImage write SetImage;
Заводим переменную - состояние кнопки fButtonState: TMyButtoState;в зависимости от которого в методе PAINT отрисовываем копку с нужного изображение
-
Буквально за час (правда, без Caption) unit HSFlatImageButton;
interface
uses
Messages, Classes, Graphics, Controls;
type
THSButtonState = (hsbsUp, hsbsDown, hsbsHover, hsbsDisabled);
THSFlatImageButton = class(TGraphicControl)
private
FImages: array[THSButtonState] of TBitmap;
FState: THSButtonState;
procedure SetState(const Value: THSButtonState);
function GetImage(const Index: THSButtonState): TBitmap;
procedure SetImage(const Index: THSButtonState; const Value: TBitmap);
function GetDisabledImage: TBitmap;
function GetDownImage: TBitmap;
function GetHoverImage: TBitmap;
function GetUpImage: TBitmap;
procedure SetDisabledImage(const Value: TBitmap);
procedure SetDownImage(const Value: TBitmap);
procedure SetHoverImage(const Value: TBitmap);
procedure SetUpImage(const Value: TBitmap);
protected
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;
property State: THSButtonState read FState write SetState;
property UpImage: TBitmap read GetUpImage write SetUpImage;
property DownImage: TBitmap read GetDownImage write SetDownImage;
property HoverImage: TBitmap read GetHoverImage write SetHoverImage;
property DisabledImage: TBitmap read GetDisabledImage write SetDisabledImage;
property OnClick;
end;
implementation
procedure THSFlatImageButton.CMMouseEnter(var Message: TMessage);
begin
if Enabled then
State := hsbsHover;
end;
procedure THSFlatImageButton.CMMouseLeave(var Message: TMessage);
begin
inherited;
if Enabled then
State := hsbsUp;
end;
constructor THSFlatImageButton.Create(AOwner: TComponent);
var
I: THSButtonState;
begin
inherited;
Height := 16;
Width := 16;
ControlStyle := ControlStyle + [csReplicatable];
FState := hsbsUp;
for I := Low(THSButtonState) to High(THSButtonState) do
begin
FImages[I] := TBitmap.Create;
FImages[I].Height := 16;
FImages[I].Width := 16;
end;
end;
destructor THSFlatImageButton.Destroy;
var
I: THSButtonState;
begin
for I := Low(THSButtonState) to High(THSButtonState) do
FImages[I].Free;
inherited;
end;
function THSFlatImageButton.GetDisabledImage: TBitmap;
begin
Result := GetImage(hsbsDisabled);
end;
function THSFlatImageButton.GetDownImage: TBitmap;
begin
Result := GetImage(hsbsDown);
end;
function THSFlatImageButton.GetHoverImage: TBitmap;
begin
Result := GetImage(hsbsHover);
end;
function THSFlatImageButton.GetImage(const Index: THSButtonState): TBitmap;
begin
Result := FImages[Index];
end;
function THSFlatImageButton.GetUpImage: TBitmap;
begin
Result := GetImage(hsbsUp);
end;
procedure THSFlatImageButton.MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
inherited;
if Enabled then
State := hsbsDown;
end;
procedure THSFlatImageButton.MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
inherited;
if Enabled then
State := hsbsUp;
end;
procedure THSFlatImageButton.Paint;
begin
Canvas.StretchDraw(ClientRect, FImages[FState]);
end;
procedure THSFlatImageButton.SetDisabledImage(const Value: TBitmap);
begin
SetImage(hsbsDisabled, Value);
end;
procedure THSFlatImageButton.SetDownImage(const Value: TBitmap);
begin
SetImage(hsbsDown, Value);
end;
procedure THSFlatImageButton.SetHoverImage(const Value: TBitmap);
begin
SetImage(hsbsHover, Value);
end;
procedure THSFlatImageButton.SetImage(const Index: THSButtonState;
const Value: TBitmap);
begin
FImages[Index].Assign(Value);
if FState = Index then
Invalidate;
end;
procedure THSFlatImageButton.SetState(const Value: THSButtonState);
begin
if FState <> Value then
begin
FState := Value;
Invalidate;
end;
end;
procedure THSFlatImageButton.SetUpImage(const Value: TBitmap);
begin
SetImage(hsbsUp, Value);
end;
end.
-
> > Понизить видимость нельзя > Как нельзя? перемещю соотв свойства в protected и все.
Перемешение ничего не даст, можете проверить
-
> Кулибин. Компонентов таких написано море.
Покажи удовлетворяющий сабжу. Чтобы с Caption и c Action'ом был. > Моё предложение.
Ок. Последую. Только зачем тогда mbsDisabled если можно проверять просто Enabled. mbsHot надо ставить и снимать в CMMouseEnter|Leave, так? А вот где можно понять что кнопка нажата? Так а как рисовать Caption? Нашел это место в TSpeedButton там как-то хитро закручено через TButtonGlyph
-
> Перемешение ничего не даст, можете проверить
Действительно. В результате только CodeInsite не видит свойство, а компиляция идет нормально
Может тогда заглушки сделать?
-
Kolan © (01.04.08 11:41) [11]
Любой наследник TButton,TSpeedButton,TBitBtn будет иметь Action. Перекрытие процедуры Paint дает тебе возможность рисовать хоть черта лысого.
Накачай компонентов с torry.net - там кнопок с картинками как звезд на небе, посмотри, как устроены, пойми почему так, а не иначе.
-
> Буквально за час
> Кулибин
Еще нет Экшена и TPicture :)
Благодарю. Теперь понятно где какие состояния выставлять.
ЗЫ Не увидел где устанавливается Disabled.
-
Kolan © (01.04.08 11:48) [14]
TPicture не нужен.
> ЗЫ Не увидел где устанавливается Disabled.
Не стал делать, но обычно в обработчике сообщение CM_ENABLEDCHANGED
-
> Игорь Шевченко © (01.04.08 11:34) [9]
Класс !!! Проиндексировав картинки можно сокатить код
-
if Enabled then State := XXX; Можно перенести в SetState тогда
procedure THSFlatImageButton.SetState(Value: THSButtonState);
begin
if not Enabled then Value := hsbsDisabled;
if fState = Value then Exit;
fState := Value;
Invalidate;
end;
-
Ок.
-
DimaBr © (01.04.08 12:51) [16]
У меня не вышло проиндексировать :) Я запамятовал, можно ли индексировать свойства, значением которых является объект
-
Кстати, еще одна написанная за час кнопка: 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)
Форма, прогрессбар и кнопка. Идет какой либо процесс (прогрессбар бежит) и одна кнопка Ок, Которая не доступна пока идет процесс, а пользователь мышь держит на ней и ждет.... :о)
-
...по окончанию процесса кнопка становится доступной...
-
> DimaBr
Правда не понял зачем эти извращения с курсором. Вроде и так ([24]) состояния правильно работают.
-
Сделал так вывод кэпшена: 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;
if FButtonState = mibsDisabled then
begin
Canvas.Font.Color := clBtnHighlight;
Canvas.TextOut((ControlMiddle.X — TextMiddle.X) + CaptionXOffset + 1,
(ControlMiddle.Y — TextMiddle.Y) + CaptionYOffset + 1, Caption);
Canvas.Font.Color := clBtnShadow;
Canvas.TextOut((ControlMiddle.X — TextMiddle.X) + CaptionXOffset,
(ControlMiddle.Y — TextMiddle.Y) + CaptionYOffset, Caption);
end
else
Canvas.TextOut((ControlMiddle.X — TextMiddle.X) + CaptionXOffset,
(ControlMiddle.Y — TextMiddle.Y) + CaptionYOffset, Caption); Повиду все нормально работает.
-
{RASkov} © (01.04.08 17:17) [39]
Я бы для подобных извратов все равно сделал бы по образу и подобию TSpeedButton.UpdateTracking
-
Хотелось бы, чтобы если картинка не задана, то рисовалась бы обычная
Изменил код так: TempPicture := GetImage(FButtonState);
if not Assigned(TempPicture.Graphic) or (TempPicture.Graphic.Empty) then
TempPicture := GetImage(mibsNormal);
Canvas.StretchDraw(ClientRect, TempPicture.Graphic); Но почему-то все равно ничего не рисуется
-
Удалено модератором Примечание: Флудить завязываем
-
А и еще. А как реагировать на изменение Caption? Написать сеттер&
-
И все-таки все это дело мерцает :(. Как быть?
-
> А как реагировать на изменение Caption? Написать сеттер&
Обрабатывать CM_TEXTCHANGED
Ты когда-нибудь откроешь исходники VCL или так всю жизнь и будешь ключи подавать ? Тогда тебе в "Начинающие", навечно
-
> Обрабатывать CM_TEXTCHANGED
Я сомневаюсь в себе :). Получилось.
А с мельканием что делать?
-
С мельканием - воевать ControlStyle := ControlStyle + [ csOpaque ] ;
-
> А с мельканием что делать?
Скачай уже готовый компонент и не парься
-
> DimaBr © (01.04.08 11:33) [8] > Код DVM - я бы сказал не очень.
Это не мой код, я там написал же, что код не очень. Просто под руку попался.
-
> ControlStyle := ControlStyle + [ csOpaque ] ;
Угу. Помогло. Игорь, Dima, благодарю. Все что хотель все сделал + про index узнал. :)
-
> Игорь Шевченко © (02.04.08 11:18) [51] > Скачай уже готовый компонент и не парься
В принципе - не верно. "Лучше один раз увидеть, чем сто раз услышать"
-
DimaBr © (02.04.08 12:06) [54]
Раз пошел оффтопик - во всех нюансах компонентостроения лучше разбираться на действующих примерах, так как нюансы, они общие для многих компонентов. А не понимая этих нюансов и задавая на каждый чих вопрос в форуме - так всю жизнь и будешь ключи подавать и по форумам клянчить.
-
> [55] Игорь Шевченко © (02.04.08 12:30)
К сожалению к компонентам скачанным с нета у меня нет доверия. А незная нормальных решений я не могу понять хорошо написано или нет
ЗЫ До задания вопроса я скачал 3 штуки и посмотрел. Смысл везде один и тот же.
-
Kolan © (02.04.08 12:33) [56]
Какая разница "хорошо написано" или нет - главное, чтобы работало, как надо.
|