Author Topic: Mastering InForm: method to deal with a continuous loop  (Read 2865 times)

0 Members and 1 Guest are viewing this topic.

Offline Qwerkey

  • Forum Resident
  • Posts: 755
Mastering InForm: method to deal with a continuous loop
« on: August 19, 2018, 05:14:47 am »
Today's Problem - How to do a calculation loop whilst still updating in SUB __UI_BeforeUpdateDisplay

Fellippe, in my Trackword program post, you mentioned that any continuous process initiated by a SUB __UI_Click event would not interfere with the ongoing InForm processing in SUB __UI_BeforeUpdateDisplay, thus giving a kind of multithreading which will be what I require for the Gravitation program.

TIMERs are QB64's way of multithreading if you will, which means that even while the calculations are going on in SUB __UI_Click, which was fired by the __UI_EventsTimer, the interface keeps on being updated because __UI_RefreshTimer keeps being fired at ~30fps (or as otherwise set by the SetFrameRate method).

In the Gravitation program, a Click of the Execute button (event CASE ExecuteBT) will initiate a high CPU usage calculation loop.  In the attached program, which will work with the Form already supplied, when the calculation is triggered (a very simple but continuous loop in this trial) the InForm display goes into a freeze mode.

Is there actually a method to deal with a continuous loop (where I imagine the program will "stay" and not get to antywhere else until the loop is finished)?

