Page 1 of 2

===>> Is there a function like DoEvents in Visual Basi

Posted: Tue Mar 22, 2005 2:19 am
by goomoo
Hello,everyone.

I want to read a large number of strings to a treegadget from a text file in a WHILE loop,This operation will take a long time, during this, the gadgets and window cannot response user's operation, so I think there should be some funcion like DoEvents in VB or Application.ProcessMessages in Delphi , Is there anyone in PureBasic, or Can I have an alternate solution?

Thanks! :D

Posted: Tue Mar 22, 2005 2:25 am
by Shannara
Delay(#)

Posted: Tue Mar 22, 2005 3:33 am
by goomoo
Shannara, thanks for your reply.

The Delay() subroutine sleeps current thread only, it cannot process window messages. For an example:

Code: Select all

OpenWindow(1,0,0,320,240,#PB_Window_ScreenCentered|#PB_Window_SystemMenu,"asdf")
CreateGadgetList(WindowID())
ButtonGadget(1,5,5,300,25,"After Click me, Move the window")

Repeat
  event.l=WaitWindowEvent()
  If event=#PB_Event_Gadget
    Delay(5000)
  EndIf
  
Until event=#PB_Event_CloseWindow
when you click the button, the window can't be moved in 5 seconds.[/code]

Posted: Tue Mar 22, 2005 3:41 am
by Beach
I would also like to know a good way to do this. Currently, I use the 'CreateThread' function if I need something going on in the background.

Posted: Tue Mar 22, 2005 7:40 am
by goomoo
CreateThread() works well at most situations, but using multi-threads to modify user interface can easily cause access conflict.

Posted: Tue Mar 22, 2005 7:57 am
by LarsG
Perhaps putting a WindowEvent() in the while loop?

Posted: Tue Mar 22, 2005 8:55 am
by thefool
i would put the reading file part in a thread.

Posted: Tue Mar 22, 2005 9:37 am
by einander
Or you can try with a CallBack

Code: Select all

Procedure ReadTree()
  Static count
  count$="Reading Tree : "+Str(count)
  TextOut_(GetDC_(WindowID()),10,10,count$,Len(count$)) 
  count+1
EndProcedure


Procedure Callback(Win, Msg, wParam, lParam) 
   result = #PB_ProcessPureBasicEvents 
   Select Msg 
   Case #PB_Event_CloseWindow:End
    ; here you can process other messages
    EndSelect 
  ProcedureReturn result 
EndProcedure 

hWnd = OpenWindow(0,0,0,800,80,#PB_Window_SystemMenu|#PB_Window_ScreenCentered, "Test") 
    CreateGadgetList(hWnd) 
   TextGadget(0, 200, 6, 200, 20, "")
      
SetWindowCallback(@Callback()) 
Repeat 
      If WindowEvent() = 0 
        Readtree()
        SetGadgetText(0, "Window mouse position: "+Str(WindowMouseX())+","+Str(WindowMouseY()))
        Delay(20)
      EndIf
  ForEver   
 

Posted: Tue Mar 22, 2005 11:53 am
by PB
> Perhaps putting a WindowEvent() in the while loop?

Yes, this is the PureBasic equivalent of VB's "DoEvents" command. Try it! :)

Posted: Tue Mar 22, 2005 3:02 pm
by gnozal
This one also works :

Code: Select all

Procedure DoEvents() 
    msg.MSG 
    If PeekMessage_(msg,0,0,0,1) 
      TranslateMessage_(msg) 
      DispatchMessage_(msg) 
    Else 
      Delay(1) 
    EndIf 
EndProcedure
Call DoEvents() in your loop to update your gagdets.

Posted: Tue Mar 22, 2005 3:09 pm
by Beach
Doooode, thanks Gonzal! 8)

Posted: Tue Mar 22, 2005 5:24 pm
by freak
The code by gnozal does the exact same thing that WindowEvent() does.
(except for the delay, and WindowEvent() handles shortcuts too)

It is recommended to call WindowEvent() in a loop until it returns 0.
This way you make sure all redraw events get processed as quickly as possible.
the code by gnozal does process only one event per DoEvents() call, which, depending
on what you do between those calls can still lead to an unresponsive gui.

Also the Delay(1) is not a good choise. As long as your program is still working on something
in a loop, it makes no sense to slow that down with a delay.
The Delay makes only sense where your app has actually nothing to do at the moment
and you want to avoid using 100% cpu.)

Short Version:

Code: Select all

Procedure DoEvents()
  While WindowEvent(): Wend
EndProcedure
This makes sure any waiting events are processed, so the gui is redrawn correctly.
However, you must notice that this discards any user events like button clicks and such
too. So i suggest before entering the loop you are in to use DisableGadget() to disable
any buttons, so tha user knows that clicking them has no effect, and enable them again
when entering the main loop again.
Otherwise the user might wonder why your program is not reacting to his input.

If you have lets say an "Abort" button that can stop what you are currently doing,
or any other event you need to check, i recommend this:

Code: Select all

Procedure DoEvents()
  Repeat
    event = WindowEvent()
    ; check for the abort condition here, for example a #PB_Event_Gadget on a button
    ; and set a global variable that will abort the loop
  Until event = 0 ; stop processing when all waiting events are done
EndProcedure
these 2 ways are both 100% crossplatform compatible btw.

It is also recommended to tell the user in some way that your app is busy, especially
if what you are doing takes a little time. This can be done by opening a small "busy"
window, or putting a "processing, please wait..." in the statusbar.
Also a progressbar is always a good choise.

If you don't do that, the user will think that the app hangs if he doesn't know why it is
not responding for some time and believe your app is not well coded.
.. and you don't want that, do you? :wink:

hope that helps a bit...

Posted: Tue Mar 22, 2005 7:32 pm
by Flype
your recommendations are welcome Freak :wink:

Posted: Wed Mar 23, 2005 3:18 am
by goomoo
I got it.

Thank you , freak.

Thank you all. :)

Posted: Wed Mar 23, 2005 8:42 am
by gnozal
Thanks freak :)