I have an abstract Delphi XE form that acts as base class for a family of forms used in my application. I am trying to figure out the best way to make a help function (on F1 keypress) that opens a wiki-page for the active form.
I'd very much like this function to be implemented at base-class level and to call when the user presses F1 but I need some advice on how to do this in a smart way. Currently I just put a KeyDown-event on the base form but this gets overwritten if the subform receives its own KeyDown, at which point I have to manually call the baseKeyDown. Obviously, this is not optimal.. Is there a way to ensure I catch the F1 keypress at baseclass level, random overloads nonwithstanding?
I am running Delphi XE on Windows 7
The straight answer to your question is that a library writer should not assign to event handlers. That's because doing so makes it hard for library consumers to also consume those events. And when you are writing a base class, you are taking the role of the library author.
So, instead of implementing the handler in the OnKeyDown event, override the KeyDown method.
type
TBaseForm = class(TForm)
protected
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
end;
....
procedure TBaseForm.KeyDown(var Key: Word; Shift: TShiftState);
begin
inherited; // this will fire the OnKeyDown event
// your processing for F1 goes here
end;
However, I wonder if you would not be better off using the built in help system. Personally I'd add an OnHelp event for the Application object and place the centralised logic there.
You should override KeyDown method in your base form class.
type
TBaseForm = class(TForm)
protected
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
end;
procedure TBaseForm.KeyDown(var Key: Word; Shift: TShiftState);
begin
// do your processing here
// ...
inherited; // call inherited method that will call OnKeyDown if assigned
end;
This is default implementation of KewDown method that calls OnKeyDown events
procedure TWinControl.KeyDown(var Key: Word; Shift: TShiftState);
begin
if Assigned(FOnKeyDown) then FOnKeyDown(Self, Key, Shift);
end;
Related
my client requested to me for make a "effect" where each time that release any key of keyboard, change this character to asterisk on field.
How do this in Delphi?
I have in Html + Javascript like this. .js code can be found here.
There is no way to achieve what you want with the standard Delphi controls.
The VCL edit control uses the feature of the underlying Windows EDIT control to mask input characters for "Password" type edit controls. The behaviour is therefore determined by the Windows (OS) control, not Delphi itself.
You could try to get the effect you need by using a non-password field and handling key events to replace characters as required with asterisks or any other masking character, but you would also need to separately maintain the intended content of the edit control.
This would almost certainly be easier to implement as a custom edit control, rather than trying to customize the behaviour of a standard edit control with events.
I suspect that the implementation of a custom control is not the solution you are after however.
The below simulates the behavior of the js code with the difference backspace is also handled.
type
TForm2 = class(TForm)
Edit1: TEdit;
procedure Edit1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
procedure Edit1KeyPress(Sender: TObject; var Key: Char);
private
FEditText: string;
procedure TForm2.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
if Key = ^H then
SetLength(FEditText, Length(FEditText) - 1)
else
FEditText := FEditText + Key;
end;
procedure TForm2.Edit1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
Edit1.Text := StringOfChar('*', Length(Edit1.Text));
Edit1.SelStart := Length(Edit1.Text);
end;
FEditText is the equivalent of df[0].Value in js code, the actual value that is typed.
Note that there's no option to reset the text, as there is none in the js code.
I have a project with multiple forms that use TCombobox and i would like to remove the default behavior when a focused combobox receives a Return stroke:
In the Keydown of TCustomCombobox:
vkF4, vkReturn:
DropDown;
Q: How could i remove the functionality for all my forms?
Creating a new custom control that overrides this would mean to much work to recreate all the comboboxes.
A: Make an "imposter" subclass :
Found a Duplicate question : Delphi subclass visual component and use it
I put this code in a unit, and put that unit in the interface/uses of my forms.
TCombobox = class(FMX.ListBox.TComboBox)
protected
procedure KeyDown(var Key: Word; var KeyChar: System.WideChar; Shift: TShiftState);override;
end;
procedure TCombobox.KeyDown(var Key: Word; var KeyChar: System.WideChar;
Shift: TShiftState);
begin
if key=vkReturn then exit;
inherited;
end;
I have inherited a Delphi 7 (VisualCLX) application to maintain and I want to filter some windows message like the mouse wheel (WM_MOUSEWHEEL) on the main form(TForm) of the application, is it possible on the Visual CLX ? How ?
I know that is possible on the VCL, but I'm looking for some solutions on the old Cross-Platform (CLX) ...
Note
I need to disable the mousewheel event because it keeps changing the active page(TPageControl) and this is very annoying in Delphi with Component Library for Cross-Platform (CLX), so any other workaround that solve the problem is welcome ...
Filtering input messages in CLX is not simple. There appears to be nothing like the VCL's OnMessage.
You can stop mouse wheel events being handled by CLX page controls with a simple interposer. Add this code to your main form, before the declaration of your main form class.
type
TPageControl = class(QComCtrls.TPageControl)
protected
function DoMouseWheel(Shift: TShiftState; WheelDelta: Integer;
const MousePos: TPoint): Boolean; override;
end;
And then in the implementation section of the unit, add this:
function TPageControl.DoMouseWheel(Shift: TShiftState; WheelDelta: Integer;
const MousePos: TPoint): Boolean;
begin
Result := True;
end;
If you have a number of page controls on different forms then you should declare the interposer in a unit that can be shared by all the forms in your app. Or maybe even derive a proper grown-up sub-class.
With Delphi Win32 (VCL) I use:
Application.OnMessage := MyAppMessage;
What is the equivalent in FireMonkey?
I have a routine that needs to catch all the keyboard and mouse events in the application (on all the active form controls) and handle them.
I don't know of a way in FireMonkey to capture mouse and keyboard events at the application level in a platform agnostic way. I don't think that has been implemented yet, as of Delphi XE 2 Update 2.
However, by default FireMonkey forms get all of the MouseDown and KeyDown events before the controls do.
If you simply override the MouseDown and KeyDown events on your form, you'll accomplish the same thing.
type
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
private
{ Private declarations }
public
{ Public declarations }
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override;
procedure KeyDown(var Key: Word; var KeyChar: System.WideChar; Shift: TShiftState); override;
end;
{ TForm1 }
procedure TForm1.KeyDown(var Key: Word; var KeyChar: System.WideChar;
Shift: TShiftState);
begin
// Do what you need to do here
ShowMessage('Key Down');
// Let it pass on to the form and control
inherited;
end;
procedure TForm1.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
Y: Single);
begin
// Do what you need to do here
ShowMessage('Mouse Down');
// Let it pass on to the form and control
inherited;
end;
If you want, you can keep going with MouseMove, MouseUp, MouseWheel, MouseLeave, KeyUp, DragEnter, DragOver, DragDrop, and DragLeave.
FireMonkey is cross platform and runs on Windows, Mac OSX, iOS and no doubt many other platforms in due course. Therefore there are no Windows messages exposed by FireMonkey.
Whatever it is you are used to doing with OnMessage in the VCL most likely has an equivalent in FireMonkey. Exactly what that equivalent is depends very much on what your OnMessage handler is trying to achieve.
These answers are fine for exposed events, but for other obscure system events it's more tricky. At the time of writing this link isn't answered:
capturing-usb-plug-unplug-events-in-firemonkey
but it will help with solving the general problem.
I would have posted this as a comment not an answer, but the previous answers were not accepting further comments.
Does anybody know the trick, how to free control inside its event handler ? According delphi help it is not possible...
I want to free dynamicaly created TEdit, when Self.Text=''.
TAmountEdit = class (TEdit)
.
.
public
procedure KeyUp(var Key: Word; Shift :TShiftState);
end;
procedure TAmountEdit.KeyUp(var Key: Word; Shift :TShiftState);
begin
inherited;
if Text='' then Free; // after calling free, an exception arises
end;
How should do to achieve the same effect?
Thanx
The solution is to post a queued message to the control, which it responds to by destroying itself. Ny convention we use CM_RELEASE which is the private message used by TForm in its implementation of the Release method that performs an analogous task.
interface
type
TAmountEdit = class (TEdit)
...
procedure KeyUp(var Key: Word; Shift :TShiftState); override;
procedure HandleRelease(var Msg: TMessage); message CM_RELEASE;
...
end;
implementation
procedure TAmountEdit.KeyUp(var Key: Word; Shift :TShiftState);
begin
inherited;
if Text = '' then
PostMessage(Handle, CM_RELEASE, 0, 0);
end;
procedure TAmountEdit.HandleRelease(var Msg: TMessage);
begin
Free;
end;
The control is destroyed when the application next pumps its message queue.
Before implementing this I would stop and ask "Is this really the best approach?"
Do you really want an edit control class that always destroys itself when key input results in the Text property becoming an empty string?
Is it not more likely to be the case that you have a specific form/dialog where this behaviour is required? In which case, there is no problem... you can free the edit control in the KeyUp event handled by the form without incurring an Access Violation.