Code: QB64: [Select]
  1. ': This program uses
  2. ': InForm - GUI library for QB64 - Beta version 7
  3. ': Fellippe Heitor, 2016-2018 - fellippe@qb64.org - @fellippeheitor
  4. ': https://github.com/FellippeHeitor/InForm
  5. '-----------------------------------------------------------
  6.  
  7. ': Controls' IDs: ------------------------------------------------------------------
  8. REM NOTICE: THIS FORM HAS BEEN RECENTLY EDITED
  9. '>> The controls in the list below may have been added or renamed,
  10. '>> and previously existing controls may have been deleted since
  11. '>> this program's structure was first generated.
  12. '>> Make sure to check your code in the events SUBs so that
  13. '>> you can take your recent edits into consideration.
  14. ': ---------------------------------------------------------------------------------
  15. DIM SHARED GravitationSimulation AS LONG
  16. DIM SHARED SimulationTypeFR AS LONG
  17. DIM SHARED BodyDataFR AS LONG
  18. DIM SHARED GravitationalCollapseFR AS LONG
  19. DIM SHARED PictureBox1 AS LONG
  20. DIM SHARED ExitBT AS LONG
  21. DIM SHARED CauseBT AS LONG
  22. DIM SHARED ExecuteBT AS LONG
  23. DIM SHARED SolarSystemRB AS LONG
  24. DIM SHARED BodyManualRB AS LONG
  25. DIM SHARED GravitationalCollapseRB AS LONG
  26. DIM SHARED LoadFromFileRB AS LONG
  27. DIM SHARED DemonstrationRB AS LONG
  28. DIM SHARED GravitationalConstantFR AS LONG
  29. DIM SHARED GravitationalConstantLB AS LONG
  30. DIM SHARED GravitationalConstantTB AS LONG
  31. DIM SHARED Earth&, DispCalc`
  32. CONST Thirty%% = 30
  33.  
  34. ': External modules: ---------------------------------------------------------------
  35. '$INCLUDE:'InForm\InForm.ui'
  36. '$INCLUDE:'InForm\xp.uitheme'
  37. '$INCLUDE:'GravitationSimulation.frm'
  38.  
  39. ': Event procedures: ---------------------------------------------------------------
  40. SUB __UI_BeforeInit
  41.     Earth& = _LOADIMAGE("The Earth.png", 32)
  42.  
  43.     OPEN "temp.txt" FOR OUTPUT AS #1 '!!! Temporary
  44.  
  45.  
  46. SUB __UI_OnLoad
  47.     _SCREENMOVE 0, 0
  48.     '!!! Ought to be able to set these in UIEditor
  49.     Control(BodyDataFR).Disabled = True
  50.     Control(GravitationalCollapseFR).Disabled = True
  51.     DispCalc` = True
  52.     SetFrameRate Thirty%%
  53.  
  54. SUB __UI_BeforeUpdateDisplay
  55.     'This event occurs at approximately 30 frames per second.
  56.     'You can change the update frequency by calling SetFrameRate DesiredRate%
  57.  
  58.  
  59.     IF DispCalc` THEN
  60.         '!!! Temp
  61.         NoBodiesLess1% = 11
  62.         DIM GlobalArray#(NoBodiesLess1%, 3)
  63.         GlobalArray#(0, 3) = 1
  64.         GlobalArray#(1, 3) = 2
  65.         GlobalArray#(0, 0) = 5
  66.  
  67.         'Use local array from global to display only >0 mass bodies in z-dimension order
  68.         DIM LocalArray!(NoBodiesLess1%, 2)
  69.  
  70.         NoVisible% = 0
  71.         FOR N% = 0 TO NoBodiesLess1%
  72.             IF GlobalArray#(N%, 3) <> 0 THEN
  73.                 FOR M%% = 0 TO 2
  74.                     LocalArray!(NoVisible%, M%%) = GlobalArray#(N%, M%%) '!!! Or whatever index value is correct
  75.                 NEXT M%%
  76.                 NoVisible% = NoVisible% + 1
  77.             END IF
  78.         NEXT N%
  79.  
  80.         'FOR N% = 0 TO NoVisible% - 1
  81.         '    PRINT #1, N%, LocalArray!(N%, 0)
  82.         'NEXT N%
  83.         'PRINT #1, ""
  84.  
  85.         IF NoVisible% >= 2 THEN
  86.  
  87.             'Now order visible bodies
  88.             'To order based upon z-dimension
  89.             '!!! NB Here, x- is out of screen, y- is left to right, z_ is botton to top (old coordinate system)
  90.             ' dblA#() is the array used here, not in the calculations routine
  91.             Jump% = 1 'fio To order based upon x-distance: this doesn't seem to slowdown calculation too much.
  92.             WHILE Jump% <= NoVisible% - 1: Jump% = Jump% * 2: WEND
  93.             'Have to do this every time as collisions change NoBodiesLess1%
  94.             WHILE Jump% > 1
  95.                 Jump% = (Jump% - 1) \ 2
  96.                 Finis` = False
  97.                 WHILE NOT Finis`
  98.                     Finis` = True
  99.                     FOR Upper% = 0 TO NoVisible% - 1 - Jump%
  100.                         Lower% = Upper% + Jump%
  101.                         'IF dblA#(intKeep%(Upper%, 3), 1) > dblA#(intKeep%(Lower%, 3), 1) THEN
  102.                         '    SWAP intKeep%(Upper%, 3), intKeep%(Lower%, 3)
  103.                         '    Finis` = False
  104.                         'END IF
  105.                         IF LocalArray!(Upper%, 1) > LocalArray!(Lower%, 1) THEN
  106.                             SWAP LocalArray!(Upper%, 1), LocalArray!(Lower%, 1)
  107.                             Finis` = False
  108.                         END IF
  109.                     NEXT Upper%
  110.                 WEND
  111.             WEND
  112.  
  113.             BeginDraw PictureBox1 'Replace PictureBox1 with the actual ID of the desired PictureBox
  114.             'Drawing code goes here
  115.  
  116.             CLS '!!! Need this if image is (software)
  117.  
  118.             '_DISPLAYORDER _HARDWARE '!!! This doesn't work
  119.  
  120.             IF Caption(CauseBT) = "Cause" THEN
  121.                 _PUTIMAGE (200, 200), Earth&
  122.                 '_MAPTRIANGLE (0, 0)-(260, 0)-(0, 253), Earth& TO(200, 200, -400)-(460, 0, -400)-(200, 453, -400) '261x254
  123.                 '!!! _MAPTRIANGLE(3D) doesn't work in InForm
  124.             END IF
  125.             EndDraw PictureBox1
  126.  
  127.         ELSE
  128.             '!!! Not enough bodies to carry on
  129.             '!!! Or do we do this assessment elsewhere?
  130.         END IF
  131.  
  132.     END IF
  133.  
  134.  
  135. SUB __UI_BeforeUnload
  136.     'If you set __UI_UnloadSignal = False here you can
  137.     'cancel the user's request to close.
  138.  
  139.  
  140. SUB __UI_Click (id AS LONG)
  141.     SELECT CASE id
  142.         CASE GravitationSimulation
  143.  
  144.         CASE ExitBT
  145.  
  146.             CLOSE #1 '!!! Temporary
  147.  
  148.             SYSTEM
  149.         CASE CauseBT
  150.             IF Caption(CauseBT) = "Cause" THEN
  151.                 Caption(CauseBT) = "Effect"
  152.                 Control(SimulationTypeFR).Hidden = False
  153.                 Control(SimulationTypeFR).Disabled = False
  154.             ELSE
  155.                 Caption(CauseBT) = "Cause"
  156.             END IF
  157.  
  158.         CASE ExecuteBT
  159.  
  160.             Control(SimulationTypeFR).Hidden = True
  161.             Control(SimulationTypeFR).Disabled = True
  162.             '!!! And other Frames
  163.  
  164.             DoCalc` = True
  165.             WHILE DoCalc`
  166.                 _LIMIT 3000
  167.                 A# = 2E24 * (3.6 ^ 5)
  168.                 B# = 2345.67 * RND
  169.                 C# = B# * A# / ATN(1)
  170.             WEND
  171.  
  172.         CASE SolarSystemRB
  173.  
  174.             'PRINT #1, Control(SolarSystemRB).Value
  175.             'PRINT #1, Control(BodyManualRB).Value
  176.             'PRINT #1, Control(GravitationalCollapseRB).Value
  177.             'PRINT #1, Control(LoadFromFileRB).Value
  178.             'PRINT #1, Control(DemonstrationRB).Value
  179.  
  180.             'Hidden/NotHidden 11-Body, GravitationalCollapse Input Forms
  181.             IF Control(BodyManualRB).Value = True THEN
  182.                 Control(BodyDataFR).Hidden = False
  183.                 Control(BodyDataFR).Disabled = False
  184.             ELSE
  185.                 Control(BodyDataFR).Hidden = True
  186.                 Control(BodyDataFR).Disabled = True
  187.             END IF
  188.             IF Control(GravitationalCollapseRB).Value = True THEN
  189.                 Control(GravitationalCollapseFR).Hidden = False
  190.                 Control(GravitationalCollapseFR).Disabled = False
  191.             ELSE
  192.                 Control(GravitationalCollapseFR).Hidden = True
  193.                 Control(GravitationalCollapseFR).Disabled = True
  194.             END IF
  195.  
  196.         CASE BodyManualRB
  197.  
  198.             IF Control(BodyManualRB).Value = True THEN
  199.                 Control(BodyDataFR).Hidden = False
  200.                 Control(BodyDataFR).Disabled = False
  201.             ELSE
  202.                 Control(BodyDataFR).Hidden = True
  203.                 Control(BodyDataFR).Disabled = True
  204.             END IF
  205.             IF Control(GravitationalCollapseRB).Value = True THEN
  206.                 Control(GravitationalCollapseFR).Hidden = False
  207.                 Control(GravitationalCollapseFR).Disabled = False
  208.             ELSE
  209.                 Control(GravitationalCollapseFR).Hidden = True
  210.                 Control(GravitationalCollapseFR).Disabled = True
  211.             END IF
  212.  
  213.         CASE GravitationalCollapseRB
  214.  
  215.             IF Control(BodyManualRB).Value = True THEN
  216.                 Control(BodyDataFR).Hidden = False
  217.                 Control(BodyDataFR).Disabled = False
  218.             ELSE
  219.                 Control(BodyDataFR).Hidden = True
  220.                 Control(BodyDataFR).Disabled = True
  221.             END IF
  222.             IF Control(GravitationalCollapseRB).Value = True THEN
  223.                 Control(GravitationalCollapseFR).Hidden = False
  224.                 Control(GravitationalCollapseFR).Disabled = False
  225.             ELSE
  226.                 Control(GravitationalCollapseFR).Hidden = True
  227.                 Control(GravitationalCollapseFR).Disabled = True
  228.             END IF
  229.  
  230.         CASE LoadFromFileRB
  231.  
  232.             IF Control(BodyManualRB).Value = True THEN
  233.                 Control(BodyDataFR).Hidden = False
  234.                 Control(BodyDataFR).Disabled = False
  235.             ELSE
  236.                 Control(BodyDataFR).Hidden = True
  237.                 Control(BodyDataFR).Disabled = True
  238.             END IF
  239.             IF Control(GravitationalCollapseRB).Value = True THEN
  240.                 Control(GravitationalCollapseFR).Hidden = False
  241.                 Control(GravitationalCollapseFR).Disabled = False
  242.             ELSE
  243.                 Control(GravitationalCollapseFR).Hidden = True
  244.                 Control(GravitationalCollapseFR).Disabled = True
  245.             END IF
  246.  
  247.         CASE DemonstrationRB
  248.  
  249.             IF Control(BodyManualRB).Value = True THEN
  250.                 Control(BodyDataFR).Hidden = False
  251.                 Control(BodyDataFR).Disabled = False
  252.             ELSE
  253.                 Control(BodyDataFR).Hidden = True
  254.                 Control(BodyDataFR).Disabled = True
  255.             END IF
  256.             IF Control(GravitationalCollapseRB).Value = True THEN
  257.                 Control(GravitationalCollapseFR).Hidden = False
  258.                 Control(GravitationalCollapseFR).Disabled = False
  259.             ELSE
  260.                 Control(GravitationalCollapseFR).Hidden = True
  261.                 Control(GravitationalCollapseFR).Disabled = True
  262.             END IF
  263.  
  264.     END SELECT
  265.  
  266.  
  267. SUB __UI_MouseEnter (id AS LONG)
  268.     SELECT CASE id
  269.         CASE GravitationSimulation
  270.  
  271.     END SELECT
  272.  
  273. SUB __UI_MouseLeave (id AS LONG)
  274.     SELECT CASE id
  275.         CASE GravitationSimulation
  276.  
  277.     END SELECT
  278.  
  279. SUB __UI_FocusIn (id AS LONG)
  280.     SELECT CASE id
  281.     END SELECT
  282.  
  283. SUB __UI_FocusOut (id AS LONG)
  284.     'This event occurs right before a control loses focus.
  285.     'To prevent a control from losing focus, set __UI_KeepFocus = True below.
  286.     SELECT CASE id
  287.     END SELECT
  288.  
  289. SUB __UI_MouseDown (id AS LONG)
  290.     SELECT CASE id
  291.         CASE GravitationSimulation
  292.  
  293.     END SELECT
  294.  
  295. SUB __UI_MouseUp (id AS LONG)
  296.     SELECT CASE id
  297.         CASE GravitationSimulation
  298.  
  299.     END SELECT
  300.  
  301. SUB __UI_KeyPress (id AS LONG)
  302.     'When this event is fired, __UI_KeyHit will contain the code of the key hit.
  303.     'You can change it and even cancel it by making it = 0
  304.     SELECT CASE id
  305.     END SELECT
  306.  
  307. SUB __UI_TextChanged (id AS LONG)
  308.     SELECT CASE id
  309.     END SELECT
  310.  
  311. SUB __UI_ValueChanged (id AS LONG)
  312.     SELECT CASE id
  313.         CASE SolarSystemRB
  314.  
  315.         CASE BodyManualRB
  316.  
  317.         CASE GravitationalCollapseRB
  318.  
  319.         CASE LoadFromFileRB
  320.  
  321.         CASE DemonstrationRB
  322.  
  323.     END SELECT
  324.  
  325. SUB __UI_FormResized
  326.  
  327.  
  328.  

Richard
« Last Edit: August 24, 2018, 10:48:14 am by odin »

FellippeHeitor

  • Guest
Re: Mastering InForm
« Reply #1 on: August 19, 2018, 10:44:05 am »
Hi Richard,

You just add a call to __UI_DoEvents inside the LOOP that will hog your program for a while. I may have forgotten to mention it in InForm's wiki, sorry about that.

A progress bar is highly recommended here.

Another thing: you'll want a flag to allow the ExecuteBT button to remain unresponsive while calculation takes place so that the action doesn't get inadvertently restarted by the user. And also make the button's .Disabled property = True.

Please check out the mock up program I'm attaching to show what I mean in practice.

Fellippe.
* IntenseCalculator.zip (Filesize: 74.65 KB, Downloads: 269)
« Last Edit: August 19, 2018, 11:30:43 am by FellippeHeitor »

Offline Qwerkey

  • Forum Resident
  • Posts: 755
Re: Mastering InForm
« Reply #2 on: August 19, 2018, 11:29:28 am »
Thank you, Fellipppe.  I see that you have renamed the title to be a general Inform learning exercise.  Noting the standard of your principal student, a better title might have been "Making a Dog's Dinner of Inform".

Making a Dog's Dinner of ... -  British English for a general mess

Richard

Offline Qwerkey

  • Forum Resident
  • Posts: 755
Re: Mastering InForm
« Reply #3 on: August 19, 2018, 12:16:47 pm »
Hi Richard,

You just add a call to __UI_DoEvents inside the LOOP

Yep, that works.  Thank you.

Another thing: you'll want a flag to allow the ExecuteBT button to remain unresponsive while calculation takes place so that the action doesn't get inadvertently restarted by the user. And also make the button's .Disabled property = True.

I expect that the Execute Button will transform into a Stop Button when the simulation is running.

Richard

Offline Qwerkey

  • Forum Resident
  • Posts: 755
Re: Mastering InForm
« Reply #4 on: August 19, 2018, 12:28:59 pm »

I expect that the Execute Button will transform into a Stop Button when the simulation is running.


Ah!  Another Button (in place of the Execute Button) will be required to stop the loop.

FellippeHeitor

  • Guest
Re: Mastering InForm
« Reply #5 on: August 19, 2018, 06:52:19 pm »

I expect that the Execute Button will transform into a Stop Button when the simulation is running.


Ah!  Another Button (in place of the Execute Button) will be required to stop the loop.
You most definitely do not need that extra button. I added it in for good measure, but here's the same program above with StartBT serving both to start and cancel the process. This one never even shows CancelBT (just replace event SUB __UI_Click):

Code: QB64: [Select]
  1. SUB __UI_Click (id AS LONG)
  2.     STATIC DoingIt AS _BYTE 'Flag to indicate a LOOP is being run
  3.  
  4.     SELECT CASE id
  5.         CASE IntenseCalculator
  6.  
  7.         CASE QuitBT
  8.             SYSTEM
  9.         CASE StartBT
  10.             IF NOT DoingIt THEN
  11.                 PrevCaption$ = Caption(StartBT)
  12.                 Caption(StartBT) = "Cancel"
  13.                 Caption(PB) = "Locating stars in observable universe... \#"
  14.                 DoingIt = True
  15.                 Control(PB).Hidden = False
  16.                 Control(PB).Value = 0
  17.                 BeginDraw PictureBox1
  18.                 CLS
  19.                 EndDraw PictureBox1
  20.                 StartTime! = TIMER
  21.                 DO
  22.                     Control(PB).Value = Control(PB).Value + 1
  23.  
  24.                     BeginDraw PictureBox1
  25.                     PSET (RND * _WIDTH, RND * _HEIGHT), _RGB32(RND * 255, RND * 255, RND * 255)
  26.                     EndDraw PictureBox1
  27.  
  28.                     __UI_DoEvents 'This is what you'll want to have in your main loop
  29.  
  30.                     _LIMIT 30 'simulate a loop that takes a good while...
  31.                 LOOP UNTIL DoingIt = False OR Control(PB).Value >= Control(PB).Max
  32.                 Control(PB).Hidden = True
  33.                 Control(StartBT).Disabled = False
  34.                 Caption(StartBT) = PrevCaption$
  35.                 BeginDraw PictureBox1
  36.                 IF DoingIt = False THEN PRINT "Canceled."
  37.                 DoingIt = False
  38.                 PRINT "Seconds since start:"
  39.                 PRINT TIMER - StartTime!
  40.                 EndDraw PictureBox1
  41.             ELSE
  42.                 DoingIt = False
  43.             END IF
  44.         CASE PictureBox1
  45.  
  46.         CASE PB
  47.  
  48.     END SELECT

Offline Qwerkey

  • Forum Resident
  • Posts: 755
Re: Mastering InForm
« Reply #6 on: August 20, 2018, 04:34:54 am »
You most definitely do not need that extra button.

Ah!  Silly Me!  I forgot to make my equivalent of DoingIt STATIC.