Unintended tStringGrid.OnFixedCellClick firing behind tOpenDialog - delphi

I use Delphi Berlin on Windows 10. I need to use tOpenDialog on a tStringGrid based tForm.
When I double click a file which overlaps a fixed column or row on an open dialog onFixedCellClick event fires automatically right after the disapperance of the open dialog. In the following image the file is on the same position of fixed row which is the first line.
type
TForm1 = class(TForm)
StringGrid1: TStringGrid;
OpenDialog1: TOpenDialog;
procedure FormClick(Sender: TObject);
procedure StringGrid1FixedCellClick(Sender: TObject; ACol, ARow: Integer);
procedure FormCreate(Sender: TObject);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
StringGrid1.Options := StringGrid1.Options + [goFixedColClick, goFixedRowClick];
end;
procedure TForm1.FormClick(Sender: TObject);
begin
OpenDialog1.Execute;
end;
procedure TForm1.StringGrid1FixedCellClick(Sender: TObject; ACol, ARow: Integer);
begin
Caption := '';
end;
In most cases I can handle this by moving the dialog window or clicking the file once and clicking open button but I can't guarantee that other people who will use this would do that.
What is the reason and how can I solve this problem?

I believe this is a problem in how TCustomGrid triggers its OnFixedCellClick event on a mouse-up message (in its overriden MouseUp method) without checking if there was a corresponding mouse-down message (FHotTrackCell.Pressed). A quick fix (if you can copy and modify Vcl.Grids): on line 4564 in Berlin (in TCustomGrid.MouseUp method add another condition to check, leading to the call to FixedCellClick):
if ... and FHotTrackCell.Pressed then
FixedCellClick(Cell.X, Cell.Y);
In other words, don't call FixedCellClick if a mouse-up comes without a prior corresponding mouse-down.

Related

Firemonkey Form always restores to wsNormal

I don't know if this could be a BUG or just some configuration.
By setting the form to WndowState = wsMaximized and pressing Windows+D (Show Desktop), when the form is restored from the taskbar the WindowState changes to WndowState = wsNormal.
This only happens in Firemonkey, in VCL it doesn't.
Would there be any solution to keep the form always in wsMaximized?
I think this ought to be reported as a bug.
But I think I have a workaround to this. When the form is hidden the OnDeactivate event is fired. Of course that is also fired if another form takes the focus. But if SetBounds() is then called without OnActivate being fired first, as far as I've been able to tell, this only happens when the form is being shown again from the Show Desktop state.
So this code seems, from the testing I've done, to resolve the issue:
type
TForm1 = class(TForm)
procedure FormActivate(Sender: TObject);
procedure FormDeactivate(Sender: TObject);
private
WasMaximised: Boolean;
public
procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
procedure TForm1.FormActivate(Sender: TObject);
begin
WasMaximised:=False;
end;
procedure TForm1.FormDeactivate(Sender: TObject);
begin
WasMaximised:=WindowState=TWindowState.wsMaximized;
end;
procedure TForm1.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
begin
inherited;
if WasMaximised then begin
WasMaximised:=False;
WindowState:=TWindowState.wsNormal;
WindowState:=TWindowState.wsMaximized;
end;
end;

How do I detect if a floating control is closed?

In a Delphi program I use ManualFloat to show a TPanel containing a Frame as a floating window for displaying extra information about a selected item. This window is shown/hidden using a checkbox, however if the user closes the floating control using the X on the dock window that Delphi automatically creates, there does not seem to be an event I can hook into to change the state of the checkbox. Does anyone know how this would be accomplished?
You can hook into the OnClose event of the floating dock, provided the floating dock has an OnClose event. By default it has. It's of type TCustomDockForm which is a descendant of TCustomForm. But technically it can be a descendant of TWinControl. If you, for some reason, change the class of the floating dock to something that wouldn't descend from TCustomForm, you may need to tweak this answer.
OnClose event of TCustomDockForm is not published. Hence you would need to use a protected hack to access the event. If you use your own class for the floating dock as in the below sample, you can extend functionality should the need arise.
type
TForm1 = class(TForm)
Button1: TButton;
Panel1: TPanel;
...
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
procedure FloatingDockClose(Sender: TObject; var Action: TCloseAction);
end;
...
type
TMyDockForm = class(TCustomDockForm)
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Panel1.FloatingDockSiteClass := TMyDockForm;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Panel1.ManualFloat(Rect(200, 200, 420, 280));
// now we have a floatin dock
TMyDockForm(Panel1.HostDockSite).OnClose := FloatingDockClose;
end;
procedure TForm1.FloatingDockClose(Sender: TObject; var Action: TCloseAction);
begin
CheckBox.Checked := False;
end;

