Image Preview in a Listbox - delphi

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.

Related

how can I lock and hide a FastReport object inspector?

I am using a fastreport report to create a label and then print it. but I need to show the user the TfrxDesigner from code so that they can drag and resize the components in the report's page.
with that being said, I need to lock and hide all the menus and toolbars so that users don't use them.
I don't want to show or let the user use the menus in the red shape on the picture, also the data tree and all those tool bars, only the green ones.
has anyone been there? any help is appreciated, thanks!
You can create a TfrxDesigner instance:
FDesigner := TfrxDesigner.Create(nil);
FDesigner.OnShow := DesignerShow;
with an OnShow handler like this:
procedure TFRHelper.DesignerShow(Sender: TObject);
begin
Assert(Sender is TfrxDesignerForm);
// Change the TfrxDesignerForm as you wish, e.g.:
TfrxDesignerForm(Sender).BorderIcons := TfrxDesignerForm(Sender).BorderIcons - [biMinimize];
TfrxDesignerForm(Sender).OnMouseWheel := DesignerFormMouseWheel;
end;

Vcl Style Utils - Get rid of default form icon

I've already posted this as an issue on RRUZ's Vcl Style Utils library on GitHub. However, I thought I could get some help here too.
I'm using VCL Styles to create a Windows 10 user interface, specifically using the "Windows 10 Dark" style. I'm also using the VCL Style Utils to be able to add buttons to the non-client area in the title bar. I'm attempting to completely disregard the form icon and its default functionality in favor of a back button, just like most new Windows 10 apps do.
I'm trying to place a button in the far upper-left corner of the form, using the TNCControls component in Vcl.Styles.NC. However, when I place a button over the form's icon, the button cannot be clicked in the area of the icon. Although I'm able to overlap the icon, clicking in that particular area of the title bar always opens the form's system menu, instead of clicking the button I've placed there.
I do not wish for this menu to pop up when clicking there:
How I'm currently creating this button:
procedure TfrmTestMain.SetupTitleBar;
var
B: TNCButton;
begin
FNCControls:= TNCControls.Create(Self);
B:= FNCControls.ButtonsList.Add;
B.Style := TNCButton.TNCButtonStyle.nsTranparent;
B.BoundsRect := Rect(0, 0, 45, 32);
B.UseFontAwesome:= True;
B.Caption := '';
B.ImageAlignment:= TImageAlignment.iaCenter;
B.ImageStyle:= TNCButton.TNCImageStyle.isNormal;
B.ImageIndex:= fa_chevron_left;
end;
What I've tried so far:
Replaced the form's Icon with a completely empty .ico file.
Changing form style to bsSizeToolWin, but the title bar becomes too small, and I lose the minimize / maximize buttons.
Changing form style to bsDialog, but I get the same effect as #2 above, as well as not being able to resize the form.
Made sure button style is nsPushButton, and although it covers up the form icon, clicking the area still clicks the icon, which in turn shows the default system menu.
Following everything in this thread, but the conclusion is that Windows forces you to have this icon.
Removed biSystemMenu from the form's BorderIcons property, but this also removes the default buttons in the top-right of the form, forcing me to place my own system buttons there.
How do do I completely eliminate the form icon and its default functionality in favor of my Windows 10 style back button?
The TNCControls component includes the ShowSystemMenu property. If you set the value to false, then the system menu will be not shown.
Try this
uses
Vcl.Styles.Utils.Graphics;
procedure TfrmTestMain.FormCreate(Sender: TObject);
begin
SetupTitleBar;
end;
procedure TfrmTestMain.NCClick(Sender: TObject);
begin
ShowMessage('Hello');
end;
procedure TfrmTestMain.SetupTitleBar;
var
B: TNCButton;
begin
FNCControls:= TNCControls.Create(Self);
FNCControls.ShowSystemMenu := False; //Disable the system menu.
B := FNCControls.ButtonsList.Add;
B.Style := TNCButton.TNCButtonStyle.nsTranparent;
B.BoundsRect := Rect(0, 0, 45, 32);
B.UseFontAwesome:= True;
B.Caption := '';
B.ImageAlignment:= TImageAlignment.iaCenter;
B.ImageStyle:= TNCButton.TNCImageStyle.isNormal;
B.ImageIndex:= fa_chevron_left;
B.OnClick := NCClick;
end;

Delphi XE5 Firemonkey TTabItem and TEdit repaint coordination

