I trying to update the existing fields through the forms and click on the SAVE(from the Main Menu), that time i want to show Alerts/Messages 'Do you want to made changes? Yes or No?" Can you please help me, how to use this ? What triggers to use , i set the properties of the Updated Items , Values are getting effected into the Table, But i want a messages please help
I checked all code like :System.Message_Level := '20';
My Database tables data are effected,I don't want any button,i want triggers to save the records
You need to have Key-Commit form level trigger. In that trigger you write logic to show alert. The built in is Show_Alert(), if I remember this correctly. You need to create alerts under Alert(s) node in Forms builder. The alert can have one or up to 3 buttons. Check Show_Alert() in Forms help - Forms Builder -> Help. You can copy paste code from there. It is very easy to figure out. I do not remember exact syntax...
Declare
al_button number;
Begin
IF :System.Form_Status = 'CHANGED' THEN
al_button := Show_alert('SAVE');
IF al_button = alert_button1 THEN
Commit_Form;
END IF;
END IF;
End;
I have written in the KEY-COMMIT Trigger at the Form Level...
Related
I am attempting to use the SetAscending in Visual Studio Code for Business Central Sales Order List Page. It works to set the Sales Order "No." field to descending however it does not reset the scrollbar to the top of the page. I've tried adding it to multiple places and it sorts the page but no scrollbar update. What code could I be missing?
Places I've added it to:
Sales Order List Page Extension - OnAfterGetRecord and OnAfterGetCurrRecord
Sales Order List Page Events - OnOpenPageEvent, OnAfterGetRecordEvent, and OnAfterGetCurrRecordEvent
trigger OnAfterGetCurrRecord()
begin
rec.SetCurrentKey("Document Type", "No.");
rec.SetAscending("No.", false);
end
You must tell the page to navigate to the new first record.
In the OnOpenPage trigger you do the following:
Rec.SetCurrentKey("Document Type", "No.");
Rec.SetAscending("No.", false);
if Rec.FindSet() then; // use if-then to avoid error if there are no records within the filter
You have 3 methods to use as FIND
FindFirst = Find the first ocurrence of your filters
Findlast = Find the last ocurrence of your filters
FindSet = Find a set of ocurrence of your filter
You can use all of them with the repeat and until statements to loop through records.
The difference between FindFirst and FindSet for Repeat and Until is that FindSet find a Set of registers Whilst FindFirst find only one so FindSet it is more performant.
For your case
You need to modify the property sourceTableView. This is a page property. FindSet is used for variables not for DataSourceTable in page list.
Create a key in your table and then put this key in sourceTableView property of the page.
This is what worked for me. Since, this is a standard list page in Business Central I could not modify the SourceTableView. I had to use two triggers to first sort and the move the cursor to the top of the list.
trigger OnAfterGetRecord()
begin
rec.SetCurrentKey("Document Type", "No.");
rec.SetAscending("No.", false);
end;
trigger OnOpenPage()
begin
rec.FindLast();
end;
I was testing answers and reading about this subject on learn.microsoft.com, but the only trick that works is the following:
trigger OnOpenPage()
begin
Rec.SetCurrentKey(SystemCreatedAt);
Rec.Ascending := false;
end;
Note: I'm sorting by a datetime object. But the clues are: OnOpenPage trigger, SetCurrentKey and Ascending property instead of SetAscending. This is the unique solution that leaves the scroll bar on the top, at least for me.
In an application, that uses a TPanel on a "main form", to display other forms, I need to be able not only to display those forms on the TPanel, but also to close and destroy them using controls (buttons) on the main form.
The goal is following - many buttons, each one displaying a specific form on one panel, on the main form. Then, one button, that kills any possible form, that is currently being displayed (= embedded on the panel). Plus, the same closing/killing action should be called every time, when some of the "opening" buttons are triggered, so if some form is being displayed on the panel, it should be replaced by the new form.
To display a form inside the TPanel, I use something like this:
procedure TMainForm.Button1Click(Sender: TObject);
begin
if not assigned(form4) then
form4:= TForm4.Create(Panel2);
form4.Parent:= Panel2;
form4.Show;
end;
Now, to close the window, using another button on the main form, I tried various methods, icluding a CloseWindow method, using handles or pointers etc. The most promissing way, was this:
procedure TMainForm.Button2Click(Sender: TObject);
begin
Panel2.controls[0].Free;
end;
It actually closes the form, but since FreeAndNil is not used, repeated click on the Button1, leads to a nasty series of exceptions, because the form (form4 in this case) has been freed, but the reference to it has not, so the assigned() method returns true and then I try to assign a value to something, that no longer exists with form4.Parent:= Panel2;. An onClose Action:= caFree on the embedded form, does not help either, because the onClose action is not being triggered at all... Placing FreeAndNil(Form4) in onDestroy event of the Form4, also leads to a series of exceptions starting with "Invalid pointer operation".
Using
procedure TMainForm.Button2Click(Sender: TObject);
begin
FreeAndNil(Panel2.controls[0]);
end;
leads to a following error: [dcc32 Error] Unit3.pas(47): E2197 Constant object cannot be passed as var parameter
So what is the correct way to get an instance of the embedded form, to be able to use FreeAndNil(...the form...)? I cannot address it by a name, mainly because I don't know what form is currently being displayed. I need to be able to find an instance of the form based on fact, that it belongs to the TPanel on the main form, and then completely destroy it, so that a second click on the Button1, will display it again, and another click on the Button2, will close and destroy it again.
The key to the solution is Vcl.Forms.TFormClass. From the documentation:
TFormClass is the metaclass for TForm. Its value is the class
reference for TForm or for one of its descendants.
And use it as follows:
First, ditch the FormN global variables from all units that define forms that you will be showing in the panel of the main form. You will not need them and deleting them will prevent you from doing mistakes.
Secondly, in the main form, add a private declaration, CurrentForm: TForm and a private procedure ShowForm
...
private
CurrentForm: TForm;
procedure ShowForm(aFormClass: TFormClass);
...
Because of the aFormClass: TFormClass argument, you can pass in any form type.
Write event handlers for the buttons that should create and show the forms in the panel, similar to this:
procedure TForm25.ShowFormAClick(Sender: TObject);
begin
ShowForm(TForm26);
end;
And write the ShowForm() method:
procedure TForm25.ShowForm(aFormClass: TFormClass);
begin
CurrentForm.Free;
CurrentForm := aFormClass.Create(self);
CurrentForm.Parent := Panel1;
CurrentForm.Show;
end;
Finally also write the event handler for the button that should hide whatever form is currently displayed:
procedure TForm25.ShowNothingClick(Sender: TObject);
begin
FreeAndNil(CurrentForm);
end;
What you're doing wrong
You're completely misunderstanding Delphi's default global form variables. E.g. in this case Form4: TForm4;. (And yet again, I lament the fact that Delphi clings to this horrendous design shortcut.)
Just because Delphi happens to generate this for you doesn't give it any special meaning. You cannot assume it in any way binds to a specific instance of TForm4. And you most certainly shouldn't assume its Assigned status gives any indication how many instances of the form exist. Indeed, as you've noticed, even when Assigned(Form4) = True it's possible the instance that Form4 was referring to has already been destroyed.
To gain a better understanding, experiment with the following:
{Add these to your main form}
FForm4a: TForm4;
FForm4b: TForm4;
FHelloWorld: TForm4;
{Try the following in a button click event
You should see 3 instances of TForm4.}
FForm4a := TForm4(Self);
FForm4b := TForm4(Self);
FHelloWorld := TForm4(Self); {You might not have realised, but the
identifier can be completely different
to the class name.}
FForm4a.Show();
FForm4b.Show();
FHelloWorld.Show();
{In another try}
FreeAndNil(FHelloWorld);
if not Assigned(FHelloWorld) then
ShowMessage('Code explicitly ensured the reference to the form was cleared.');
FForm4b.Free;
if Assigned(FForm4b) then
ShowMessage('If you do not clear the reference, the form variable *remains* assigned.');
{Finally close all TForm4 instances through the UI
(if your form settings allow it), and call the following.}
if Assigned(FForm4a) then
ShowMessage('Form4a is assigned.');
if Assigned(FForm4b) then
ShowMessage('Form4b is assigned.');
if Assigned(FHelloWorld) then
ShowMessage('HelloWorld is assigned.');
So how can you solve your problem?
For a start if you want to know about forms that are on Panel2, check Panel2! Don't waste time checking global variables that have nothing to do with what's on Panel2.
function TMainForm.DoesForm4Exist(): Boolean;
begin
Result := True;
for I := 0 to Panel2.ControlCount-1 do
begin
if (Panel2.Controls[I] is TForm4) then Exit;
end;
Result := False;
end;
You now have a reliable way to check if Panel2 currently has a TForm4 instance. And this should set you on the right path.
Improving the solution
You can make the above code generic so you can reuse it for your other forms. At the same time, you can return a reference to the form, so you interact with it programatically. E.g. to destroy it:
function TMainForm.FindForm(AFormClass: TFormClass): TForm;
begin
Result := nil;
for I := 0 to Panel2.ControlCount-1 do
begin
if (Panel2.Controls[I] is AFormClass) then
begin
Result := TForm(Panel2.Controls[I])
Exit;
end;
end;
end;
{Example using the code to find and destroy a TForm4 instance}
LForm := FindForm(TForm4);
if Assigned(LForm) then LForm.Free;
You can similarly make the form creation generic as per Tom's answer.
Your main problem is, you're trying to solve a problem that doesn't exist. Mainly, you don't need to keep track of the form that is potentially being displayed in the panel and hence you don't have to use FreeAndNil at all.
That is because you can ask the panel anytime what it has got, and since you know what form you are attempting to display when you click a button, you can specifically ask the panel if it has got that kind of specific form.
procedure DisplayFormInPanel(Panel: TPanel; FormClass: TFormClass);
begin
if (Panel.ControlCount > 0) and not (Panel.Controls[0] is FormClass) then
Panel.Controls[0].Free;
if Panel.ControlCount = 0 then
begin
with FormClass.Create(Panel) do begin
Parent := Panel;
Show;
end;
end;
end;
The above procedure gets rid of any possible form that is not of the kind you want to display. If there's already a form that is of the kind that is going to be displayed, then nothing happens - the form stays in the panel.
Call it like:
procedure TForm1.Button1Click(Sender: TObject);
begin
DisplayFormInPanel(Panel2, TForm4);
end;
And your button click handler that closes any form could be as simple as
if Panel.ControlCount > 0 then
Panel.Controls[0].Free;
Regarding the DCC error, there is no point in pursuing that because the reference in the controls array is not the same as the "form4" reference. Even if you could nil that reference, it wouldn't effect "form4" and hence would not help with testing for Assigned. And the reference in the controls array is going to be removed from the controls array as soon as the form is freed anyway.
ControlGet List,List,,DropDownList, Installer Language,English
Control,Choose,1,ComboBox,DropDown
This is the snippet which I am using to read from the dropdownlist and it is not working. Please tell me what is the right snippet to be use here.
Thanks
I'm not sure what you are trying here. This code is something similar to what you require...
Gui, Add, DDL, %chooseMonth% vMonthSelected,January||February|March|April|May|June|July|August|September|October|November|December
It allows you to select Month from the drop down list and stores the selected value in variable chooseMonth
My program has to search through a CSV file line by line and if a unique item is found, another form needs to be opened asking the user for more information on this item to store in a file before continuing to search the CSV file. I have browsed around looking for an answer and the only thing that I can find is showmodal which closes the pop-up form after it's finished. I need to keep the form open in case there is another unique item. I have also tried having a repeat, until loop which repeats until the value of a certain variable is changed by the pop-up form, allowing the program to continue when the pop-up form is hidden. This, however, does not seem to work and causes the pop-up form to be blank and unusable. Help please!
another form needs to be opened asking the user for more information on this item to store in a file before continuing
This is what called "Modal Window"
Hence it is displayed by .ShowModal method.
if ItemFound then begin
user_info := false;
user_prompt := CreateMessageDialog(... 'answer me!' );
try
user_choice := user_prompt.ShowModal();
if IsPositiveResult(user_choice) then begin
user_Var_1 := Trim(user_prompt.Edit1.Text);
user_Var_2 := user_prompt.ListBox1.ItemIndex;
....
user_info := True;
end.
finally
user_prompt.Destroy;
end;
if user_info then begin
...
end;
end;
Read manuals:
http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/Forms_TCustomForm_ShowModal.html
http://delphi.about.com/library/rtl/blrtlCreateMessageDialog.htm
http://docwiki.embarcadero.com/Libraries/XE5/en/Vcl.Dialogs.CreateMessageDialog
The following code is from http://wiki.freepascal.org/MySQLDatabases
procedure TFormTryMySQL.OpenQueryButtonClick(Sender: TObject);
begin
ShowQueryForm := TShowQueryForm.Create(self);
ShowQueryForm.Datasource1.DataSet := SQLQuery1;
SQLQuery1.SQL.Text := CommandEdit.Text;
SQLQuery1.Open;
ShowQueryForm.ShowModal;
ShowQueryForm.Free;
SQLQuery1.Close;
end;
I'm new to Lazarus. Can someone please explain the line ShowQueryForm := TShowQueryForm.Create(self);? I'm particularly curious about:
Why do we need to CREATE a form programmatically?
What is the TShowQueryForm?
My form is without a T. How come the SQLQuery1
control can access the data on the new form?
I'm sorry if this is not a well-phrased question but I AM confused here :(
Thanks!
1. Why do we need to CREATE a form programmatically?
It's optional. You can let forms autocreate, as vfclists says, in which the designer adds the form creation to the LPR. (just like Delphi btw).
2. What is the TShowQueryForm? My form is without a T.
The type of the form. So you have a variable name xxxsomeForm with Txxxsomeform as its specific type.
3. How come the SQLQuery1 control can access the data on the new form?
Other way around. The grids, or whatever db aware controls are in showqueryform get their data from a datasource object. In the 2nd line:
ShowQueryForm.Datasource1.DataSet := SQLQuery1;
the sqlquery component of the current form is assigned to the dataset on the newly created form.
If the form is automatically created in the Project | Forms Auto-Create sas one which is automatically created when the application starts there is no need to create it.
The fact that the form being displayed is a Modal form, means it is like a dialog which is not created automatically, but only on demand.