Caret position on webbrowser - delphi

I'm trying to get the id of a htmlinputtextelement in webbrowser where the caret is blinking. So when I press TAB it changes.
How can I do this in delphi?
You know when you go onto a website and there are multiple inputtextelements. You can scroll through them by pressing TAB. When you are finished with box 1, TAB, fill in box 2, TAB, box 3, TAB till you have completed the form on the website. I want to do this. By knowing what the id is of the inputtextelement that the current caret is in.
You can get the mouse position with getcursorpos. can you get the caret position the same way? They do not give the same location for x and y...??
procedure TForm1.Button2Click(Sender: TObject);
var
MausPos: TPoint;
HtmlElement: IHTMLElement;
iHTMLDoc: IHtmlDocument2;
tag1:string;
id1:string;
begin
if Supports(webbrowser1.Document, IHtmlDocument2, iHTMLDoc) then
begin
if GetcaretPos(MausPos) then
begin
MausPos := webbrowser1.screentoclient(MausPos);
HtmlElement := iHTMLDoc.ElementFromPoint(MausPos.X, MausPos.Y);

The Caret is not as simple as the mouse cursor position: Each Window is free to create and display it's own caret, wherever it wants it. Here's a Using Carets link on MSDN. You'd normally expect a window to only show a Caret if it has keyboard focus, but a I don't think there's anything stopping a window from showing the Caret even if it doesn't have keyboard focus.
Since the normal behavior is to only show the caret if there's keyboard focus, you may check for that using: GetFocus. But you'll likely find out the TWebBrowser itself is holding the focus, I doubt there's an Window Handle for each HTML element.
What I assume you actually want is the active element. You can get that using:
(TWebBrowser.Document as IHTMLDocument2).activeElement
Here's a short code snippet that uses this property:
procedure TForm25.Button2Click(Sender: TObject);
begin
if (W.Document as IHTMLDocument2).activeElement <> nil then
ShowMessage((W.Document as IHTMLDocument2).activeElement.tagName);
end;

Related

Displaying a disabled modal form

I'm trying to disable a TForm's descendant and showing it as a modal form.
procedure TForm1.Button1Click(Sender: TObject);
var
Frm : TMyForm;
begin
Frm := TMyForm.Create(nil);
try
Frm.Enabled := False;
Frm.ShowModal();
finally
Frm.Free;
end;
end;
At runtime, it raises the following error message:
Cannot make a visible window modal.
The OP wants to display a disabled form modally when the form should be displayed for read-only purposes.
Disabling the form is the wrong thing to do.
How do you display the information? If you are using TEdit, TMemo, or TRichEdit controls, you should simply set them to read only. Otherwise, if you have some combinations of various controls like radio buttons, you should disable each and every such control, not the form itself. I mean, surely you still want the Cancel button to be enabled?
In addition, disabling the form instead of the actual controls will make the controls look enabled, which is very confusing! That's an important point.
So what you need to do is to display the form normally (not disabled!) and then set its controls to their appropriate states when the dialog is shown.
Just to emphasise my point about disabling the form vs its controls, consider this dialog box:
If I do
procedure TCustomViewFrm.FormShow(Sender: TObject);
begin
Enabled := False;
end;
then it looks like this when shown:
As you can see, every control looks very enabled indeed, but no control responds to mouse or keyboard input. This is very confusing and a horribly bad UX.
In fact, you cannot even close the dialog box using its title-bar Close button or Alt+F4. You cannot close it using its system menu, either. In fact, you cannot close it at all, because to close a window, it must respond to user input, and a disabled window doesn't do that. (You cannot move the window, either.)
Instead, if we disable all controls (except the Cancel button),
procedure DisableControl(AControl: TWinControl);
begin
for var i := 0 to AControl.ControlCount - 1 do
begin
if
(AControl.Controls[i] is TCustomButton)
and
(TCustomButton(AControl.Controls[i]).ModalResult = mrCancel)
then
Continue;
if AControl.Controls[i] is TWinControl then
DisableControl(TWinControl(AControl.Controls[i]));
AControl.Controls[i].Enabled := False;
end;
end;
procedure TCustomViewFrm.FormShow(Sender: TObject);
begin
DisableControl(Self);
end;
you get this nice UI:
Not only is it very clear that all controls are disabled, the user can also close the dialog box without killing your application using the Task Manager.

