Avoid mouse right click for edit box - delphi

I want to avoid mouse right click on the edit boxes of my application which I am doing in BDS 2006.
I googled about it and i found a code as follows.
noPopUp := TPopupMenu.create(Edit1);
Edit1.PopupMenu := noPopup;
This is written on form activate. It works fine for edit1, but there are many edit boxes on the form so i wrote a for loop,
for i := 0 to Self.ControlCount-1 do
begin
if Self.Controls[i].ClassName = 'TEdit' then
begin
noPopUp := TPopupMenu.create(Self.Controls[i]);
TEdit(Self.Controls[i]).PopupMenu := noPopup;
end;
end;
This works fine for the edit boxes whose parent is Form. But if there are edit boxes on groupboxes or panels then, these panels and groupboxes in turn children of the form.
So my question is how to disable mouse right click on the edit boxes when the parent is not the form?

This accepted answer allocate unnecessary memory . You can think then it causes memory leaks too, because the created TPopupMenu are never released. But the Create( AOwner) of each TPopupMenu prevent this, releasing this memory on TEdit's Free.
To avoid unnecessary memory alloc, try this:
procedure TForm1.MyContextPopup(Sender: TObject; MousePos: TPoint;
var Handled: Boolean);
begin
Handled := True;
end;
and in the loop:
for i := 0 to Self.ComponentCount-1 do
if Self.Components[i] is TEdit then
TEdit(Self.Components[i]).OnContextPopUp := MyContextPopup;
This is enought to do what you want!
Best regards!

The solution in not that far: substitute control with component, like this
for i := 0 to Self.ComponentCount-1 do
begin
if Self.Components[i].ClassName = 'TEdit' then
begin
noPopUp := TPopupMenu.create(Self.Components[i]);
TEdit(Self.Components[i]).PopupMenu := noPopup;
end;
end;

Related

How to create a non visual component without any icon on the form?

