We have a Delphi 2007 application and have recently enabled MainFormOnTaskBar for better support of Windows Aero. However because the main form would not come to the top of all child forms when clicked we added the following code.
procedure TBaseForm.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
Params.WndParent := 0;
end;
One side effect of this is that when pressing an Alt + key hotkey on a child form that does not handle that particular hot key the main form flicks to the front and then back again. If the hot key is handled then this behavior does not occur, probably because the hotkey is swallowed.
Has anyone else experienced this behavior and can advise a workaround.
Thanks
The observed behavior is the result of VCL's accelerator support for a possible main menu on the main form, so that you can select menu items from the main form's menu even when another form is active.
The activation of the main form takes place by a SetFocus call on the main form's handle while the "Application" is handling the CM_APPSYSCOMMAND message which is sent from the WM_SYSCOMMAND handler of a "WinControl" (secondary form) when command type is SC_KEYMENU (window menu activation - Alt key).
Note that this behavior is not a side effect of using MainFormOnTaskBar and then overriding CreateParams to have forms that can be brought to front. The same behavior occurs regardless of the setting of MainFormOnTaskBar. The only difference is that the activated main form cannot come in front of secondary forms when it is set, but the main form is activated all the same.
You can intercept to modify the behavior in a number of places, like a WM_SYSKEYDOWN handler on the secondary form, or in OnKeyDown of the secondary form. Semantically more correct override, IMO, should be done on the IsShortCut of the secondary form. As you have found out, when the secondary form handles a key combination, the processing of the system key terminates. You can, then, tell the VCL that your form requires the key:
type
TSecondaryForm = class(TForm)
..
public
function IsShortCut(var Message: TWMKey): Boolean; override;
...
function TSecondaryForm.IsShortCut(var Message: TWMKey): Boolean;
begin
Result := True;
end;
Of course you can fine tune to conditionally return true depending on the parameter.
Related
I have TAction with ShortCut key set to BkSp (backspace). I'm trying implementing Back button like in web browser so I need TAction is called in any control except Edit controls (TMemo, TEdit etc.).
All works as expected, but Backspace key is not sent to Edit controls (so user can't delete char).
OnExecute look's like:
if (Screen.ActiveControl is TCustomMemo) or (Screen.ActiveControl is TCustomEdit) then exit;
DoBack;
Any idea to past BkSp key trought TAction to edit control (fo all platforms Win,Mac,Linux)?
Solution is simple, based on Andreas Rejbrand comment and same as in Delphi.
On OnUpdate for action:
procedure TForm1.aBackUpdate(Sender: TObject);
begin
aBack.Enabled := not (Screen.ActiveControl is TCustomEdit);
end;
And OnExecute for action:
procedure TForm1.aBackExecute(Sender: TObject);
begin
DoBack;
end;
Using c++ builder borland (bcb6).
I wish to invoke manually button click event. I did:
FMap->bbDoneInClick(NULL);
While Done button located on the FMap form, but something went wrong with that.
Do I need to call bbDoneInClick with different parameters and not with NULL ?
Instead of NULL use the Form1 or the bbDone itself ...
it depends on the event code itself how it uses the Sender parameter
Also you can call the event handler safely only if the form is already created
if it does not access Canvas you can use it even in TForm1::TForm1 constructor
if it does you need to take care of not using it prior to OnShow or OnActivate
to avoid VCL problems or App crashes
for common handlers it is sufficient to use main window ... (I use this instead of NULL)
if you have single even handler for multiple components then the even is usually deciding the operation or target from the Sender parameter so in that case you need to pass the pointer to component itself
I have a main form and a status form that I display when work is going on in my application. If the work is finished I just call Hide on the status form and the status form disappears.
My problem occurs when I minimize the main form whilst the wait form is visible. Then both forms are hidden which is what I want. However, if the work finishes whilst the main form is minimized then when I restore it, the status form is also restored, even though Hide has been called on it whilst minimized.
Visible seems to be False for the status form when the application is minimized and therefore calling Hide seems to have no effect (the help says it just sets Visible to False).
Are that observations correct? How is the form visibility restored when the application gets focus again? How can I hide my form while the application is minimized?
Visible of the display form is indeed false and calling Hide does nothing when the application is minimized, because it is hidden by the application as part of the minimization mechanism.
Code calls ShowOwnedPopups with first 'False' as 'bShow' while the application is minimizing, and then with 'True' as 'bShow' while the application is restoring. Since the function shows all windows which was hidden by a previous call, changing visibility of a form
in between has no effect.
Now, see this quote from the remarks section of the documentation of the function,
if a pop-up window is hidden by using
the ShowWindow function, subsequently
calling ShowOwnedPopups with the fShow
parameter set to TRUE does not cause
the window to be shown
So, one solution can be to hide the form before the application hides it, so it won't get shown while restoring. But then we have to know if the display form is actually to be hidden or shown when we restore. This can be achieved by putting a property on the display form or with a global variable perhaps. In the below, 'ShouldBeVisible' is a hypothetical property that would return true if we are to display information:
type
TForm1 = class(TForm)
..
private
procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;
...
procedure TForm1.WMSysCommand(var Msg: TWMSysCommand);
begin
if (Msg.CmdType = SC_MINIMIZE) and Assigned(Form2) and Form2.Visible then
Form2.Hide;
inherited;
if (Msg.CmdType = SC_RESTORE) and Assigned(Form2) and Form2.ShouldBeVisible then
Form2.Show;
end;
I now use the following solution which works for me:
In Application.OnRestore restore event handler I call StatusForm.NotifyRestored. Status form is explicitly hidden if it should not be visible.
In my status form I keep track of visibility in a boolean field FShouldDisplay. This is set in methods ShowStatusForm and HideStatusForm.
procedure TMainForm.OnApplicationRestore(Sender : TObject);
begin
StatusForm.NotifyRestored;
end;
procedure TStatusForm.NotifyRestored;
begin
if not FShouldDisplay then
ShowWindow(Handle, SW_HIDE);
end;
procedure TStatusForm.ShowStatusForm;
begin
FShouldDisplay := True;
Show;
end;
procedure TStatusForm.HideStatusForm;
begin
FShouldDisplay := False;
Hide;
end;
Warning: I am not 100 % sure that the following approach is safe.
If you don't need the same form object to be alive for the duration of the application's life (which you most likely do not), then you could try to disable the automatic creation of the popup form (Project/Options) and then create and show it by
Application.CreateForm(TForm2, Form2);
Form2.Show;
and then free it by
Form2.Release;
This way the form cannot possibly be restored together with the main form.
What should I do in order to allow users to navigate through widgets using the Tab key (in either Gtk or any derivative like gtkmm, pyGtk)?
This is build into the default "key_press_event" signal handler. If you set your own handler you must return FALSE from this handler because a TRUE means you have handled the key and no further processing is done. You can use this to avoid the default tabbing.
And i would like to add a question here, because i have no idea how i can do the focus-next-widget, focus-prev-widget action programmatically.
Is tabbing through your controls not working? This should work out of the box as you build up your forms. To customize the order of moving through the widgets as you tab, you use the set_focus_chain methods: gtk, pygtk, gtkmm.
I have a dialog in vb6 which changes the values being displayed in its parent dialog.
The x1 is displayed in txt_c1 text in parent dialog and it has a txt_1validate function too for the text box. Now i want to change the value of txt_c1 txtbox from child dialog and then call its validate function. But the problem is that txt_c1 is not available in child dialog.
Please note that i am working in vb6 in the MS VB 6.0 IDE
Forms are just classes and can therefore be instantiated explictly (and you will probably find your life easier if you do rather than using the automatic instantiation in VB6) and references to forms can be assigned.
You can solve your problem by creating a public property on your child dialog (Form1.frm) of type Form that you set to the instance of the parent dialog thus giving you access to the controls andd methods on the parent from the child.
My VB6 is somewhat rusty (and I don't have an installed instance available) so this isn't going to be actual, correct code - but something along the lines of the following should work
In the code that calls the child:
Form childDialog = new Form1
childDialog.Parent = this
childDialog.ShowModal
Then in the child dialog:
Parent.txt_c1 = newValue
if not Parent.Validate then
...
end if