Clear TEdit control rad studio delphi - delphi

When use TEdit control on the right side stay small icon 'x'. How after click on icon clear TEdit box.
Tnx all!

Delphi provide TClearEditButton to clear the TEdit content. It can be added by right clicking and selecting AddItem - TClearEditButton from the popup menu. It also has a Click procedure overriden in FMX.Edit unit like:
procedure TClearEditButton.Click;
var
EditTmp: TCustomEdit;
begin
inherited Click;
EditTmp := GetEdit;
if EditTmp <> nil then
begin
if EditTmp.Observers.IsObserving(TObserverMapping.EditLinkID) then
if not TLinkObservers.EditLinkEdit(EditTmp.Observers) then
Exit; // Can't change
EditTmp.Text := string.Empty;
if EditTmp.Observers.IsObserving(TObserverMapping.EditLinkID) then
TLinkObservers.EditLinkModified(EditTmp.Observers);
if EditTmp.Observers.IsObserving(TObserverMapping.ControlValueID) then
TLinkObservers.ControlValueModified(EditTmp.Observers);
end;
end;
Which make you don't need to write OnClick event handler for the TClearEditButton unless you want to do some other job along side with clearing the edit.
If you are using a TEditButton then you should write the OnClick event handler like:
procedure TForm1.EditButton1Click(Sender: TObject);
begin
Edit1.Text:= EmptyStr;
end;

Related

How to make close button open a new form on Delphi

I need that "x" button on any form would not close the form but instead open another 3 random forms on delphi, i have no idea how to do that, please help
Just use the form's OnCloseQuery event to detect the user's trying to close your form (by clicking the close button in the top-right corner, by double-clicking the form's title bar icon, by selecting the Close system menu item, by pressing Alt+F4, etc.).
Then set CanClose to False and instead open your three new forms:
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
CanClose := False;
Form2.Show;
Form3.Show;
Form4.Show;
end;
As suggested by #AndreasRejbrand's answer, you could use the Form's OnCloseQuery event. But, the problem with that approach is that the event is also triggered during system reboot/shutdown, and you don't want to block that. If OnCloseQuery returns CanClose=False during a system shutdown, the shutdown is canceled.
Another option is to use the Form's OnClose event instead, setting its Action parameter to caNone, eg:
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caNone;
Form2.Show;
Form3.Show;
Form4.Show;
end;
However, the best option would to be to handle only user-initiated closures (the X button, ALT-F4, etc) by having the Form handle the WM_SYSCOMMAND message looking for SC_CLOSE notifications, eg:
procedure TForm1.WndProc(var Message: TMessage);
begin
if (Message.Msg = WM_SYSCOMMAND) and (Message.WParam and $FFF0 = SC_CLOSE) then
begin
Message.Result := 0;
Form2.Show;
Form3.Show;
Form4.Show;
end
else
inherited;
end;
This way, system-initiated closures are unhindered.

TListBox Multiselect Style

Is it possible to change the Multiselect behaviour with a standard TListBox?
I would like items to only be multiselected by holding the Ctrl key, not the Shift key.
I have TActions which update depending on items selected, eg:
TAction(Sender).Enabled := ListBox1.ItemIndex <> -1;
The controls assigned to the action flicker when a listbox item is selected when holding shift to multiselect, this does not happen by holding ctrl key only.
So I would like to use only Ctrl key to multiselect.
Simply put, how can I:
Multiselect TListBox
Use Ctrl to multiselect
Shift has no effect
Thanks :)
Item selection is processed by the default window procedure of the underlying list box api control. Because of this there's no VCL property that would do this. Nevertheless, users might not like this, but you can change the behavior by handling WM_LBUTTONDOWN message that is post the the control which triggers item selection. Subclass the control in any way you like. Or, since WM_LBUTTONDOWN is posted, you can use OnMessage event of an ApplicationEvents component. Or, just as one example below, if the control is immediately parented by the form, you can use the notification sent to the parent:
type
TForm1 = class(TForm)
..
private
procedure WMParentNotify(var Msg: TWMParentNotify); message WM_PARENTNOTIFY;
..
procedure TForm1.WMParentNotify(var Msg: TWMParentNotify);
var
Pt: TPoint;
State: TKeyboardState;
begin
if (Msg.Event = WM_LBUTTONDOWN) then begin
Pt := SmallPointToPoint(SmallPoint(Msg.XPos, Msg.YPos));
MapWindowPoints(Handle, ListBox1.Handle, Pt, 1);
if PtInRect(ListBox1.ClientRect, Pt) then begin
GetKeyboardState(State);
State[VK_SHIFT] := 0;
SetKeyboardState(State);
end;
end;
inherited;
end;