I would like to create a non visual component (like TTimer for example) that I can drop on the form and that I can set up directly from the Object Inspector, but I don't want to see its icon on the form (it'd just obstruct anything). For example TFloatAnimation works like this but I don't understand how.
The GExperts library (http://www.gexperts.org/) has a plug-in which can toggle the visibility
of non-visual components on a form, and it is apparently not Delphi-version-specific but it is
not exactly trivial.
The method which does this is
procedure THideNonVisualCompsExpert.ToggleNonVisualVisible(Form: TCustomForm);
const
NonVisualClassName = 'TContainer';
var
VisibleState: Boolean;
FormHandle: THandle;
CompHandle: THandle;
WindowClass: string;
FirstCompFound: Boolean;
WinControl: TWinControl;
ChildControl: TWinControl;
i: Integer;
begin
Assert(Assigned(Form));
Assert(Form.Handle > 0);
FirstCompFound := False;
WinControl := Form;
if InheritsFromClass(WinControl.ClassType, 'TWinControlForm') then
begin
for i := WinControl.ComponentCount - 1 downto 0 do
begin
if WinControl.Controls[i] is TWinControl then
begin
ChildControl := WinControl.Controls[i] as TWinControl;
if InheritsFromClass(ChildControl.ClassType, 'TCustomFrame') then
begin
WinControl := ChildControl;
Break;
end;
end;
end;
end;
FormHandle := GetWindow(WinControl.Handle, GW_CHILD);
CompHandle := GetWindow(FormHandle, GW_HWNDLAST);
VisibleState := False;
GxOtaClearSelectionOnCurrentForm;
while (CompHandle <> 0) do
begin
WindowClass := GetWindowClassName(CompHandle);
if AnsiSameText(WindowClass, NonVisualClassName) then
begin
if not FirstCompFound then
begin
VisibleState := not IsWindowVisible(CompHandle);
FirstCompFound := True;
end;
if VisibleState then
ShowWindow(CompHandle, SW_SHOW)
else
ShowWindow(CompHandle, SW_HIDE);
end;
CompHandle := GetWindow(CompHandle, GW_HWNDPREV);
end;
end;
in the unit GX_HideNonVisualComps.Pas.
As written, it toggles the visibility of all the non-visual components on the
target form, but looking at the code of the ToggleNonVisualVisible method it looks like it
ought to be possible (but I have not tried) to adapt it to operate on a selected component class and
force instances of the class to a non-visible state. Once you have done that, you would probably
need to experiment with how and when to invoke the method at design-time; if I was doing it, I would probably start
with somewhere like the target component's Loaded method.
(I would feel more comfortable posting this "answer" as a comment but obviously it would be too long)
I have thought about this. A Non Visual Component does not do any painting, in a Windows environment (like the IDE) it has no Window, and therefore cannot influence how the IDE chooses to render it.
One approach would be to derive from TWinControl, making your component a Visual Component, and then to ensure that it is not drawn. Try setting the positioning properties to be non-published, and when you are parented, always set your position outside the parent window. This means that your control is always clipped and never painted.
I haven't tried this, but I can see no reason why it wouldn't work.
You can also use this approach to have an apparently non visual component that renders information in the IDE at designtime, but not at runtime.

Remove a Dynamically Created Panel from Scroll List

Hopefully I can articulate this properly. I have a TScrollBox on a form. I am adding instances of another form to a dynamically created panel that I am adding to the TScrollBox , here is the code I am using to add it.
procedure TSettings.AddWFOnclick(Sender: TObject);
var
dlg : TWFDetail;
panel: TPanel;
i : Integer;
begin
panel := TPanel.Create(self);
dlg := TWFDetail.Create(self);
panel.Parent := WFList;
panel.clientheight := dlg.height;
panel.align := alTop;
panel.Top := 330;
panel.Left := 0;
dlg.Parent := panel;
dlg.align := alClient;
dlg.visible := True;
dlg.Show;
end;
The above works beautifully to add my form and panel. As seen here:
The issue occurs when I try to close the dlg and remove the panel. I don't have any sample code for that. I have tried a dozen different things and can't seem to figure it out. I am closing the form with a close call on the click of the red X, then the panel remains. Seen here:
I need to be able to remove the blank panel and shift everything up. I just can't seem to wrap my head around it since the panel is being created dynamically.
The parenting structure is TScrollBox > TPanel > MyForm
Any help would be appreciated.
You can use an TNorifyEvent on TWFDetail form. Define it:
property OnCloseForm:TNotifyEvent read FOnCloseForm write FOnCloseForm;
When you close the form, fire the event if assigned:
Self.Close;
if Assigned(OnCloseForm) then
OnCloseForm(Self);
When you create the form, assign the OnCloseForm event:
...
dlg.OnCloseForm := CloseForm;
...
And define a simple CloseForm procedure to free the panel that you use to contain the form:
var
pnl:TPanel;
begin
if (Sender is TWFDetail) then begin
if TWFDetail(Sender).Parent is TPanel then begin
pnl := TPanel(TWFDetail(Sender).Parent);
pnl.Free;
end;
end;
end;
There are some other ways to to this, but this work fine.

Firemonkey do stuff in background Form Delphi 10 Seattle

I've created a pop-up loadscreen Form that I want to show above any other form in a Firmonkey Multi device project. Now i've run into the problem that the loadscreen doesn't get updated with the things I do in the background Form. How can I solve this?
In the code below is an example of what i've tried:
procedure TForm1.Button1Click(Sender: TObject);
var
loadScreen:TfrmLoadScreen;
begin
loadScreen := TfrmLoadScreen.Create(nil);
loadScreen.ShowModal(
procedure(ModalResult: TModalResult)
var
i:Integer;
begin
for i := 0 to 200 do
begin
loadScreen.CurrentItem := i;
loadScreen.TextMessage := 'Item:' + loadScreen.CurrentItem.ToString;
Sleep(100);
end;
ModalResult := mrCancel;
end);
end;
I guess I have to do some multi-threading, but I don't have any experience doing this! How should I do this for my loadscreen?
I've also tried the following, but the form doesn't get shown:
procedure TForm1.Button1Click(Sender: TObject);
var
loadScreen:TfrmLoadScreen;
begin
loadScreen := TfrmLoadScreen.Create(nil);
loadScreen.OnShow := FormShowLoadScreen;
loadScreen.Show;
end;
procedure TForm1.FormShowLoadScreen(Sender: TObject);
var
i:Integer;
loadScreen:TfrmLoadScreen;
begin
loadScreen := TfrmLoadScreen(Sender);
for i := 0 to 200 do
begin
loadScreen.CurrentItem := i;
Sleep(100);
end;
loadScreen.Close;
end;
In your first code block, the annonymous method is only called after loadscreen.modalresult is set to something other than 0. This never happens (that we can see)
In your second block, you have 2 different loadscreen instances. They are not the same one. The FormShowLoadScreen handler is called after the firstly loadscreen.show, but it creates a 2nd loadscreen, with it's own displays. In fact, this might happen so fast, you wouldn't see it happen.
You really need to learn more about Delphi multi-threading. To display a "progress" form, you will have to put it's processing (display updates) inside the synchronise event of a separate thread that is started just after the loadscreen form is shown.
Actually... It's actually much easier in FMX to show an animation indicator before starting an annonymous thread, and then hide it again in the thread terminate block.
See Marco Cantu's blog post here Background Operations on Delphi Android, with Threads and Timers

How to display Hints on not active form

I wanna display hint just on mouse move, like in Winamp. No need to have focus on app. Thanks for help.
You can make the hint popup, but I'm not sure if you can do that if the application is not the focussed application.
This will show the hint for anything where the hint is set and ShowHint = True. But only if it is the focusseed Application. (As Sertac Akyuz said in a comment on the original post, VCL only does this for the currently active form).
procedure TForm1.ControlMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
var
aPoint: TPoint;
aControl: TControl;
begin
aControl := TControl(Sender);
if aControl.ShowHint = true then
begin
aPoint.X := X;
aPoint.Y := Y;
if Assigned(aControl.Parent) then
aPoint := aControl.ClientToParent(aPoint);
aPoint := ClientToScreen(aPoint);
Application.ActivateHint(aPoint);
end;
end;
Hope this helps.
There is a way you can detect if mouse cursor position is over some controll by periodically checking mouse cursor position in relation of that controls client rectangle. You can do this using Timer and next code:
procedure TForm4.Timer1Timer(Sender: TObject);
if Panel1.ClientRect.Contains(Panel1.ScreenToClient(Mouse.CursorPos)) then
begin
Form4.Caption := 'Panel1';
end
else if Panel2.ClientRect.Contains(Panel2.ScreenToClient(Mouse.CursorPos)) then
begin
Form4.Caption := 'Panel2';
end
else if Panel3.ClientRect.Contains(Panel3.ScreenToClient(Mouse.CursorPos)) then
begin
Form4.Caption := 'Panel3';
end
else if Panel4.ClientRect.Contains(Panel4.ScreenToClient(Mouse.CursorPos)) then
begin
Form4.Caption := 'Panel4';
end
else Form4.Caption := 'None';
There is probably some better solution by iterating through your forms component list or even better creating your own specific list for this.
Now the only problem is that hint is shown only for active applications. So if you want for hints to be shown even when your application isn't active you will have to make your own hint system (Creating a small form with hint text shown).
Finally it works now. I copied VCL.Forms.pas to project directory
removed there ForegroundTaskCheck like Sertac Akyuz said
var
HintInfoMsg: TCMHintInfo;
{$ENDIF}
begin
FHintActive := False;
HintInfo.ReshowTimeout := 0;
if FShowHint and (FHintControl <> nil) {and ForegroundTaskCheck(EnumAllWindowsOnActivateHint)} and
and most important thing is to add {$B-} in VCL.Forms.pas (without it many AV and crash)
unit Vcl.Forms;
{$B-}

How can I Activate/Focus a Modal Form

I have an application with a TTrayIcon Component that I use to "Hide" and "Restore" my MainForm. Here is what I use to "Hide" (OnTrayClick)
procedure TMainWindow.TrayIcon1Click(Sender: TObject);
var
I : Integer;
begin
if Application.MainForm.Visible then begin
{ Hide }
Application.MainForm.Visible := FALSE;
end else begin
{ Restore }
Application.MainForm.Visible := TRUE;
WindowState := wsNormal;
Application.BringToFront();
{ Workaround for ModalForms }
for I := 0 to Screen.FormCount-1 do begin
if (fsModal in Screen.Forms[I].FormState) then begin
Screen.Forms[I].BringToFront;
Screen.Forms[I].SetFocus;
break; // Stop looking for more ModalForms
end;
end;
end;
end;
This example works just fine if there are no other (Modal) Forms open.
But if there is a ModalForm open and restore my MainForm, the ModalForm seems to be behind the MainForm and I can't reach it. How can I activate/focus the ModalForm and put it in front of my MainForm after my MainForm has been restored? My Application.MainFormOnTaskbar is set to False
EDIT:
If a ModalForm is open and I restore my MainForm, both of the forms won't focus at all.
The setting of MainFormOnTaskbar seems to be causing the problem. You really need to keep that set to true.
You could choose to not hide any forms if there is a modal windows. In that case check for Application.ModalLevel > 0 in your hide code. You could even show a balloon hint stating that the application cannot be minimized until messages are closed.
Otherwise if you really want to minimize all windows the code below works well for me. Hide all of the open windows including the modal window. This will cause the main taskbar icon to go away and everything is off the screen. The one thing you need to do is keep track of which windows were just open. I did that below by setting the Tag value on the forms that were just hidden. Then in the restore code you can set the visible of those windows back to true.
The only case this does not deal with is hiding the main window but leaving the modal window visible. I'm not sure why you would want to do that and personally I would find that confusing as a user.
procedure TForm1.TrayIcon1Click(Sender: TObject);
var
I : Integer;
begin
if Application.MainForm.Visible then
begin
// Hide
for I := 0 to Screen.FormCount-1 do
begin
if Screen.Forms[i].Visible = true then
begin
Screen.Forms[i].Visible := false;
Screen.Forms[i].Tag := 1;
end;
end;
end
else
begin
// Restore
for I := 0 to Screen.FormCount-1 do
begin
if Screen.Forms[i].Tag = 1 then
begin
Screen.Forms[i].Visible := true;
Screen.Forms[i].Tag := 0;
end;
end;
Application.BringToFront();
end;
end;
You may need need to set the PopupParent property on the Modal Form to be your main form. This is set to pmAuto for new forms but if this is an old project it could be pmNone.
Here is a link to a blog post by Allen on PopupMode and PopupParent and here is another Stackoverflow questions that address the topic Newly created modal window loses focus and become inacessible in Windows Vista
I normally use something like this:
MyPopupForm := TMyForm.Create(Owner);
MyPopupForm.PopupMode := pmAuto;
MyPopupForm.PopupParent := Owner;
MyPopupForm.ShowModal;

Resources