Link to home
Start Free TrialLog in
Avatar of hush021299
hush021299

asked on

How can I use non-rect. bitmap-buttons in my delphi application

Question: How can I use such non-rectangular bitmap-buttons (e.g.with shadow) in my delphi application ?

I want to use some round buttons on my App. as designed with an Image program. Those button images contain gradient, shadow etc.

Currently I use an imagebutton component to hold 3 images for the different mouse states. Problems are:
Matching image on button and background.

Any recommendations?

Avatar of Member_2_248744
Member_2_248744
Flag of United States of America image

hello hush, the thing you describe will require you to get the view of the background behind your button as a bitmap and then create your "shadow" as some sort of blend darking of that elllipical area, as long as your buttons do not change position, this may not be overly difficult. . .  You should be able to Show your form with your buttons hidden, and then get a bitmap of the background behind the buttons and create your shadows, add those bitmaps to your Image button control and then show the buttons, if you are not using a changable windows system color behind your buttons (maybe your background is a bitmap) then you can just use the bitmap and create your blend bitmaps from the background bitmap. Alot depends on some conditions your buttons be have. . .
Avatar of hush021299
hush021299

ASKER

This is another aspect.
I was not considering to make the shadows myself, but if this is possible I should consider.

First currently I have a rectangular coolbar/toolbar and a rectangular image button.

Do you now a tutorial how to make a shadow? (I do this just for the design, so this has to compete with a professional shadow from a photo program). I didnt find anything here in the web

