LAMW: Create (sub-)controls on runtime lazarus / 43-Android ---------------------------------------------------------------------- Gerrit · 2016-07-14 01:03 Has anyone tried to create controls on runtime? I try to place a jButton on a jPanel like this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  ajButton:= jButton.Create(jPanel_Work); ajButton.Left:=30; ajButton.Top:=30; ajBu tton.Width:=130; ajButton.Height:=40; ajButton.Text:='ButtonText'; ajB utton.BackgroundColor:=colbrWhite; ajButton.FontColor:=colbrBlack; ajB utton.Parent:=jPanel_Work; jPanel_Work.Invalidate;  // <-- just tried all of that stuff, nothing worked jPanel_Work.Refresh; ajButton.Invalidate; ajButton.Refresh;The ajButton appears to be in jPanel_Work.Components and can also be deleted. But i never see a button on screen, even if i make button/panel visible/invisible/refresh/invalidate/resize and all the stuff. On the other hand, when i make a button a subcomponent of that panel in GUI designer it is shown and behaves like expected, but is not listed in jPanel_Work.Components. Has anyone any idea how i have to add that button dynamically? Is it even possible to create controls on runtime? ---------------------------------------------------------------------- jmpessoa · 2016-07-14 02:25 Please, try: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  ajButton:=jButton.Create(Self); ajButton.LayoutParamWhidth:= lpHalfOfParent; ajButton.LayoutParamHeight:= lpWrapContent; ajButton.PosRelativeToParent:= [rpCenterHorizontal] ajB utton.Text:='ButtonText'; ajButton.BackgroundColor:=colbrWhite; ajButt on.FontColor:=colbrBlack; ajButton.Parent:=jPanel_Work; ajButton.Init( gApp);     // << ----------------  NOTE1: [left,  top, width,height ] has no correspondent in run time .... From "readme_get_start.txt" Quote#Question: How do we can design a layout that shown same in real device? [Answer]: You should use the component properties:       "Anchor",       "PosRelativeToParent",       "PosRelativeToAnchor",       "LayoutParamHeight",       "LayoutParamWhidth" NOTE2. You really need to do so? Maybe you'll need to learn LAMW by code. Welcome! ---------------------------------------------------------------------- Gerrit · 2016-07-14 16:38 Quote from: jmpessoa on July 14, 2016, 04:25:54 amCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  ajButton.Init(gApp);     // << ----------------This did the magic, thanks a lot. QuoteNOTE2. You really need to do so? Maybe you'll need to learn LAMW by code. Welcome!Dunno really know yet what i need to do, still in try & error phase, just starting with lamw. Tried CustomizedControls and Ionic before. Customer's looking for results. ---------------------------------------------------------------------- jmpessoa · 2016-07-14 17:45 Quote... Tried CustomizedControls Well, there is "jCustomDialog", too... come on! Thank you! ---------------------------------------------------------------------- Gerrit · 2016-07-20 22:32 Sorry, but this drives me crazy. I put a lone control on main form, lets say a jTextView1 with PosRelativeToParent=[rpCenterInParent]. It's displayed well in the middle of the screen when running the app. After that i add jTextView2 manually, with Anchor=jTextView1 and PosRelativeToParent=[rpCenterHorizontal] and PosRelativeToAnchor=[raBelow]. It's displayed well in the middle of the screen just below jTextView1. Now i tried this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TAndroidModule1.jButton1Click(Sender: TObject);var ajTextView:jTextView;begin  ajTextView:=jTextView.Create(Self);  ajTextView.PosRelativeToParent:=[rpCenterHorizontal];    // <------- works fine, text is centered  ajTextView.Anchor:=jTextView2;  ajTextView.Text:=ajTextView.Anchor.Text;      // <---- yes it displays "jTextView2", so anchor is set  ajTextView.PosRelativeToAnchor:=[raBelow];     // <---- doesn't work at all, text is on top of the screen  ajTextView.Parent:=Self;  ajTextView.Init(gApp);end; All anchor related positioning doesn't have any effect as long as i create those controls on runtime. But its all fine when they are placed at design time. Any idea or do i have to dig into the whole LAMW code? ---------------------------------------------------------------------- jmpessoa · 2016-07-21 16:32 Hi Gerrit try change the "Parent" to Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   ajTextView.Parent:= AndroidModule1.View; ---------------------------------------------------------------------- Gerrit · 2016-07-21 19:14 Quote from: jmpessoa on July 21, 2016, 06:32:09 pmCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   ajTextView.Parent:= AndroidModule1.View;This crashs the App when touching the button.  Doesn't anyone else create controls at runtime? ---------------------------------------------------------------------- jmpessoa · 2016-07-21 22:23 Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TAndroidModule1.jButton1Click(Sender: TObject);var ajTextView:jTextView;begin  ajTextView:=jTextView.Create(Self);  ajTextView.PosRelativeToParent:=[rpCenterHorizontal];    // <------- works fine, text is centered   if jTextView2.Id = 0 then  //prepare to anchor  begin    jTextView2.Id:= 1212;   //ramdom !!    jTextView_SetId(gApp.Jni.jEnv, jTextView2.jSelf , jTextView2.Id);  // hack!!!  end   ajTextView.Anchor:=jTextView2;  ajTextView.Text:=ajTextView.Anchor.Text;      // <---- yes it displays "jTextView2", so anchor is set  ajTextView.PosRelativeToAnchor:=[raBelow];     // <---- doesn't work at all, text is on top of the screen  ajTextView.Init(gApp);end;  NOTE: the "Parent" is take care by "Init"  when parent is the Form ---------------------------------------------------------------------- Gerrit · 2016-07-22 00:40 Magic. But it's working now, thanks a lot. ---------------------------------------------------------------------- jmpessoa · 2016-07-22 02:32 Ok.  [no magic!] Github fixed!!! Now, this work: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TAndroidModule1.jButton1Click(Sender: TObject);var   ajTextView:jTextView;begin  ajTextView:=jTextView.Create(Self);   ajTextView.PosRelativeToParent:=[rpCenterHorizontal];     ajTextView.Anchor:=jTextView2;  ajTextView.Text:= 'Hello World!';  ajTextView.PosRelativeToAnchor:=[raBelow];   ajTextView.Init(gApp);end;  Thank you! ---------------------------------------------------------------------- Handoko · 2016-07-22 04:02 Please include this info into documentation or tutorials. So others won't repeat same mistakes. ---------------------------------------------------------------------- Gerrit · 2016-08-04 18:00 Quote from: jmpessoa on July 22, 2016, 04:32:45 amNow, this work:My discovery: With one flaw: When generating the controls very fast, there was a strange behaviour where all the controls have been placed on the top again. Crouching through the code i found two Randomize; in androidwidget.pas.jVisualControl.SetAnchor (Line ~2100). Please remove them from the procedure and call Randomize just on initialization (if even - imho it's not really needed because all we want is hopefully unique values, doesn't matter if they are the same on every run). Background: Randomize provides a seed for the random generator, using just the systems time stamp (and nothing else). When called repeatedly very fast it initialises the generator with the same value, leading to the same ID for several controls, letting Android go crazy. For the future: Others have the same problem here and found a solution here, which works up from API 17. Maybe this can be implemented in LAMW. My opinion: Providing an operating system for sixteen releases over millions of devices without providing a simple UID function for some ID is just insane. Someone please slap Google.  For jmpessoa and all the others who contribute to LAMW: Great work, thank you all, this thing is so cool, i owe you. ---------------------------------------------------------------------- Handoko · 2016-08-04 18:31 Thanks you Gerrit for sharing what you've found. I love Google, it really helps me to find good tutorials. But in the same time, I hate it too. ---------------------------------------------------------------------- jmpessoa · 2016-08-04 19:45 @Gerrit QuoteCrouching through the code i found two Randomize...Please remove them from the procedure and call Randomize just on initialization.. OK. Thank you! EDITED: Done. Please, need test in run time component create! ---------------------------------------------------------------------- Gerrit · 2016-08-14 00:00 I got a new issue.  1. create a new GUI project 2. create a jVisualControl (lets say jTextView) at runtime(!) 3. app crashes 4. now go back to designer and put a jTextView manually on the form, restart app 5. now you can create other jTextViews at runtime I've found jTextView.java and a jTextView object in .\src\org\lamw\\Controls.java after adding it  manually in designer. Even after i delete it from GUI i still can create them at runtime from then on. So, i have to add all the controls i want to create at runtime manually at design time. I can live with that, but maybe someone will find a solution, i don't have a clue yet. ---------------------------------------------------------------------- jmpessoa · 2016-08-14 04:03 Quote4. now go back to designer and put a jTextView manually on the form, restart app ... Why? now you get a "jTextView.java" template in  "....\src\org\lamw\" and a  jTextView "create" method in "Controls.java"  and things work again! Quotei have to add all the controls i want to create at runtime manually at design time. I can live with that.... Yes, the "hack way" pay some price!  Quote...but maybe someone will find a solution, i don't have a clue yet... I'll think about it. Have fun EDITED: Go to "JNIAndroidProject.ini"  in folder "lazarus/config" and add this line: CanUpdateJavaTemplate=f This line will break update/delete all ".java", so you can preserve your  templates included "by hand". ---------------------------------------------------------------------- Gerrit · 2016-08-15 23:37 Me again. Another riddle i couldn't solve. Usually i get rid of no longer needed jVisualControls by just freeing them (i.e. jTextView.Free). They disappear and all is fine. This works for jTextView and jCheckBox so far. But not for jSpinner. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TAndroidModule1.jButton_DemoSpinnerClick(Sender: TObject);var aXView:j Spinner;begin aXView:=jSpinner.Create(AndroidModule1); aXView.Name:='j Spinner_1_1'; aXView.PosRelativeToParent:=[rpCenterInParent]; aXView.P arent:=jScrollView1; aXView.Text:='first'; aXView.Add('first'); aXView .Add('second'); aXView.Add('third'); aXView.Init(gApp); //now get rid of it aXView.Free;end;This code just crashes the app. Didn't find a solution today. Any hacks needed here? ---------------------------------------------------------------------- jmpessoa · 2016-08-17 02:36 Yes, you got a "jSpinner.java" Bug! But here is a fix: Code: Java  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   public void jFree() {      if (parent != null) { parent.removeView(this); }    //free local objects...      mStrList = null;       mSpAdapter = null;          lparams = null;      //setOnClickListener(null);      // BUG!      setOnItemSelectedListener(null);   // FIX !!!   } ---------------------------------------------------------------------- Gerrit · 2016-08-17 22:26 Quote from: jmpessoa on August 17, 2016, 04:36:38 amBut here is a fix:Updated ... worked ... thanks.