How to hide caret in Delphi TEdit?

I want to remove the caret from a TEdit control in Delphi. I have made the component Enabled := False but the caret still appears.
My question is how to remove the caret from a disabled TEdit control?
I assume that you mean TEdit control.
The solution is HideCaret function, the only problem is where to call it. The 2 event handlers below worked fine for me:
procedure TForm18.Edit1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
HideCaret(Edit1.Handle);
end;
procedure TForm18.Edit1MouseEnter(Sender: TObject);
begin
HideCaret(Edit1.Handle);
end;
Place a TApplicationEventscontrol on the form and in the OnIdle event, hide the caret, as follows. Set the event to nil so it only fires once.
procedure TFormMain.AppEventsIdle(Sender: TObject; var Done: Boolean);
begin
AppEvents.OnIdle := nil;
HideCaret(Memo1.Handle);
end;

How can I trigger an event when the mouse leaves my control?

How do I create an OnMouseLeave event?
Another alternative to the Andreas solution, is use the CM_MOUSELEAVE VCL Message which is already defined in delphi 7.
check this sample using a interposer class for the TButton
type
TButton = class(StdCtrls.TButton)
private
FOnMouseLeave: TNotifyEvent;
procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
protected
property OnMouseLeave: TNotifyEvent read FOnMouseLeave write FOnMouseLeave;
end;
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
procedure FormCreate(Sender: TObject);
private
procedure ButtonMouseLeave(Sender: TObject);
public
end;
//handle the message and call the event handler
procedure TButton.CMMouseLeave(var Message: TMessage);
begin
if (Message.LParam = 0) and Assigned(FOnMouseLeave) then
FOnMouseLeave(Self);
end;
procedure TForm1.ButtonMouseLeave(Sender: TObject);
begin
//your code goes here
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
//assign the event
Button1.OnMouseLeave:=ButtonMouseLeave;
end;
You can tell Windows to post you a message, more specifically a WM_MOUSELEAVE message, when the mouse leaves the control. To do this, call the TrackMouseEvent function. In the TRACKMOUSEEVENT structure, specify the TME_LEAVE flag.
On request, some code:
When the control has been created, and the mouse is inside the client area of the control, tell Windows that you want to be notified about the mouse leaving the control:
procedure TMyControl.SetMouseEvent;
var
tme: TTrackMouseEvent;
begin
tme.cbSize := sizeof(tme);
tme.dwFlags := TME_LEAVE;
tme.hwndTrack := Self.Handle;
TrackMouseEvent(tme);
end;
Call this procedure when the control has been created and the mouse is inside the control. Now you just have to listen to the WM_MOUSELEAVE mesage. In your WndProc procedure (a protected member of the class), add a WM_MOUSELEAVE case.
procedure TMyControl.WndProc(var Message: TMessage);
begin
inherited;
case Message.Msg of
WM_MOUSELEAVE:
beep;
end;
end;
I think that Windows removes the notification request when a message has been created, so you have to rerequest the notification when you have recieved a message. You cannot call SetMouseEvent in the WndProc, because the mouse needs to be inside the client area of the control when you call TrackMouseEvent. I think you could place your SetMouseEvent inside the OnMouseMove of the control:
procedure TMyControl.WndProc(var Message: TMessage);
begin
inherited;
case Message.Msg of
WM_MOUSELEAVE:
beep;
WM_MOUSEMOVE:
SetMouseEvent;
end;
end;
I haven't tested the code above myself, because I use a newer version of Delphi, Delphi 2009, which does things like this behind the scenes (I think, because there is now a OnMouseLeave event in controls), and I think that will interfere.

Open / save file dialog set focus to the file list view

is it possible to open TOpenDialog, TSaveDialog with focus set to the file list view instead of file name edit box ?
Thanks a lot
Regards
You can put the focus to the control you like but the dialog should be ready when you do that. The 'OnShow' event is early for that. You can use 'OnFolderChange' event for instance, together with a flag in order to not to change the focus every time the folder is changed:
type
TForm1 = class(TForm)
Button1: TButton;
OpenDialog1: TOpenDialog;
procedure OpenDialog1FolderChange(Sender: TObject);
private
FDlgSetFocus: Boolean;
uses
dlgs;
procedure TForm1.Button1Click(Sender: TObject);
begin
FDlgSetFocus := False;
OpenDialog1.Execute;
end;
procedure TForm1.OpenDialog1FolderChange(Sender: TObject);
begin
if not FDlgSetFocus then
windows.SetFocus(GetDlgItem(GetParent((Sender as TOpenDialog).Handle), lst2));
FDlgSetFocus := True;
end;

Resources