I created a TTabControl with two TTabItems. On each TTabItem there is one (or more) TImageViewers and several TEdits. When I click on the TImageViewer, a modal screen pops up, I set some values, and I want to report those values to the user through the TEdits. So on returning from the Modal screen,
I execute
editn.text := whateveritis;
I then say
editn.repaint;
Nothing happens. I say TTabItem.repaint. Nothing happens. I click the other TTabIem and then come back to the first TabItem and, voila, the Edit control contains the right information. So my editn.text := whateveritis must be working (that's the only write to the TEdit), but I can't get the blinkin' control to show the result without going off-tab. How do I get it to redisplay as soon as I change the content? Do I need to write an OnChange routine that is one line, self.repaint? Seems ugly, and I'd hope there's a more global approach. Suggestions?
In light of initial comments, let me give more details. Setup: In main screen, drop in tabcontrol, and in tabcontrol drop in 2 tabitems. In tabitem1, drop in a timageviewer and 4 tedits (plus other stuff, probably irrelevant). Image gets dropped into the imageviewer (and displays correctly). The onclick event activates the following (ellipsis cuts out irrelevant code):
procedure TSCKMain.ImageViewer1Click(Sender: TObject);
var
lochold, scrollhold : tpoint;
backfromwavform : tmodalresult;
begin
lochold.X := mouseloccallback.x;
lochold.Y := mouseloccallback.y;
scrollhold.X := round(imageviewer1.ViewportPosition.X);
scrollhold.Y := round(imageviewer1.ViewportPosition.Y);
…
repeat backfromwavform := Wavform.Showmodal until backfromwavform<>mrnone;
case backfromwavform of
mrOK : begin {blue end}
Specsingle.BlueEnd.X := lochold.X;
Specsingle.BlueEnd.y := lochold.y;
edit13.Text := inttostr(Specsingle.BlueEnd.X);
Edit14.Text := inttostr(Specsingle.BlueEnd.y);
PublicWindowFlag := 'RePlot';
end;
mrContinue : begin {red end}
Specsingle.RedEnd.X := lochold.X;
Specsingle.RedEnd.y := lochold.y;
edit15.Text := inttostr(Specsingle.RedEnd.X);
Edit16.Text := inttostr(Specsingle.RedEnd.y);
PublicWindowFlag := 'RePlot';
end;
…
end;
if PublicWindowFlag<>'Cancel' then
if PublicWindowFlag='RePlot' then
begin
specsingle.RegenImage;
end
else
showmessage('Single image semaphore error. Debug.');
Imageviewer1.scrollto(scrollhold.X-Imageviewer1.viewportposition.X, scrollhold.y-Imageviewer1.ViewportPosition.Y);
end;
The modal screen sends back either mrContinue or mrOK correctly, and the appropriate case executes. However, edit13, edit14, edit15, and edit16 do not change their content. However, if I click over to Tabitem2 and back to Tabitem1, they DO repaint and DO contain the correct characters, which they could only have gotten from the above code. Conclusion: somehow, the edits aren’t repainting independently, but it’s not clear why.
Got it. The canvas for the imageviewer, the canvas for the bitmap in the imageviewer, and the canvas for the parent form are all in play. One must be sure that the canvas is the right one. As soon as scenes got untangled between imageviewer.bitmap and everything else, the edits worked as one would expect.

How to change the ListView OnDrag image?

I'm using a ListView with the ViewStyle := vsReport. When I drag a row from one point to another point it takes the value of column one of the row being dragged (in the case it's 1) and displays it inside a dark grey rectangle as shown below.
I've tried looking around in the XE4 source code but can't find where this background color is set. I'd like to change this background color to clSkyBlue (or something similar) but don't know how it's done.
How do you go about changing the default dark grey background image of the drag operation?
VCL's drag operations does not have drag images out of the box, but it does provide a mechanism for providing a drag image to be used. This is normally done by constructing your own "drag image list", either by overriding the GetDragImages method of the control itself (when an internal drag object is used), or by constructing your own "drag object" when the drag is started, and assemble an image list in its GetDragImages method to be called by the VCL when the drag is initiated.
This mechanism is a bit different though for TListView and TTreeView controls because the underlying api controls themselves natively support providing a drag image for the item that's being dragged. Hence, unlike other controls, these controls override their GetDragImages methods and return the image list that's being created in overriden DoStartDrag methods where the controls ask the api to provide the image list. This is why you won't be able to find where a drag image is created in VCL code.
To override this behavior, one could possibly override these (and possibly a few other) methods in a descendant class and implement them. I don't know if this would be easy or not, I find providing an image list through constructing a drag object in the OnStartDrag event handler easier. This normally does not have any effect, since by the time GetDragImages of our drag object is called, the VCL already has settled on an image list which the api has supplied and the api has created a temporary list that's being dragged. Then, we can force the dragging of the original image list to an end and substitute our own.
Below is an oversimplified example. Apart from error handling, resource protecting, hot spot determining etc.. look to VCL code to see how it ensures there's actually an item that's being dragged.
type
TListWiewDragControlObjectEx = class(TDragControlObjectEx)
protected
function GetDragImages: TDragImageList; override;
end;
function TListWiewDragControlObjectEx.GetDragImages: TDragImageList;
var
Bmp: TBitmap;
R: TRect;
begin
Bmp := TBitmap.Create;
Bmp.Canvas.Brush.Color := clSkyBlue;
R := TListView(Control).Selected.DisplayRect(drBounds);
Bmp.SetSize(R.Right - R.Left, R.Bottom - R.Top);
Bmp.Canvas.Font := TListView(Control).Font;
Bmp.Canvas.TextOut(0, 0, TListView(Control).Selected.Caption);
Result := TDragImageList.Create(Control);
Result.Width := Bmp.Width;
Result.Height := Bmp.Height;
ImageList_EndDrag; // end the drag with the temporary list
Result.SetDragImage(Result.Add(Bmp, nil), 0, 0);
Bmp.Free;
end;
procedure TForm1.ListView1StartDrag(Sender: TObject;
var DragObject: TDragObject);
begin
DragObject := TListWiewDragControlObjectEx.Create(ListView1);
DragObject.AlwaysShowDragImages := True;
end;

Caret position on webbrowser

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;

Resources