Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Edit Box with Image


This question is answered. Helpful answers available: 2. Correct answers available: 1.


Permlink Replies: 11 - Last Post: Nov 3, 2017 3:39 AM Last Post By: Mark Williams Threads: [ Previous | Next ]
Mark Williams

Posts: 120
Registered: 5/8/10
Edit Box with Image  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 1, 2017 12:15 PM
I have created an edit component which can display an image when required. The idea is to replicate the password dialog such as on login to Windows 10 ie the eye icon which when you hover over it reveals the password.

All works well with the new component save that the image disappears when navigational keys are entered. It does not disappear if any other keys are entered.

Does anyone have any idea what may be causing this behaviour?
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Edit Box with Image  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 1, 2017 5:13 PM   in response to: Mark Williams in response to: Mark Williams
Mark Williams wrote:

Does anyone have any idea what may be causing this behaviour?

Not without seeing your actual code.

--
Remy Lebeau (TeamB)
Mark Williams

Posts: 120
Registered: 5/8/10
Re: Edit Box with Image  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 2, 2017 12:51 AM   in response to: Mark Williams in response to: Mark Williams
Mark Williams wrote:
I have created an edit component which can display an image when required. The idea is to replicate the password dialog such as on login to Windows 10 ie the eye icon which when you hover over it reveals the password.

All works well with the new component save that the image disappears when navigational keys are entered. It does not disappear if any other keys are entered.

Does anyone have any idea what may be causing this behaviour?

{code}
unit PixEdit;

interface

uses
System.SysUtils, System.Classes, Vcl.Controls, Vcl.StdCtrls, vcl.Graphics, vcl.ExtCtrls, Winapi.Messages,
winapi.windows;

type
TPixEdit = class(TEdit)
private
FHeight, FWidth: Integer;
FPicture, FHotPicture: TPicture;
FImage, FHotImage: TImage;
FImageAlwaysVisible: Boolean;
FMaintainAspectRatio: Boolean;
FOnMouseImageEnter: TNotifyEvent;
FOnMouseImageLeave: TNotifyEvent;
FOnMouseHotImageEnter: TNotifyEvent;
FOnMouseHotImageLeave: TNotifyEvent;
FOnImageClick: TNotifyEvent;
procedure MouseImageEnter(Sender: TObject);
Procedure MouseImageLeave(Sender: TOBject);
procedure MouseHotImageEnter(Sender: TObject);
Procedure MouseHotImageLeave(Sender: TObject);
Procedure ImageClick(Sender: TObject);
{ Private declarations }
protected
procedure Change; override;
procedure CreateWnd; override;
procedure PictureChanged(Sender: TObject);
procedure HotPictureChanged(Sender: TObject);
procedure SetMargin;
procedure SetPicture(Value: TPicture);
procedure SetHotPicture(Value: TPicture);
procedure SetAspectRatio(Value: Boolean);
Procedure SetImageAlwaysVisible(Value: Boolean);
procedure WMKillFocus(var Message: TMessage); message WM_KILLFOCUS;
procedure WMSetFocus(var Message: TMessage); message WM_SETFOCUS;
procedure WMSize(var Message: TWMSize); message WM_SIZE;
{ Protected declarations }
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
{ Public declarations }
published
property Picture: TPicture read FPicture write SetPicture;
property HotPicture: TPicture read FHotPicture write SetHotPicture;
property MaintainAspectRatio: Boolean read FMaintainAspectRatio write SetAspectRatio;
property ImageAlwaysVisible: Boolean read FImageAlwaysVisible write SetImageAlwaysVisible;
property OnMouseImageEnter: TNotifyEvent read FOnMouseImageEnter write FOnMouseImageEnter;
property OnMouseImageLeave: TNotifyEvent read FOnMouseImageLeave write FOnMouseImageLeave;
property OnMouseHotImageEnter: TNotifyEvent read FOnMouseHotImageEnter write FOnMouseHotImageEnter;
property OnMouseHotImageLeave: TNotifyEvent read FOnMouseHotImageLeave write FOnMouseHotImageLeave;
property OnImageClick: TNotifyEvent read FOnImageClick write FOnImageClick;
{ Published declarations }
end;

procedure Register;

implementation

procedure Register;
begin
RegisterComponents('OWn Components', [TPixEdit]);
end;

constructor TPixEdit.Create(AOwner: TComponent);

Function CreateImage:TImage;
begin
Result := TImage.Create(Self);
with Result do
begin
Transparent := True;
Stretch := True;
Center := True;
Cursor := crArrow;
SetBounds(Width, 0, 0, Height);
Visible := false;
end;
Result.OnClick:=ImageClick;
end;

begin
inherited Create(AOwner);
ControlStyle:=ControlStyle + [csReplicatable];
FHeight := 0;
FWidth := 0;

FImage := CreateImage;
FImage.OnMouseEnter := MouseImageEnter;
FImage.OnMouseLeave := MouseImageLeave;
FPicture := TPicture.Create;
FPicture.OnChange:=PictureChanged;