How do I display a label in an edit box, but switch to password-entry mode when it receives focus?

I use Delphi 10 and Windows 10.
The following code makes caret and selection disappear in Edit1.
procedure TForm1.Edit1Enter(Sender: TObject);
begin
Edit1.PasswordChar := '*';
end;
After the focus moves to the other control and in onClick it works well.
I can't use onClick because the focus moves by tab key and the Edit1 should start with default #0 because it holds text which is 'password' before the focus enters.
How can I solve this?
The edit control works as designed and as expected.
If you want the control to hide a password then set then TEdit.PasswordChar in the OI or on creation or ... but not every time you enter the control
If you want to have a hint then set the TEdit.TextHint property which will be shown if TEdit.Text is empty and the control is not focused

TEdit onclick select all?

How to select all text of a TEdit1 whenever user click on it or click to select some text of it
It can be quite dangerous to do anything beyond the default behaviour of the TEdit control. Your users know how the standard Windows controls behave and any deviation from this is likely to cause confusion.
By default the AutoSelect property is set to True.
Determines whether all the text in the edit control is automatically selected when the control gets focus.
Set AutoSelect to select all the text when the edit control gets focus. AutoSelect only applies to single-line edit controls.
Use AutoSelect when the user is more likely to replace the text in the edit control than to append to it.
When this property is True, the entire contents of the edit control are selected when it gets the focus by means of keyboard action. If the control gets the focus by a mouse click then the contents will not all be selected. In that case you simply press CTRL+A to select all. A double click will select the word underneath the mouse. This is all standard behaviour implemented by the underlying Windows control.
If you change the select in response to the OnClick event, as per the currently selected answer, then you will find that it is impossible to move the caret with a mouse click. This is exceedingly counter-intuitive behaviour.
This is a classic example of why you need to be very careful about changing the behaviour of a control from its default. It's simply very easy not to miss a particular use case when testing but when your users get hold of the program, they are sure to find all such wrinkles.
What you could safely do is to call SelectAll from OnDblClick. This would, I believe have no annoying side-effects.
Another option would be to call SelectAll when the focus switched to the edit control, but not every time you click in the control. This might feel a little odd to the user, but I personally think it would be reasonable to take this course of action. If you want to do this you need to handle the OnEnter event of your edit control:
procedure TForm1.Edit1Enter(Sender: TObject);
begin
PostMessage(Edit1.Handle, EM_SETSEL, 0, -1);
end;
How to select all text of a TEdit1 whenever user click on it
Select Edit1 in the VCL editor and double-click on the OnClick event:
procedure TForm13.Edit1Click(Sender: TObject);
begin
Edit1.SelectAll;
end;
You can also link this event to another control like a button.
Select the button, choose and click on the V arrow to select an event you want to link.
Now both Edit1.OnClick and Button1.OnClick link to the same event.
How to select some text of a TEdit1 whenever user click on it:
procedure TForm1.Edit1Click(Sender: TObject);
begin
Edit1.SelStart:= 1;
Edit1.SelLength:= 2;
end;
You must use OnMouseUp;
procedure cxMRUEdit1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Button=mbLeft then cxMRUEdit1.SelectAll;
end;

How Do I Add A TLabel To The Menu Bar in Delphi?