Displaying hints

I have added hints to components on my form. When the components receive the focus, I'd like to set the caption of a label component to display the hint.
I have added a TApplicationEvents object and set the OnShowHint event to
procedure TImportFrm.ApplicationEvents1ShowHint(var HintStr: string;
var CanShow: Boolean; var HintInfo: THintInfo);
begin
HelpLbl.Caption := HintStr;
end;
However it seems that the ShowHint event only fires with mouse movements. Is there a way to fire the hint code when components receive focus, without having to implement the OnEnter event for every single component on the form?
Add a handler for TScreen.OnActiveControlChange in your main form's creation, and handle the hints in that event:
type
TForm2=class(TForm)
...
private
procedure ScreenFocusControlChange(Sender: TObject);
end;
implementation
procedure TForm2.FormCreate(Sender: TObject);
begin
Screen.OnActiveControlChange := ScreenFocusControlChange;
end;
procedure TForm2.ScreenFocusControlChange(Sender: TObject);
begin
Label1.Caption := ActiveControl.Hint;
Label1.Update;
end;
Note that Sender won't do you much good; it's always Screen. You can filter (for instance, to only change the Label.Caption for edit controls) by testing the ActiveControl:
if (ActiveControl is TEdit) then
// Update caption of label with ActiveControl.Hint
Note that if you'll need to reassign the event when you show child forms (to an event on that child form), or you'll always be updating the original form's label with the hints. The easiest way to do the reassignment is to give every form an OnActiveControlChange handler, and assign it in the form's OnActivate event and unassign it in the OnDeactivate event:
procedure TForm1.FormActivate(Sender: TObject);
begin
Screen.OnActiveControlChange := Self.ScreenActiveControlChange;
end;
procedure TForm1.FormDeactivate(Sender: TObject);
begin
Screen.OnActiveControlChange := nil;
end;
This will allow you to update controls other than Label1 on each form, and only use the hint changes on forms you want to do so.
A simple solution is to use OnIdle event:
procedure TForm1.ApplicationEvents1Idle(Sender: TObject; var Done: Boolean);
begin
if Assigned(ActiveControl) then
Label1.Caption:= ActiveControl.Hint;
end;
A more advanced solution is to override protected ActiveChanged method of TForm:
type
TForm1 = class(TForm)
...
protected
procedure ActiveChanged; override;
end;
...
procedure TForm1.ActiveChanged;
begin
inherited;
if Assigned(ActiveControl) then
Label1.Caption:= ActiveControl.Hint;
end;
Receiving focus and OnShowHint are quite different events; OnShowHint can be triggered for non-focused control as well.
Why would you need to implement the OnEnter event for every single component? You can create one generic method / event handler like:
procedure TForm1.AnyControlEnter(Sender: TObject);
begin
lbl1.Caption := TControl(Sender).Hint;
end;
and assign it to every component you placed on the form.
You said:
it seems that the ShowHint event only fires with mouse movements
This is a normal behaviour. The problem you have ( it's a guess) is that hints are not fired directly. Don't try to make a workaround, what you try to do with MouseEnter is exactly what is already happening...the only difference is that you'be forget something...
Keep the event ApplicationEvents1ShowHint() as you've initially done but add this in the form constructor event:
Application.HintPause := 1;
And then hints will be displayed (almost) without delay.

How to keep Modal Dialog on top of Dynamic Created Form? (CreateParams - overridden)

I am dynamically creating a Form that overrides the CreateParams so that I can have it displayed on the TaskBar. From the dynamically created Form, I am calling a TColorDialog but once it is displayed my Form will go under the MainForm with the ColorDialog on top of that.
After the ColorDialog is closed the dynamic Form will return back over the MainForm.
I see that on the ColorDialog Execute method there is a Handle that can be passed but I am not sure if I am on the right track with that?
If I click under the Dialog on the MainForm it will flash but how can I have the dynamically created Form "own" this Dialog with the MainForm at the back?
I create the Form like this:
procedure TMain.Button1Click(Sender: TObject);
var
SEMArcF: TWriteSEMArcFrm;
begin
SEMArcF := TWRiteSEMArcFrm.Create(nil);
SEMArcF.Show;
end;
and it is freed on the OnClose Event:
procedure TWriteSEMArcFrm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;
I am overriding the CreateParams like this:
procedure TWriteSEMArcFrm.CreateParams(var Params: TCreateParams);
begin
inherited;
if (FormStyle = fsNormal) then begin
Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
Params.WndParent := GetDesktopWindow;
end;
end;
and to show the ColorDialog I either create it or just have a TColorDialog Component on the Form, either way will result in the same. I want it to be owned by the dynamic Form.
EDIT
I now add:
Application.ModalPopupMode := pmAuto;
The full code:
procedure TWriteSEMArcFrm.btnBackColourClick(Sender: TObject);
var
ColorDlg: TColorDialog;
begin
Application.ModalPopupMode := pmAuto;
ColorDlg := TColorDialog.Create(nil);
try
if ColorDlg.Execute then
re.Color := ColorDlg.Color;
finally
ColorDlg.Free;
end;
end;
This works fine but could there be any unusual behaviour by setting this?
Thank you
Chris
TColorDialog derives from TCommonDialog, which has two overloaded versions of Execute() available - the legacy parameterless version that has existed for years, and a newer overload that takes a parent HWND as an input parameter. You are likely calling the former. That overload uses the Handle property of the currently active TForm (only if the TApplication.ModalPopupMode property is not set to pmNone), falling back to the Handle of the MainForm if needed. If you want more control, you should call the other overload directly instead, then you can pass the dynamic form's Handle property as the parameter value.

How to set a variable if any action is done (in Delphi)?

I need to somehow implement this in Delphi 2009:
The user clicks on button 2. If the user's very last action was clicking on button 1, then I want to do one thing, but if the user's very last action was anything else, I want to do another thing.
Obviously, I set up a boolean variable: UserClickedOnButton1 and set it to true when button 1 is clicked on, and I test that variable in the OnButtonClick event for Button 2.
My question is how do I set that to false whenever anything else is done by the user before clicking on button 2. (e.g. Mouse press, key press, arrow keys, switch to another program, or anything else).
... or is there a simpler way to do this that I am overlooking.
The code below seems to work (D7), but please check this for your specific situation.
type
TButton = class(StdCtrls.TButton)
private
FClickedLast: Boolean;
FNextButton: TButton;
protected
procedure WndProc(var Message: TMessage); override;
public
procedure Click; override;
property ClickedLast: Boolean read FClickedLast write FClickedLast;
property NextButton: TButton write FNextButton;
end;
TForm1 = class(TForm)
...
procedure TForm1.FormCreate(Sender: TObject);
begin
Button1.NextButton := Button2;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if Button1.ClickedLast then
Caption := Caption + ' +'
else
Caption := Caption + ' -';
Button1.ClickedLast := False;
end;
{ TButton }
procedure TButton.Click;
begin
inherited Click;
if (FNextButton <> nil) and Focused then
FClickedLast := True;
end;
procedure TButton.WndProc(var Message: TMessage);
begin
if (FNextButton <> nil) and not (csDestroying in ComponentState) then
case Message.Msg of
CM_CANCELMODE,
WM_KEYFIRST..WM_KEYLAST:
FClickedLast := False;
WM_KILLFOCUS:
if TWMKillFocus(Message).FocusedWnd <> FNextButton.Handle then
FClickedLast := False;
end;
inherited WndProc(Message);
end;
Explanation:
CM_CANCELMODE handles mouse clicks anywhere not resulting in changing focus,
WM_KEY* handles all key events, but also switching to another application (there is a WM_SYSKEYDOWN, otherwise WM_KILLFOCUS takes care),
WM_KILLFOCUS handles everything else.
From what I think; It's not really possible unless you're willing to go and track all (or at least all possibly unwanted) of events with logic.
A key-press (Tab?) can still be valid to move on to the next button and click it; a mouse-down event, obviously is good if it's on the second button, otherwise it's not. You'd probably want to check if the 'first button is clicked' before executing a whole bunch of logic to slow down every keypress/mousedown/lostfocus event in your application.
An idea could be to use a timer, but this doesn't prevent the user from 'quickly' doing something else.
Edt1: If all other actions that are 'illegal' are actually doing something, perhaps a lostfocus event on the first button could be a start?

Resources