FHotImage := CreateImage;
FHotImage.OnMouseEnter := MouseHotImageEnter;
FHotImage.OnMouseLeave := MouseHotImageLeave;
FHotPicture := TPicture.Create;
FHotPicture.OnChange := HotPictureChanged;
end;

destructor TPixEdit.Destroy;
begin
try
FImage.Free;
FHotImage.Free;
FPicture.Free;
FHotPicture.Free;
finally
inherited Destroy;
end;

end;

procedure TPixEdit.Change;
begin
inherited;
FImage.Visible := FImageAlwaysVisible or (trim(text)<>'');
FImage.Repaint;
FHotImage.Repaint;
end;

procedure TPixEdit.SetPicture(Value: TPicture);
begin
FPicture.Assign(Value);
end;

procedure TPixEdit.SetHotPicture(Value: TPicture);
begin
FHotPicture.Assign(Value);
end;

procedure TPixEdit.SetImageAlwaysVisible(Value: Boolean);
begin
if value <> FImageAlwaysVisible then
begin
FImageAlwaysVisible := value;
FImage.Visible := FImageAlwaysVisible;
end;
end;

procedure TPixEdit.PictureChanged(Sender: TObject);
begin
FImage.Picture.Assign(FPicture);
SetMargin;
end;

procedure TPixEdit.HotPictureChanged(Sender: TObject);
begin
FHotImage.Picture.Assign(FHotPicture);
SetMargin;
end;

procedure TPixEdit.SetAspectRatio(Value: Boolean);
begin
if value <> FMaintainAspectRatio then
begin
FMaintainAspectRatio := value;
setMargin;
end;
end;

procedure TPixEdit.MouseImageEnter(Sender: TObject);
begin
if (FHotPicture.Graphic <> nil) and not FHotPicture.Graphic.Empty then
begin
FHotImage.Visible := true;
FImage.visible := false;
end;

if Assigned(FOnMouseImageEnter) then
FOnMouseImageEnter(Self);
end;

procedure TPixEdit.MouseImageLeave(Sender: TObject);
begin
if Assigned(FOnMouseImageLeave) then
FOnMouseImageLeave(Self);
end;

procedure TPixEdit.MouseHotImageEnter(Sender: TObject);
begin
if Assigned(FOnMouseHotImageEnter) then
FOnMouseHotImageEnter(Self);
end;

Procedure TPixEdit.MouseHotImageLeave(Sender: TObject);
begin
if Assigned(FOnMouseHotImageLeave) then
FOnMouseHotImageLeave(Self);
FHotImage.Visible := false;
FImage.visible := true;
end;

procedure TPixEdit.ImageClick(Sender: TObject);
begin
if Assigned(FOnImageClick) then
FOnImageClick(Self);
end;

procedure TPixEdit.WMKillFocus(var Message: TMessage);
begin
inherited;

FImage.Repaint;
FHotImage.Repaint;
end;

procedure TPixEdit.WMSetFocus(var Message: TMessage);
begin
inherited;
end;

procedure TPixEdit.WMSize(var Message: TWMSize);
begin
inherited;

FHeight := Message.Height;
FWidth := Message.Width;

SetMargin;
end;

procedure TPixEdit.CreateWnd;
begin
inherited;

SetMargin;
end;

procedure TPixEdit.SetMargin;
var
FImgWidth: integer;
h: integer;
begin
FImgWidth := FHeight;

if assigned(FPicture.graphic) and not FPicture.Graphic.empty and FMaintainAspectRatio
and (FPicture.Bitmap.Height <> FPicture.bitmap.Width) then
begin
h := FHeight-2;
FIMgWidth := trunc(FPicture.bitmap.Width / FPicture.bitmap.height * h);
inc(FImgWidth, 2); //we're going to reduce it by 2 in setbounds
end;

// Resource protection
try
// Check state
if (FHeight = 0) or (FPicture.Graphic = nil) or FPicture.Graphic.Empty
or (not FImage.visible and not FHotImage.Visible) then
// Clear border
Perform(EM_SETMARGINS, EC_RIGHTMARGIN, MakeLong(0, 0))
else
// Set left size border
Perform(EM_SETMARGINS, EC_RIGHTMARGIN, MakeLong(0, FImgWidth));
finally
// Set the image bounds
FImage.SetBounds(FWidth-(FImgWidth+2), 1, FImgWidth - 2, FHeight - 2);
FHotImage.SetBounds(FWidth-(FImgWidth+2), 1, FImgWidth - 2, FHeight - 2);
end;

end;

end.
{Code}

Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Edit Box with Image  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 2, 2017 10:36 AM   in response to: Mark Williams in response to: Mark Williams
Mark Williams wrote:

FImage, FHotImage: TImage;
<snip>

I'm a little lost in what your component is trying to accomplish
exactly. Can you please explain the code?

Why are you using two separate TImage objects? I would use just one
TImage and swap its Picture content as needed. Or, not even use a
TImage at all, just handle WM_PAINT to draw the desired TPicture
graphic directly onto the TEdit's HDC after letting the default handler
draw the text.

--
Remy Lebeau (TeamB)
Mark Williams

Posts: 120
Registered: 5/8/10
Re: Edit Box with Image  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 2, 2017 12:33 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Mark Williams wrote:

