Does anyone of you know how to clear back all the data that I have insert in TEdit field in a form after I click submit button?
I have a button "save" and after I click on this button, some message will appear like " the data have been saved". At the same time, I want the TEdit field clear from all the data that I have insert before this.
The show message appear but the TEdit field remain the same.
I don't know how to make this happen.
The following code snippet will reset the Text value of all TEdit objects (and other descendants of TCustomEdit, such as TLabeledEdit, TMaskEdit or TMemo) found on the form. Thus, after pressing the "Save" button, the entire screen will be cleared.
Additionally you can use DB objects for this. Thus, the relevant fields will be reset automatically after the Append/Post operation. Another recommendation is that if the screen will close after the "Save" button, the free agent of the relevant form will reset all objects again. You will need to create that form while opening it, and you need to send it to the "Available forms" side from Project -> Options -> Forms so that it does not auto-create.
procedure TForm1.Button1Click(Sender: TObject);
var
I: Integer;
begin
for I := 0 to Self.ComponentCount - 1 do
begin
if Self.Components[I] is TCustomEdit then
begin
(Self.Components[I] as TCustomEdit).Text := '';
end;
end;
end;
Related
In a search form I have two components, a TEdit and and TDBGrid. The user enters text into the TEditand in the TEdit.OnChange event I search for matching items in a table using a query. These are displayed in a TDGrid. The event only triggers when the user has entered more than three characters in the TEdit.Textto cut down the overhead.
The problem occurs when the search has returned all possible records and the user wants to select one of the records displayed in the TDBGrid. While I told the users to use the Tab key (or the mouse) to switch from the TEdit to the TDBGrid, they use the return key to do this in another application and are insisting that they should be able to do the same thing in the application I'm altering/adding to. I can understand this, but the problem is that if I use
if (key = VK_RETURN) then key := VK_TAB;
in the TEdit.OnKeyUp event, the original value of the last key pressed in the TEdit is "remembered" as VK_RETURN and is passed to the TDBGrid's OnKeyUp event. Since I have other actions triggered in that event, I get undesired things happening as soon the the TDBGrid gains focus because they also want to select the correct row in the grid by pressing the return key again.
Therefore what I want to do is to "cancel" the key value passed to the TDBGrid from the TEdit. I tried using if (Sender = TEdit) then Key := VK_CANCEL; in the DGBrid's OnKeyUp event but I get a compiler "Incompatible types" error and I can't find anything to tell me how I should use it in this situation.
Is this possible? Or am I going about this the wrong way?
Thanks in advance!
I believe the following approach satisfies your needs and I suspect it to be the shortest such approach:
procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
if Key = #13 then
Key := #0;
end;
procedure TForm1.Edit1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
if Key = VK_RETURN then
begin
PostMessage(Handle, WM_NEXTDLGCTL, 0, 0);
Key := 0;
end;
end;
This will make Enter, in Edit1, move focus to the next control. This is accomplished by posting the form a WM_NEXTDLGCTL message. The OnKeyPress handler is needed to suppress the "invalid input" message beep.
For bonus points, do
PostMessage(Handle, WM_NEXTDLGCTL, Ord(ssShift in Shift), 0);
instead to have Shift+Enter correspond to Shift+Tab.
I'm not quite sure I like this entire idea, though. I think I prefer to have Enter act on key down instead. The target control shoudn't care about this key up message.
Just to add to Andreas answer, I have used the same approach. There are 3 events you can play around with, onkeydown, onkeypress, onkeyup. At some point you will probably have to assign the key to null to avoid the "beep". The other thing to watch out for are unintended side effects, like moving 2 fields instead of one as has happened to me in the past.
I have a modal form (A) that shows another modal form (B). B displays a dataset and allows the user to interact with it. My problem is that one action requires that A becomes again the focused form so the user can input certain values without closing B. I have tried A.BringToFront and A.SetFocus and it indeed is shown at front, but the input focus remains in B and any click or the like in A results in the windows "ding" when you click where you should not. The code is some how like
A.ShowModal;
.
.
. inside an event of A:
B.ShowModal();
.
.
. inside an event of B:
someobject.someMethodThatRequiresAFocused;
My guess is that some obscure and strange API call could make A modal again ¿Any ideas?
Regards
When a modal form is shown, all currently visible forms including other modal forms are disabled. As such, it is not possible to switch between multiple modal forms. You need to re-think your UI design so that B does not go back to A for new input. At the very least, you could have B open a new modal form C that prompts the user for just the needed values and gives them to B, and then either B or C can update A with the new values afterwards.
There's no API that toggles modality between windows. In any case the API you're looking for your case is EnableWindow. That's how modality works, windows other than the one that the user should be working with are disabled so that he/she cannot interact with them. This is also the reason for the 'ding' sound, to provide feedback to the user.
So while letting the user work with a window that's been disabled in favor of another modal window is technically easy, handling states may not be straight forward. I present a bare minimum example below for what it would seem to take.
'FormB' first. Lets suppose you pass a reference of 'FormA' in the 'Owner' parameter while 'FormA' is constructing 'FormB'. The below is what the code that should make 'FormA' modal again could look like:
procedure TFormB.BtnMakeFormAModalAgainClick(Sender: TObject);
begin
Enabled := False; // so that 'A' will behave like it's modal
EnableWindow(TFormA(Owner).Handle, True); // so that 'A' could be interacted
TFormA(Owner).SetFocus;
end;
When this code runs, what happens is 'FormA' is enabled and brought to front, and 'FormB' is disabled - will produce a 'ding' when clicked on.
But we're not done yet. Because we have modified the meaning of modality - now we don't want 'FormA' to be closed when the user is done with it. Below is how could the code in 'FormA's unit could look like:
type
TFormA = class(TForm)
BtnShowModalB: TButton;
BtnOk: TButton;
procedure BtnShowModalBClick(Sender: TObject);
procedure BtnOkClick(Sender: TObject);
private
FModalB: TForm;
end;
implementation
uses
unitOfFormB;
{$R *.dfm}
procedure TFormA.BtnShowModalBClick(Sender: TObject);
begin
FModalB := TFormB.Create(Self); // so that FormB can find FormA from the Owner
FModalB.ShowModal;
FModalB.Free;
FModalB := nil; // Need this if we're going to decide if FormB is showing
// by testing against this reference
end;
procedure TFormA.BtnOkClick(Sender: TObject);
begin
if Assigned(FModalB) then begin // is FormB the actual modal form?
EnableWindow(Handle, False); // disable this form so it would 'ding'
FModalB.Enabled := True; // enable FormB, so user can interact with it
FModalB.SetFocus;
ModalResult := mrNone; // don't close, FormB is the first one to be closed
end else
ModalResult := mrOk;
end;
I'm nearly positive that this example is not complete, but here's the API that you're looking for.
I'm writing a touchscreen enabled application in Delphi XE2.
I have a form with TEdits. When I click on them, I call the procedure I've written to show another maximized always on top form with a TTouchkeyboard with a label (for caption) and a TEdit for keyboard input.
My procedure (vkeyboard is my form name with the TTouchkeyboard):
procedure TLogin.showkeyboard(numeric,password: Boolean;
caption,value:string;Sender:TObject);
begin
if numeric then
vkeyboard.TouchKeyboard1.Layout := 'NumPad' // make the TTouchkeyboard on the form numeric or alpha
else
vkeyboard.TouchKeyboard1.Layout := 'Standard';
if password then
vkeyboard.input.PasswordChar := '*' //make the TEdit show * or normal characters
else
vkeyboard.input.PasswordChar := #0;
vkeyboard.title.Caption := caption;
vkeyboard.input.Text := value;
vkeyboard.Show;
end;
I'm trying to send Form1.Edit1 object to the form vkeyboard but i don't know how to do it properly!
Why? Because i want to be able to click Done on the input form (vkeyboard) then trace back who was the sender then update the text in the main form edit!
procedure Tvkeyboard.sButton1Click(Sender: TObject);
begin
(temp as TEdit).Text := input.Text; // send back the text to the right object
vkeyboard.Hide;
end;
This little part of course didn't work... I think i need to specified that the temp object belong the X form ?
To be clear, i want to trace back who called the procedure or at least be able to specified it in the procedure and then return back the text (from the 2nd form to the main one) to the right TEdit!
You're welcome to pass whatever arguments you want to whatever function you want. If you need to use the passed value in yet another function, you'll need to save it somewhere so the later function can still access it.
Using your example, you appear to have provided a Sender parameter for your showkeyboard function. I assume that's where you're passing a reference to the TEdit control that triggered the keyboard to show. The Tvkeyboard object stored in vkeyboard will need to use that value later, so give a copy of that value to the Tvkeyboard object. Declare a TEdit field:
type
Tvkeyboard = class(...)
...
public
EditSender: TEdit;
Then, in showkeyboard, set that field:
vkeyboard.EditSender := Sender;
Finally, use that field when you set the text:
procedure Tvkeyboard.sButton1Click(Sender: TObject);
begin
EditSender.Text := input.Text; // send back the text to the right object
Self.Hide;
end;
Since you know it will always be a TEdit control, you can change the type of the Sender parameter in showkeyboard to reflect that specific type:
procedure TLogin.showkeyboard(..., Sender: TEdit);
I have created one form in delphi 7 and added one combobox on it. The combobox contains the list of items. I dont want that user can enter the value to Combobox so i have set
combobox.style := csDropDownList;
But thorugh code i want to use combobox.text := 'New Item'; but its not working. Note that the text I want to show is not in the list of items and I don't want to add it there. Please is any solution to this?
No, this is simply not the way the Windows combobox control works.
However, if you insist, and you don't care that your users will get confused, you can set Style to csDropDown and then do
procedure TForm1.ComboBox1KeyPress(Sender: TObject; var Key: Char);
begin
Key := #0;
end;
as the combobox' OnKeyPress event. Then the user cannot enter text manually, but can only choose from the items in the list. However, you can still set the text to anything you like (even if it isn't in the list) by setting the Text property:
ComboBox1.Text := 'Sample';
Set the ItemIndex property. You can get ComboBox.Items.IndexOf('New Item') to get the index of that text, if you don't already know it.
Combobox.ItemIndex := Combobox.Items.IndexOf('New item');
Below sample code demonstrates how you can draw custom text in response to a WM_DRAWITEM message sent to the ComboBox control's parent window (this should be the form for the sample to work, otherwise subclassing controls or full drawing of items of the control would be necessary).
To receive this message set the Style property of the control to 'csOwnerDrawFixed', but do not put a handler for the OnDrawItem event so that default drawing should be applied in all other cases that we intervene drawing.
The sample sets a text when ItemIndex is -1, but it can be adapted/tweaked otherwise. Note that the drawing code is not complete or accurate, the sample just demonstrates a way how it can be done:
type
TForm1 = class(TForm)
ComboBox1: TComboBox;
[..]
private
procedure WMDrawItem(var Msg: TWMDrawItem); message WM_DRAWITEM;
end;
[...]
procedure TForm1.WMDrawItem(var Msg: TWMDrawItem);
var
Font: HFONT;
begin
inherited;
if (Msg.Ctl = ComboBox1.Handle) and (Msg.DrawItemStruct.itemID = $FFFFFFFF) and
((Msg.DrawItemStruct.itemAction and ODA_DRAWENTIRE) = ODA_DRAWENTIRE) then begin
Font := SelectObject(Msg.DrawItemStruct.hDC, ComboBox1.Canvas.Font.Handle);
SelectObject(Msg.DrawItemStruct.hDC, GetStockObject(DC_BRUSH));
if (Msg.DrawItemStruct.itemState and ODS_SELECTED) = ODS_SELECTED then begin
SetDCBrushColor(Msg.DrawItemStruct.hDC, ColorToRGB(clHighlight));
SetBkColor(Msg.DrawItemStruct.hDC, ColorToRGB(clHighlight));
SetTextColor(Msg.DrawItemStruct.hDC, ColorToRGB(clHighlightText));
end else begin
SetDCBrushColor(Msg.DrawItemStruct.hDC, ColorToRGB(clWindow));
SetBkColor(Msg.DrawItemStruct.hDC, ColorToRGB(clWindow));
SetTextColor(Msg.DrawItemStruct.hDC, ColorToRGB(clWindowText));
end;
FillRect(Msg.DrawItemStruct.hDC, Msg.DrawItemStruct.rcItem, 0);
TextOut(Msg.DrawItemStruct.hDC, 4, 4, '_no_selected_item_', 18);
SelectObject(Msg.DrawItemStruct.hDC, Font);
end;
end;
I think you want the normal thing, to display something in the ComboBox when no selection has yet been made. Instant of a blank rectangle. Imagine a form full of blank comboboxes... ;)
What I've seen most programmers do is have the first item as the title to display in the ComboBox.
So, in FormCreate (after you've populated the ComboBox), you set its ItemIndex to 0, and this displays the title.
In its OnChange event you can choose to take no action if item 0 is selected ("real" items then have base 1 for index), or get ItemIndex-1 and skip action if < 0.
Must be a super common complaint from everyone who has used Comboboxes the first time. I can't understand how none of the coders recognize it.
All Borland et al would have had to do was to initialize a new ComboBox with ItemIndex=0 and the confusion would have been gone. It's certainly not obvious that you have to set index 0 - since you see the blank line when clicked, the logical conclusion is that it has index 0. Probably they wanted to give designers the option to add a label outside the combobox instead.
In one part of the application I'm working on, there is a form control that does validation on reception of the CMExit message, which is exactly how the Delphi documentation says to do it (this code sample is from the Delphi Help files):
procedure TDBCalendar.CMExit(var Message: TWMNoParams);
begin
try
FDataLink.UpdateRecord; { tell data link to update database }
except
on Exception do SetFocus; { if it failed, don't let focus leave }
end;
inherited;
end;
The purpose of this is to perform the validation as soon as the control loses focus. So, for example, if I were to click on the OK button, the form control would lose focus, this method would run and on an exception would set the focus back to that form control. (Thus the "click" event on the OK button would never go through and the dialog would never close).
The problem I'm having is that this form control is inside a modal dialog window. Clicking OK does indeed send the CMExit message and causes the record to update (and validation to occur). However, pressing Enter while in the form control causes the modal dialog to close without sending the CMExit message. It's as if the form control never "loses focus". This means that not only does the dialog close without the form actually validating the data, but the data set isn't updated, either.
Given this problem, where is the best place for me to place my dataset updating/validation code? I could move it up to the dialog form itself and implement it in the OnCloseQuery handler, but this would mean that the logic is duplicated in both the form control and on the form itself. (The form control is used in other places, and I want to avoid changing its behaviour).
(I speculate that CMExit isn't triggered because the control never actually does lose focus. The form is closed, but the form control still "has focus" on the closed form.)
Closing a form does not necessarily fire the on-exit event of a TControl. The user could hit Alt-F4, for example.
I'd suggest moving the validation to a separate proc, and call that separate proc from both the on-exit and on-close events.
The below code should work without too much modification:
function TDBCalendar.UpdateSuccessful: boolean;
begin
{ tell data link to update database }
{ if successful, return True, else return False }
{ this function must be Public if a form is gonna check this value }
Result := True;
try
FDataLink.UpdateRecord;
except on Exception do
Result := False;
end;
inherited;
end;
procedure TDBCalendar.CMExit(var Message: TWMNoParams);
begin
//if not valid, then don't let them leave
if not(UpdateSuccessful) then begin
SetFocus;
end;
end;
///////////////////////////////////////////
//on the form that contains your control...
///////////////////////////////////////////
procedure TMyForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
//if not valid, then don't let them close the form
if not(dbcal.ControlIsValid) then begin
Action := caNone;
end
else begin
inherited;
end;
end;