Now the image button is rectangular. Do you suggest to use a shaped button (there are some, creating a form based on the bitmap mask) but those create usually a border.
On the other hand , when I use the image button I must know where the image on the button is. Meaning i have a gradient background. I use the image button with a red background and a round button in front. Red becomes transparent, but I need to know the position where the round button image is on the button and then on the background_`?
???
I am not to sure about your coding requirements from your last comment?
If you do not make the shadows your self, then who is going to make them? I don't get it?

you say that you have a bar with a  "rectangular image button" and you talk about a "non-rectangular bitmap-button", I will guess that you want to use a rectangular image button as an ellipise button?. .  I am not sure what to say to try and help, . . .

you might look at this EE question about non-rectangular buttons -

https://www.experts-exchange.com/questions/20190694/Shaped-buttons-again.html

it has the  ilPicButton.pas button component, but there are many many picture buttons at Torry's and other component sites, but they may not be for a toolbar type of control. . . . . . .

So, most of the control areas that the windows API have (and Delphi) are rectangular, for ALOT of good reasons, as far as a non-rectangular, this can be a visual effect, you can draw a circle on a square control and if that control does not have visual borders, it looks round. . . So you will have to deal with color of the pixels and the visual effect to the eye, a shadow is just a darker appearence from the surrounding background, with the shape of the thing that is shadowed.

But I am not sure about a tutorial how to make a shadow, do you mean with an Image editor or with delphi code?
I have done delphi code to do shadows, you just darken an area, , the problem is that you will need something to darken, a background, I can only guees from your comment, that your bakground is a windows system color (for a ToolBar I guess it's system Button Color), but you say something about "Meaning i have a gradient background", , , but I can understand about that?

seems like I could help you with this, maybe if you could tell me-
Does the area behind (background) the button area, have a single color, or more than one color,, , ,, if more than one color, you you know the colors at design time, or are they created at run time?

Sorry I wasnt online for a while.
Thanks for your suggestions.
The idea is that a buddy is responsible for the design of my application. He has created some pretty studies with some even round buttons. Those buttons are round - gel type buttons with a shadow .. but here is the crux .. I must then be the same background as for the coolbar background. So the designer has to design the background and the button.
I think I have understand that it should work like a web page rather then using non rec-buttons because the non-rec buttons are not antialiased at the edge and it is difficult to create a professional looking shadow (at least for me by using code).
Some other designed buttons are even more od to create programatically. E.g buttons like Tabs of a Tabcontrol that could be realized again just as an image (at least this is what I believe now).

So it seems to fall back to another imagebutton-component. I have one, but this one has a bug. I guess I need to find another one.

For now I think I should reward you,  but pls. show me another good and small image-button.

Regards
HH
???
I no longer use any other components except my own components, and my buttons are very specialized, not for general use
the link above is for a graphic button that works well using an Image List. Maybe I can find something in my old code storage. . .

you should really look at Torry's oat

http://www.torry.net

or other component web site
ASKER CERTIFIED SOLUTION
Avatar of Member_2_248744
Member_2_248744
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thank you it works well for me..unless..do you think I can make it to show the normal image at designtime?
Regards
HH
sorry hush, I have been busy with the end of the week "Finish It" and "Clean Up", . . . I have not had time to install and eveluate PicButton2. . . however. . . Looking at the code I commented out the

procedure TPicButton2.CreateParams(var Params: TCreateParams);

don't have a clue why I did that?

and would guess that this may be why it don't paint in design mode


add it to theprotected section like - -

    protected
    property Brush;
    property Default;
    property Action;
    procedure SetButtonStyle(ADefault: Boolean); overRide;
    procedure CreateParams(var Params: TCreateParams); override;
    procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
    procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;

and UnComment all of the

procedure TPicButton2.CreateParams(var Params: TCreateParams);

procedure. . .
maybe that will help
This doesnt work, it shut down entire delphi. I have no idea why.
I had some time yesterday, and did this version for  PicButton3 and I changed it some, it will draw in design time, and seems to work in all that I tried it, I hope it does OK for you -




unit PicButton3;

interface
uses
  Windows, Messages, Classes, Graphics, Controls, stdCtrls;


type
TPicButton3 = class(TButton)
    private
    FOver, FDoRect, FDoText: Boolean;
    FFocusColor: TColor;
    FNormalPic, FHiLightPic, FDownPic, FDisabledPic, FFocusPic: TBitmap;
    procedure setNormal(Value: TBitMap);
    procedure setHiLight(Value: TBitMap);
    procedure setDown(Value: TBitMap);
    procedure setDisabled(Value: TBitmap);
    procedure setFocusPic(Value: TBitMap);
    procedure DrawItem(const DIRec: TDrawItemStruct);
    procedure CNMeasureItem(var Message: TWMMeasureItem); message CN_MEASUREITEM;
    procedure CNDrawItem(var Message: TWMDrawItem); message CN_DRAWITEM;
    procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
    procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
    procedure CMEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED;

    protected
    property Brush;
    property Default;
    property Action;
    procedure SetButtonStyle(ADefault: Boolean); overRide;
    procedure WMPaint(var Message: TMessage); message WM_PAINT;
    procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
    procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;

    public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Loaded; override;

    published
    { Published declarations }
    property PicNormal: TBitMap read FNormalPic write setNormal;
    property PicHiLight: TBitMap read FHiLightPic write setHiLight;
    property PicPushed: TBitMap read FDownPic write setDown;
    property PicDisabled: TBitmap read FDisabledPic write setDisabled;
    property PicFocus: TBitmap read FFocusPic write setFocusPic;
    property FocusColor: TColor read FFocusColor write FFocusColor default clRed;
    property DoFocusText: Boolean read FDoText write FDoText default False;
    property DoFocusRect: Boolean read FDoRect write FDoRect default False;
    property Caption;
    property Enabled;
    property ParentShowHint;
    property ParentBiDiMode;
    property ShowHint;
    property TabOrder;
    property TabStop;
    property Visible;
    property OnEnter;
    property OnExit;

end;

procedure Register;

implementation

type
TMyState = (bsUp, bsDown, bsHigh, bsDisabled);

procedure Register;
begin
RegisterComponents('Samples', [TPicButton3]);
end;

constructor TPicButton3.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
ControlStyle:= ControlStyle - [csSetCaption, csOpaque];
FOver := False;
FNormalPic  := TBitMap.Create;
FHiLightPic := TBitmap.Create;
FDownPic  := TBitmap.Create;
FDisabledPic := TBitmap.Create;
FFocusPic := TBitmap.Create;
FDoText := False;
FDoRect := False;
FFocusColor := clRed;
Constraints.MaxHeight := Height;
Constraints.MinHeight := Height;
Constraints.MaxWidth := Width;
Constraints.MinHeight := Width;
end;

destructor TPicButton3.Destroy;
begin
inherited Destroy;
FNormalPic.Free;
FHiLightPic.Free;
FDownPic.Free;
FDisabledPic.Free;
FFocusPic.Free;
end;

procedure TPicButton3.Loaded;
begin
inherited Loaded;
if FNormalPic.Empty then Exit;
Constraints.MaxHeight := FNormalPic.Height;
Constraints.MinHeight := FNormalPic.Height;
Constraints.MaxWidth := FNormalPic.Width;
Constraints.MinHeight := FNormalPic.Width;
Width := FNormalPic.Width;
Height := FNormalPic.Height;
end;

procedure TPicButton3.SetButtonStyle(ADefault: Boolean);
begin
if HandleAllocated then
  SendMessage(Handle, BM_SETSTYLE, BS_PUSHBUTTON or BS_OWNERDRAW, 1);
end;

procedure TPicButton3.setNormal(Value: TBitMap);
begin
FNormalPic.Assign(Value);
if not FNormalPic.Empty then
  begin
  Constraints.MaxHeight := FNormalPic.Height;
  Constraints.MinHeight := FNormalPic.Height;
  Constraints.MaxWidth := FNormalPic.Width;
  Constraints.MinHeight := FNormalPic.Width;
  Height := FNormalPic.Height;
  Width := FNormalPic.Width;
  end;
Invalidate;
end;

procedure TPicButton3.setHiLight(Value: TBitMap);
begin
FHiLightPic.Assign(Value);
end;

procedure TPicButton3.setDown(Value: TBitMap);
begin
FDownPic.Assign(Value);
end;

procedure TPicButton3.setDisabled(Value: TBitMap);
begin
FDisabledPic.Assign(Value);
end;

procedure TPicButton3.setFocusPic(Value: TBitMap);
begin
FFocusPic.Assign(Value);
end;
   
procedure TPicButton3.CNMeasureItem(var Message: TWMMeasureItem);
begin
Message.MeasureItemStruct^.itemWidth := Width;
Message.MeasureItemStruct^.itemHeight := Height;
end;
   
procedure TPicButton3.CNDrawItem(var Message: TWMDrawItem);
begin
DrawItem(Message.DrawItemStruct^);
end;

procedure TPicButton3.CMTextChanged(var Message: TMessage);
begin
Invalidate;
end;

procedure TPicButton3.CMMouseLeave(var Message: TMessage);
begin
FOver := False;
if Enabled and Assigned(FHiLightPic) then
  Invalidate;
end;

procedure TPicButton3.CMMouseEnter(var Message: TMessage);
begin
FOver := True;
if Enabled and Assigned(FHiLightPic) then
  Invalidate;
end;

procedure TPicButton3.CMFontChanged(var Message: TMessage);
begin
inherited;
Invalidate;
end;
   
procedure TPicButton3.CMEnabledChanged(var Message: TMessage);
begin
inherited;
Invalidate;
end;

procedure TPicButton3.WMPaint(var Message: TMessage);
var
BmpDC: Integer;
PaintS: TPaintStruct;
cRect: TRect;
PenO: Cardinal;
begin
if not (csDesigning in ComponentState) then
  begin
  Inherited;
  Exit;
  end;

Message.Result := 0;
BeginPaint(Handle, PaintS);
if FNormalPic.Empty then
  begin
  PenO := SelectObject(PaintS.hDC, CreatePen(PS_SOLID, 1, $999999));
  SetROP2(PaintS.hdc, R2_XORPEN);
  Rectangle(PaintS.hdc, 0, 0, Width, Height);
  DeleteObject(SelectObject(PaintS.hdc, PenO));
  EndPaint(Handle,PaintS);
  Exit;
  end;

BmpDC := CreateCompatibleDC(0);
SelectObject(BmpDC, FNormalPic.Handle);
BitBlt(PaintS.hdc, PaintS.rcPaint.Left, PaintS.rcPaint.Top,
           PaintS.rcPaint.Right, PaintS.rcPaint.Bottom, BmpDC,
           PaintS.rcPaint.Left, PaintS.rcPaint.Top, SRCCOPY);
DeleteDC(BmpDC);

if Length(Caption) > 0 then
  begin
  cRect := ClientRect;
  SelectObject(PaintS.hdc, Font.Handle);
  SetBkMode(PaintS.hdc, TRANSPARENT);
  DrawText(PaintS.hdc,PChar(Caption),-1,cRect,DT_SINGLELINE or DT_VCENTER or DT_CENTER);
  end;
EndPaint(Handle,PaintS);
end;
   
procedure TPicButton3.DrawItem(const DIRec: TDrawItemStruct);
var
  Pic: TBitmap;
  IsFocus: Boolean;
  State: TMyState;
  cRect: TRect;
begin
if (csDesigning in ComponentState) then Exit;
 
cRect := ClientRect;
{I assign a State to get the correct Image}
if not Enabled then State := bsDisabled else
if DIRec.itemState and ODS_SELECTED <> 0 then
  State := bsDown else
if FOver then
  State := bsHigh else
  State := bsUp;

IsFocus := DIRec.itemState and ODS_FOCUS <> 0;

Pic := FNormalPic;
case State of
{set the Pic and cRect}
  bsUp: if IsFocus then
        if not FFocusPic.Empty then Pic := FFocusPic;
  bsDown: begin
          if not FDownPic.Empty then
            Pic := FDownPic else
            if not FHiLightPic.Empty then Pic := FHiLightPic;
          cRect := Rect(2,2,Width+2,Height+2)
          end;
  bsHigh: if not FHiLightPic.Empty then Pic := FHiLightPic;
  bsDisabled: begin
              if not FDisabledPic.Empty then Pic := FDisabledPic;
              SetTextColor(DIRec.hdc, clSilver);
              end;
  end;

if not Pic.Empty then
  BitBlt(DIRec.hDC, 0, 0, Width, Height, Pic.Canvas.Handle, 0, 0, SRCCOPY);

if IsFocus and FDoText then
  SetTextColor(DIRec.hdc, FFocusColor);

SelectObject(DIRec.hDC, Font.Handle);
SetBkMode(DiRec.hdc, TRANSPARENT);
if Length(Caption) > 0 then
    DrawText(DIRec.hDC,PChar(Caption),-1,cRect,DT_SINGLELINE or DT_VCENTER or DT_CENTER);

if IsFocus and FDoRect then
  begin
  InflateRect(cRect, -3, -3);
  windows.DrawFocusRect(DIRec.hdc, cRect);
  end;
end;

end.
THanks a lot.
THis works fine now.
Is it possible to spend some extra points from here?

Regards
hush
this question is Done, closed, but you can post another question, something like

Award (or Points)  for Slick812

and give out more points to someone

but remember, the EE moderators will not allow more than 500 points total (mutiple award questions) for any single question