FImage, FHotImage: TImage;
<snip>

I'm a little lost in what your component is trying to accomplish
exactly. Can you please explain the code?

Why are you using two separate TImage objects?

I could have used just one image and swapped the pictures. This didn't occur to me until after I had finished. I also could have drawn straight to the canvas.

The idea behind the component is to add an image to the right hand side of the edit box. This can either be set to be visible the whole time or it becomes visible only when there is text entered in the box, which is the default behaviour. I use the default behaviour to reveal the password when the user hovers over the image.

But although this works fine, sometimes the image just disappears usually when the navigational keys are entered and I cannot figure out why that is happening.
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Edit Box with Image  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 2, 2017 1:02 PM   in response to: Mark Williams in response to: Mark Williams
Mark Williams wrote:

The idea behind the component is to add an image to the right hand
side of the edit box.

I understand that much. But why are you toggling the image visibility,
and changing the edit margins, based on mouse movement within the edit
and image? That just complicates the component. I would keep the
image visible always, and the margins static, changing the margins only
when the component is resized. There is not really a good reason to
ever hide the image. Clicking on the image would just be a no-op if
there is no text.

But although this works fine, sometimes the image just disappears
usually when the navigational keys are entered and I cannot figure
out why that is happening.

That is what the debugger is meant for. Put a breakpoint in the key
down/press/up events, and step through the component's code when typing
navigation keys to see how your component actually responds.

--
Remy Lebeau (TeamB)
Lajos Juhasz

Posts: 801
Registered: 3/14/14
Re: Edit Box with Image  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 2, 2017 8:28 AM   in response to: Mark Williams in response to: Mark Williams
Mark Williams wrote:
All works well with the new component save that the image disappears
when navigational keys are entered. It does not disappear if any
other keys are entered.

Does anyone have any idea what may be causing this behaviour?

This is right how you've coded the control to behave. Inspect:

procedure TPixEdit.Change;
begin
  inherited;
  FImage.Visible := FImageAlwaysVisible or (trim(text)<>'');


When you enter a text into the edit the text is not empty anymore and
the image stays visible.
Mark Williams

Posts: 120
Registered: 5/8/10
Re: Edit Box with Image  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 2, 2017 9:57 AM   in response to: Lajos Juhasz in response to: Lajos Juhasz
This is right how you've coded the control to behave. Inspect:

When you enter a text into the edit the text is not empty anymore and
the image stays visible.

It works when you enter text into the box. The image appears, but I want it to remain visible. If you subsequently use the arrow keys eg home, end, left, right etc the image disappears, which is not what I want to happen.

I have also noticed that the image disappears if you type text anywhere other than the end of the string and this also cause the call to setmargin to miscalculate the right margin ie, the image disappears and so does the right margin.
Lajos Juhasz

Posts: 801
Registered: 3/14/14
Re: Edit Box with Image  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 2, 2017 2:15 PM   in response to: Mark Williams in response to: Mark Williams
Mark Williams wrote:

This is right how you've coded the control to behave. Inspect:

When you enter a text into the edit the text is not empty anymore
and the image stays visible.

It works when you enter text into the box. The image appears, but I
want it to remain visible. If you subsequently use the arrow keys eg
home, end, left, right etc the image disappears, which is not what I
want to happen.

I have also noticed that the image disappears if you type text
anywhere other than the end of the string and this also cause the
call to setmargin to miscalculate the right margin ie, the image
disappears and so does the right margin.

You should check out the TButtonedEdit in VCL.ExtCtrls.
Mark Williams

Posts: 120
Registered: 5/8/10
Re: Edit Box with Image  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 2, 2017 6:41 PM   in response to: Lajos Juhasz in response to: Lajos Juhasz
Lajos Juhasz wrote:

You should check out the TButtonedEdit in VCL.ExtCtrls.

Thanks. I did originally check it out and dismissed it because it didn't have a maskEdit. Also wanted to use control for DateEdit control. I could probably have added a maskEdit property to the TButtonedEdit. In fact that is probably what I will do!
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Edit Box with Image  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 2, 2017 8:09 PM   in response to: Mark Williams in response to: Mark Williams
Mark Williams wrote:

Also wanted to use control for DateEdit control.

What's wrong with using the standard TDateTimePicker?

--
Remy Lebeau (TeamB)
Mark Williams

Posts: 120
Registered: 5/8/10
Re: Edit Box with Image  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 3, 2017 3:39 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
As far as I can ascertain it doesn't allow for blank text other then by setting format to ' '. More significantly for me there is no simple mechanism for the user to clear the date. I suppose you could add a button to allow them to do that, but it is not exactly slick.

I have tried drawing the button (ie a graphic) directly to the maskedit canvas (which was one of the possible solutions you mentioned). But, unless I am missing something, this means that you also have to draw the text to the canvas, which loses all selection support, styleelements etc.

I have decided to derive from TButtonedEdit and initially I was going to try and add a maskedit to this component, but having looked into it that is a lot of work. I have decided instead to do away with the maskedit and just allow a freetext with a few checks.
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02