I use Beyond Compare (a great program), and was very impressed when it displayed a "New Version Available" label on its Menu Bar. I clicked on it, up popped an install new version box, it installed, the program restarted itself and there was the new version and no more label.
I thought that was a great feature. The label is there prominently on the menu bar where the user can't miss it. I've already got the update procedure, so all I had to do was add the label. That should be easy.
Here's the label where I want it:
(source: beholdgenealogy.com)
... Wrong. I couldn't figure out how to add a label there. The menu bar and the control area above it appear to be hands-off area for visual components. I couldn't place one there.
But I know it can be done, because Beyond Compare is a Delphi program.
Can anyone tell me what I have to do to put a TLabel in my Menu Bar or at least make it appear to be over the Menu Bar in the correct position?
For reference, I use Delphi 2009.
Conclusion: Christopher seems to have correctly figured out what the Beyond Compare people did. I've decided to implement the menu item, but without the customization of his "owner draw" solution. So I don't get the blue bold underline hyperlink look, but I also don't lose all the automatic things (like the Vista styling) that owner draw skips.
To space the menu item over to the right, I've added an item after the "Help" that has the caption " " and is disabled.
Thanks, Christopher. I was stuck thinking it must be a Label, but you saw around that.
Are you sure it's a label?
I haven't used the program, but it could just be a menu item, set to 'owner draw' and painted to look like a link?
http://sirmonkeys.com/images/updatelink.png
(done in Delphi 7)
procedure TForm1.MYITem1DrawItem(Sender: TObject; ACanvas: TCanvas;
ARect: TRect; Selected: Boolean);
begin
acanvas.Font.Style := [fsUnderline,fsbold];
acanvas.Font.color := clblue;
acanvas.Brush.Style := bsClear;
acanvas.TextOut(arect.left+1,arect.top+1,'Link to Update...');
end;
procedure TForm1.MYITem1MeasureItem(Sender: TObject; ACanvas: TCanvas;
var Width, Height: Integer);
begin
width := 100;
end;
and then either a have an ImageList assigned to MainMenu1.Images
or set MainMenu1.OwnerDraw to true.
Beyond Compare's implementation is actually a TLabel. We use Toolbar 2000 for our menus and toolbars, so embedding a control on the menu directly is supported (with a correct background), and it has the advantage that it supports right-justified menu items.

Image Preview in a Listbox

How can I display a preview (almost like a hint) of an image when I hover the mouse over an item in a listbox of filenames? I've tried showing a form and loading the image, but when the preview form shows, I lose focus for the listbox which means that when I move the mouse, the preview image does not change when I go to the next item in the list.
Thanks, Pieter.
I have, based on the answer from TOndrej, tried to implement a custom THintWindow, but the Canvas.StretchDraw does not draw the bitmap sent as a parameter. Any ideas why not? Text is displayed normally.
procedure TFormMain.DisplayPreview(HintImage: TBitmap);
var
CustomHint: THintWindow;
Rect: TRect;
MousePoint: TPoint;
begin
*{
Based on Source: http://www.chami.com/tips/delphi/112996D.html
}*
GetCursorPos(MousePoint);
with Rect do
begin
// set the position and size of the hint window
Left := MousePoint.X;
Top := MousePoint.Y;
Right := Left + 50;
Bottom := Top + 25;
end;
CustomHint := THintWindow.Create(Self);
try
with CustomHint do
begin
// set the background color
//Color := clNone;
**Canvas.StretchDraw(Rect, HintImage);**
ActivateHint(Rect, 'Hint');
Application.ProcessMessages;
//
// perform your tasks here
// before closing the hint window
//
Sleep(500);
ReleaseHandle;
end;
finally
if Assigned(CustomHint) then
CustomHint.Free;
end;
end;
To me it seems you want a custom hint window. To do this you should write a new THintWindow descendant and either set it globally to the whole application by assigning your new class to the HintWindowClass global variable in Forms unit, or write your own listbox descendant in which you will handle CM_HINTSHOW message and assign your new hint window class to HintInfo.HintWindowClass. (HintInfo points to a record passed to your control in the CM_HINTSHOW message by the VCL.)
1) Are you displaying your preview form like a dialog (Modal Window) if yes then change it to non modal window.
2) Remember to set focus back to your parent window once the preview form shows up, that way your parent form that has the listbox has the focus and it will pass the mouse move events to the listbox.
Best Regards.

Resources