Browse of my ADO Class

Re: Browse of my ADO Class

Postby nageswaragunupudi » Mon Sep 30, 2024 9:09 am

JoséQuintas wrote:Let's simplify, forgot my class.
I want to show numbers from 1 to 10, no array, no recordset, no ADO, no my class
I want to use xbrowse and codeblocks only

Code: Select all  Expand view

@ nRow, nCol XBROWSE xControl ;
      SIZE nWidth, nHeight PIXEL ;
       OBJECT Nil ;
        OF xParent
ADD oCol TO xControl ;
   DATA { || xControl:nArrayAt } ;
   HEADER "NUM"

xControl:nArrayAt := 1
xControl:bGoTop := { || xControl:nArrayAt := 1 }
xControl:bGoBottom := { || xControl:nArrayAt := 10 }
??????
 


Same problem on reduced sample.

Is there exists a solution to do this ?
xbrowse and codeblocks only.
It is a standard feature of xbrowse: to define codeblocks.
It is a simple task: show numbers from 1 to 10
And cancel any automatic detection of value used on XBROWSE OBJECT.

Sample on this post use numbers from 1 to 10.
It is a proof about to be possible to define codeblocks.

Can't use multithread... bad but ok
Can't use DBF like on multithread... bad... need change another application to MySQL
My ADOClass ???
It is the remaining one thing that I could use on fivewin.


Showing numbers from 1 to 10. No array, no Ado and no any known database.
This is a sample:
Code: Select all  Expand view
#include "fivewin.ch"

function Main()

   local oDlg, oBrw
   local nValue      := 1 // used for browse

   DEFINE DIALOG oDlg SIZE 400,500 PIXEL TRUEPIXEL RESIZABLE

   @ 20,20 XBROWSE oBrw SIZE -20,-20 PIXEL OF oDlg ;
      CELL LINES NOBORDER

   WITH OBJECT oBrw
      :nDataType  := DATATYPE_USER

      // Create and add a column, the simplest way
      oBrw:Number := { || nValue }

      // Navigation Blocks of XBrowse
      // All Required
      :bGoTop     := { || nValue :=  1 }
      :bGoBottom  := { || nValue := 10 }
      :bKeyCount  := { || 10 }  // Use this instead of bLogicLen
      :bBof       := { || nValue < 1 }
      :bEof       := { || nValue > 10 }
      :bSkip      := { |n,nSave| nSave := nValue, ;
                        nValue := Max( 1, Min( 10, nValue + IfNil(n,1) ) ), ;
                        nValue - nSave } // return number of rows actually skipped
      :bBookMark  := ;
      :bKeyNo     := { |n| If( n == nil, nValue, nValue := n ) }
      //
      :CreateFromCode()

   END

   ACTIVATE DIALOG oDlg CENTERED

return nil
 


Different ways of Creating and adding new columns to Browse

Code: Select all  Expand view
oBrw:<header> := <codeblock-to-access-value>


OR (compatible with TC browse)
Code: Select all  Expand view
ADD TO oBrw DATA { || nValue } HEADER "Number"

OR
Code: Select all  Expand view
ADD TO oBrw DATA nValue HEADER "Number"

OR (old way)
Code: Select all  Expand view
  WITH OBJECT oBrw:AddCol()
      :bEditValue := { || nValue }
      :cHeader    := "Number"
   END
 
Regards

G. N. Rao.
Hyderabad, India
User avatar
nageswaragunupudi
 
Posts: 10643
Joined: Sun Nov 19, 2006 5:22 am
Location: India

Re: Browse of my ADO Class

Postby nageswaragunupudi » Mon Sep 30, 2024 4:50 pm

Navigation code-blocks for ADO RecordSet:

Used in TWBrowse and TCBrowse
Code: Select all  Expand view
  ::bGoTop    = { || If( oRs:RecordCount() > 0, oRs:MoveFirst(), nil ) }
   ::bGoBottom = { || If( oRs:RecordCount() > 0, oRs:MoveLast(), nil ) }
   ::bSkip     = { |nSkip,x| If( oRs:RecordCount() < 1, 0, ( x := oRs:AbsolutePosition, ;
                   oRs:AbsolutePosition := Min( Max( 1, x + nSkip ), oRs:RecordCount() ), ;
                   oRs:AbsolutePosition - x ) ) }
   ::bLogicLen = { || oRs:RecordCount() }
   ::cAlias    = "Array"                // Just put something
 


Used for TXBrowse:
Code: Select all  Expand view
::bGoTop    := {|| If( ::oRs:RecordCount() > 0, ::oRs:MoveFirst(), nil ) }
::bGoBottom := {|| If( ::oRs:RecordCount() > 0, ::oRs:MoveLast(), nil )  }
::bSkip     := {| n | AdoSkip( ::oRs, IfNil( n, 1 ) ) }
::bBof      := {|| ::oRs:Bof }
::bEof      := {|| ::oRs:Eof }
::bBookMark := {| n | If( n == nil,;
                      If( ::oRs:RecordCount() > 0, ::oRs:BookMark, 0 ), ;
                      If( ::oRs:RecordCount() > 0, ( ::oRs:BookMark := n ), 0 ) ) }
::bKeyNo    := {| n | If( n == nil, ;
                      If( ::oRs:RecordCount() > 0, ::oRs:AbsolutePosition, 0 ),;
                      If( ::oRs:RecordCount() > 0, ( ::oRs:AbsolutePosition := n ), 0 ) ) }
::bKeyCount := {|| ::oRs:RecordCount() }



Code: Select all  Expand view
static function AdoSkip( oRs, n )

   LOCAL nRec

   if oRs:RecordCount() == 0
      return 0
   endif

   nRec := oRs:AbsolutePosition
   If( oRs:Eof, oRs:MoveLast(), If( oRs:Bof, oRs:MoveFirst(),) )
   oRs:Move( n )
   If( oRs:Eof, oRs:MoveLast(), If( oRs:Bof, oRs:MoveFirst(),) )

return oRs:AbsolutePosition - nRec
Regards

G. N. Rao.
Hyderabad, India
User avatar
nageswaragunupudi
 
Posts: 10643
Joined: Sun Nov 19, 2006 5:22 am
Location: India

Re: Browse of my ADO Class

Postby JoséQuintas » Tue Oct 01, 2024 3:42 pm

Thanks for all support.
Will try again later, the only working browse was using array as reference.
There are more things to be done.

Imageshell station map

My current basic test is:
- My application using gtwvg and multithread
- fivewin called from menu on one thread, more than one thread, crash all.
- there are 5 browses, but 2 are on anothers tab, not visible on image

current source code, for all browses is this:
Code: Select all  Expand view

STATIC FUNCTION gui_Browse( xDlg, xParent, xControl, nRow, nCol, nWidth, nHeight, oTbrowse, ;
   cField, xValue, workarea, aKeyDownList, oFrmClass )

   LOCAL aItem, oCol, aThisKey, nPos
#ifdef DLGAUTO_AS_LIB
   LOCAL aCol, nValue
#endif

   IF oFrmClass:lIsSQL
#ifdef DLGAUTO_AS_LIB
      IF Len( aKeyDownList ) == 0
         @ nRow, nCol XBROWSE xControl ;
            ARRAY Array(10) ;
            SIZE nWidth, nHeight PIXEL ;
            ; // LINES AUTOCOL, AUTOSORT ;
            OF xParent ;
            ON DBLCLICK gui_BrowseDblClick( xDlg, xControl, workarea, cField, @xValue )
            //LINES CELL
      ELSEIF ( nPos := hb_AScan( aKeyDownList, { | e | e[1] == VK_RETURN } ) ) != 0
         @ nRow, nCol XBROWSE xControl ;
            ARRAY Array(10) ;
            ; // LINES AUTOCOL, AUTOSORT ;
            SIZE nWidth, nHeight PIXEL ;
            OF xParent ;
            ON DBLCLICK GUI():BrowseKeyDown( VK_RETURN, aKeyDownList, workarea )
            //LINES CELL
      ENDIF
      WITH OBJECT xControl
         //:nDataType := DATATYPE_USER
         xControl:xUserData := ADOLocal()
         xControl:xUserData:Execute( "SELECT * FROM " + workarea + ;
            iif( "BROWSE" $ oFrmClass:cTitle, "LIMIT 5 ", "" ) + ;
            " ORDER BY " + oTbrowse[ 1, 1 ] )
         xControl:xUserValue := xControl:xUserData:RecordCount()
         :nArrayAt   := 1
         ADD oCol TO xControl ;
            DATA { || xControl:nArrayAt } ;
            HEADER "#ArrayAt" ;
            PICTURE "999999"
         FOR EACH aItem IN oTbrowse
            DO CASE
            CASE Len( aItem ) < 4
               ADD oCol TO xControl ;
                  DATA { || xControl:xUserData:Value( aItem[2] ) } ;
                  HEADER aItem[1] ;
                  //PICTURE aItem[3]
            CASE aItem[ 4 ] == "D"
               ADD oCol TO xControl ;
                  DATA { || xControl:xUserData:Date( aItem[2] ) } ;
                  HEADER aItem[1] ;
                  //PICTURE aItem[3]
            CASE aItem[ 4 ] == "N"
               ADD oCol TO xControl ;
                  DATA { || xControl:xUserData:Number( aItem[2] ) } ;
                  HEADER aItem[1] ;
                  //PICTURE aItem[3]
            OTHERWISE
               ADD oCol TO xControl ;
                  DATA { || xControl:xUserData:String( aItem[2] ) } ;
                  HEADER aItem[1] ;
                  //PICTURE aItem[3]
            ENDCASE
         NEXT
         //:bGoTop     := { || xControl:xUserValue :=  1 }
         //:bGoBottom  := { || xControl:xUserValue := 10 } // :oRs:RecordCount() }
         //:bKeyCount  := { || xControl:xUserValue := 10 } // :oRs:RecordCount() }  // Use this instead of bLogicLen
         //:bBof       := { || xControl:xUserValue < 1 }
         //:bEof       := { || xControl:xUserValue > 10 }
         //:bSkip      := { |n,nSave| nSave := xControl:xUserValue, ;
         //               xControl:xUserValue := Max( 1, Min( 10, xControl:xUserValue + IfNil(n,0) ) ), ;
         //               xControl:xUserValue - nSave } // return number of rows actually skipped
         //:bBookMark  := ;
         //:bKeyNo     := { |n| If( n == nil, xControl:xUserValue, xControl:xUserValue := n ) }
         :bOnSkip    := { || xControl:xUserData:Move( xControl:nArrayAt - 1, 1 ) }
         xControl:SetArray( Array( xControl:xUserData:RecordCount() ) )
      ENDWITH
#endif
   ELSE
      IF Len( aKeyDownList ) == 0
         @ nRow, nCol XBROWSE xControl ;
            SIZE nWidth, nHeight PIXEL ;
            DATASOURCE workarea ;
            OF xParent ;
            ON DBLCLICK gui_BrowseDblClick( xDlg, xControl, workarea, cField, @xValue )
            //LINES CELL
      ELSEIF ( nPos := hb_AScan( aKeyDownList, { | e | e[1] == VK_RETURN } ) ) != 0
         @ nRow, nCol XBROWSE xControl ;
            SIZE nWidth, nHeight PIXEL ;
            DATASOURCE workarea ;
            OF xParent ;
            ON DBLCLICK GUI():BrowseKeyDown( VK_RETURN, aKeyDownList, workarea )
            //LINES CELL
      ENDIF
      FOR EACH aItem IN oTbrowse
         ADD oCol TO xControl ;
            DATA { || (workarea)->(FieldGet(FieldNum( aItem[2] ) ) ) } ;
            HEADER aItem[1] ;
            PICTURE aItem[3]
      NEXT
   ENDIF
   xControl:CreateFromCode()
   xControl:Refresh() // test for bug

   /* create buttons on browse for defined keys */
   IF Len( aKeyDownList ) != 0
      FOR EACH aThisKey IN aKeyDownList
         AAdd( oFrmClass:aControlList, EmptyFrmClassItem() )
         Atail( oFrmClass:aControlList )[ CFG_CTLTYPE ] := TYPE_BUTTON_BRW
         gui_ButtonCreate( xDlg, xParent, @Atail( oFrmClass:aControlList )[ CFG_FCONTROL ], ;
            nRow - APP_LINE_SPACING, 200 + aThisKey:__EnumIndex() * APP_LINE_HEIGHT, ;
            APP_LINE_HEIGHT - 2, APP_LINE_HEIGHT - 2, "", ;
            iif( aThisKey[1] == VK_INSERT, "ICOPLUS", ;
            iif( aThisKey[1] == VK_DELETE, "ICOTRASH", ;
            iif( aThiskey[1] == VK_RETURN, "ICOEDIT", Nil ) ) ), aThisKey[2] )
      NEXT
      xControl:bKeyDown := { | nKey | GUI():BrowseKeyDown( nKey, aKeyDownList ) }
   ENDIF

   (xDlg);(cField);(xValue);(workarea);(aKeyDownList);(xControl);(nRow);(nCol);(nWidth)
   (nHeight);(oTBrowse);(oCol)
   (xValue)

   RETURN Nil
 


setup for folderex browses is this:
Code: Select all  Expand view

   cTxt += '[ "BROWSELIST",[' + hb_Eol()
   cTxt += '[ "cDbfOrigin",  "cFieldName", "cDbfTarget", "nOrder", "cFieldTarget", "cTargetKey", "lEdit", "cTitle" ],' + hb_Eol()
   cTxt += '[ "JPCADASTRO", "IDCADASTRO", "JPFINAN", 2, "FICADASTRO", "IDFINAN", true, "FINANCEIRO" ],' + hb_Eol()
   cTxt += '[ "JPCADASTRO", "IDCADASTRO", "JPFINAN", 2, "FICADASTRO", "IDFINAN", true, "FINANCEIRO" ],' + hb_Eol()
   cTxt += '[ "JPCADASTRO", "IDCADASTRO", "JPFINAN", 2, "FICADASTRO", "IDFINAN", true, "FINANCEIRO" ],' + hb_Eol()
   cTxt += '[ "JPCADASTRO", "IDCADASTRO", "JPFINAN", 2, "FICADASTRO", "IDFINAN", true, "FINANCEIRO" ]' + hb_Eol()
   cTxt += ']],' + hb_Eol()
 


browse fields comes from tables on MySQL - current test is using MySQL, but could be done using DBF too.
browses on folderex are to selected code.
browse window is called clicking on button "view".
JoséQuintas
 
Posts: 33
Joined: Tue Feb 09, 2021 4:20 pm

Re: Browse of my ADO Class

Postby JoséQuintas » Wed Oct 02, 2024 11:56 pm

cnavarro wrote:What problem do you find with using multithread?
If you have any questions or concerns that I may be able to help you with, I remain at your disposal


Problem is when closing dialogs, fivewin crashes application.

I found this on dialog activation:

Code: Select all  Expand view

   hActiveWnd = If( ::oWnd != nil, ::oWnd:hWnd,;
                If( nDlgCount > 1 .or. lWRunning(),;
                    GetActiveWindow(), GetWndApp() ) )
 


On multithread first dialog need to be modal, and can't be used an active window as reference.
Make a test changing nDlgCount to THREAD STATIC but no success.
I do not know if lWRunning() and GetWndApp() are valid for multithread.
And do not know if changing only here we get a solution or a bigger problem.
JoséQuintas
 
Posts: 33
Joined: Tue Feb 09, 2021 4:20 pm

Re: Browse of my ADO Class

Postby cnavarro » Thu Oct 03, 2024 2:34 am

Dear Jose
Please, attach an example of how you create the threads from that initial modal dialog
Cristobal Navarro
Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noción del tiempo
El secreto de la felicidad no está en hacer lo que te gusta, sino en que te guste lo que haces
User avatar
cnavarro
 
Posts: 6548
Joined: Wed Feb 15, 2012 8:25 pm
Location: España

Re: Browse of my ADO Class

Postby JoséQuintas » Thu Oct 03, 2024 1:14 pm

My use is simple, use allways the same, for many years.

Main module only wait modules
On this way, I can open/close anything later, including menu/newmain.
Code: Select all  Expand view

PROCEDURE Main

   hb_ThreadStart( { || NewMain() } )
   hb_ThreadWaitForAll()

   RETURN
 


For modules, on anywhere: hb_ThreadStart( { || Module() } )

On module, I do not test other valid options, once main application is allways GTWVG

Code: Select all  Expand view

hb_gtReload( "WVG" )
.....
// the module here
 


If do not use hb_gtReload( "WVG" ) fivewin changes previous window. (not sure if FW_GT is a not multithread GT)

fivewin has a single browse:
Code: Select all  Expand view

PROCEDURE Main
   hb_ThreadStart( { || browsemodule() } )
   hb_ThreadStart( { || browsemodule() } )
   hb_ThreadStart( { || browsemodule() } )
   hb_ThreadWaitForAll()
   RETURN

FUNCTION browsemodule()
   SET EXCLUSIVE OFF
   hb_gtReload( "WVG" )
   USE ( file )
   browse()
   CLOSE DATABASES
   RETURN Nil
 


GTWVG is not a problem, it uses same harbour GUI default, and on this way do not open window.

Another sample could be call module from fivewin menu.
Code: Select all  Expand view

// from
// MENUITEM cDBF ACTION frm_funcMain()
// to
MENUITEM cDBF ACTION hb_ThreadStart( { || frm_funcMain() } )
 


Do not know why, but seems that hb_gtReload("WVG") make difference.
I think it is about to have a proccess to be locked.
But if it is not locked by anything else, thread ends.
I have an additional setup routine, to setup all threads at the same way.
JoséQuintas
 
Posts: 33
Joined: Tue Feb 09, 2021 4:20 pm

Re: Browse of my ADO Class

Postby JoséQuintas » Sat Oct 05, 2024 8:39 am

One test using multithread.
sample carlos.prg

test 1
Code: Select all  Expand view

#include "FiveWin.ch"

function Main()

   local oDlg, oFld, lVal := .T.

   DEFINE DIALOG oDlg SIZE 400, 300

   @ 0.5, 1 FOLDER oFld PROMPTS "One", "Two", "Three" SIZE 190, 120

   @ 1, 1 CHECKBOX lVal PROMPT "Test" SIZE 80, 15 OF oFld:aDialogs[ 1 ]

   @ 7.3, 14 BUTTON "Ok" ACTION oDlg:End()

   ACTIVATE DIALOG oDlg CENTERED

return nil
 


Image

test2
Code: Select all  Expand view

#include "FiveWin.ch"

function Main()

   hb_ThreadStart( { || Main2() } )
   hb_ThreadStart( { || Main2() } )
   hb_ThreadStart( { || Main2() } )
   hb_ThreadStart( { || Main2() } )
   hb_ThreadWaitForAll()

   RETURN Nil

FUNCTION Main2()

   LOCAL oDlg, oFld, lVal := .T.

   DEFINE DIALOG oDlg SIZE 400, 300

   @ 0.5, 1 FOLDER oFld PROMPTS "One", "Two", "Three" SIZE 190, 120

   @ 1, 1 CHECKBOX lVal PROMPT "Test" SIZE 80, 15 OF oFld:aDialogs[ 1 ]

   @ 7.3, 14 BUTTON "Ok" ACTION oDlg:End()

   ACTIVATE DIALOG oDlg CENTERED

   RETURN Nil

 


move to see images, only one dialog centered.

Image

do not centralize, move manual

test3, define parent

Code: Select all  Expand view

#include "FiveWin.ch"

function Main()

   hb_ThreadStart( { || Main2() } )
   hb_ThreadStart( { || Main2() } )
   hb_ThreadStart( { || Main2() } )
   hb_ThreadStart( { || Main2() } )
   hb_ThreadWaitForAll()

   RETURN Nil

FUNCTION Main2()

   LOCAL oDlg, oFld, lVal := .T.

   DEFINE DIALOG oDlg SIZE 400, 300

   @ 0.5, 1 FOLDER oFld OF oDLG PROMPTS "One", "Two", "Three" SIZE 190, 120

   @ 1, 1 CHECKBOX lVal PROMPT "Test" SIZE 80, 15 OF oFld:aDialogs[ 1 ]

   @ 7.3, 14 BUTTON "Ok" of oDLG ACTION oDlg:End()

   ACTIVATE DIALOG oDlg CENTERED

   RETURN Nil
 


Image

test4, inkey(5) between each thread

Code: Select all  Expand view

#include "FiveWin.ch"

function Main()

   hb_ThreadStart( { || Main2() } )
   Inkey(5)
   hb_ThreadStart( { || Main2() } )
   Inkey(5)
   hb_ThreadStart( { || Main2() } )
   Inkey(5)
   hb_ThreadStart( { || Main2() } )
   hb_ThreadWaitForAll()

   RETURN Nil

FUNCTION Main2()

   LOCAL oDlg, oFld, lVal := .T.

   DEFINE DIALOG oDlg SIZE 400, 300

   @ 0.5, 1 FOLDER oFld OF oDLG PROMPTS "One", "Two", "Three" SIZE 190, 120

   @ 1, 1 CHECKBOX lVal PROMPT "Test" SIZE 80, 15 OF oFld:aDialogs[ 1 ]

   @ 7.3, 14 BUTTON "Ok" of oDLG ACTION oDlg:End()

   ACTIVATE DIALOG oDlg CENTERED

   RETURN Nil
 

Image

Seems like fivewin working on multithread, but not on each thread.
compile using -mt
may be window list is STATIC and not THREAD STATIC.
test changing aAllWindows and nWindow on window.prg to thread static but no change
JoséQuintas
 
Posts: 33
Joined: Tue Feb 09, 2021 4:20 pm

Re: Browse of my ADO Class

Postby Antonio Linares » Sat Oct 05, 2024 3:25 pm

Dear Jose,

Many thanks for these very interesting examples!

We are going to investigate why they don't work as expected :-)

great feedback
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42099
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: Browse of my ADO Class

Postby cnavarro » Sun Oct 06, 2024 3:22 pm

Dear Jose
I haven't done too many tests using modal processes in a multithreaded environment so far because I didn't see the point in using this technique for that. I think that at the process level we can use other functions that would give us fewer problems
What I have tested in depth and with various examples and running programs is the use of multithread in other cases where the GUI resources are not modal. Here is an example of use:

Code: Select all  Expand view


//----------------------------------------------------------------------------//
// Programa: TESTMT01.PRG
// Autor...: Cristobal Navarro
//----------------------------------------------------------------------------//

#include "Fivewin.ch"
#include "hbthread.ch"
#include "gif.ch"

Static oPnel1
Static pMutex
Static lExit   := .F.

Function Main()

   local oWnd
   local oBar
   local oBtt1
   local oBtt2
   local oBtt3
   local uTh1
   local uTh2
   local uTh3
   local uTh4
   local nPress  := 0
   
    DEFINE DIALOG oWnd FROM 0, 0 TO 660, 1100 TITLE "Test" PIXEL //MDI

      DEFINE BUTTONBAR oBar SIZE 48, 48 OF oWnd 2015
      DEFINE BUTTON oBtt1 PROMPT "Salir" OF oBar ACTION oWnd:End() TOOLTIP "Salir"
      DEFINE BUTTON oBtt2 PROMPT "Test"  OF oBar ;
         ACTION ( nPress++, ; //                  pMutex := hb_mutexCreate(),;
                  ; //uTh1 := hb_threadStart( HB_THREAD_INHERIT_PUBLIC, @CrearGif(), oWnd ),;
                  uTh5 := hb_threadStart( HB_THREAD_INHERIT_PUBLIC, @DlgW(), oWnd ), ;
                  uTh2 := hb_threadStart( HB_THREAD_INHERIT_PUBLIC, @WTest(), "Hello", 120, nPress ),;
                  uTh3 := hb_threadStart( HB_THREAD_INHERIT_PUBLIC, @WTest(), 333, 120, nPress ) ) //,;
                  // uTh4 := hb_threadStart( HB_THREAD_INHERIT_PUBLIC, @MsgW() ) )
      //DEFINE BUTTON oBtt3 PROMPT "UUID" OF oBar ACTION Uuid()

   ACTIVATE DIALOG oWnd ;
      ON INIT ( HazPnel( oWnd ), CrearGif( oWnd ) ) ;
      VALID ( lExit  := .T., ;
              Msginfo( Len( oPnel1:aControls ) ), ;
              hb_threadTerminateAll(), .T. )
Return NIL

//----------------------------------------------------------------------------//

Function WTest( u, nF, nPress )

   local x := 1
   if Valtype( u ) = "N"
      For x = 1 to 300 step 15
         //hb_mutexLock( pMutex )
         @ nF + x, 60 + ( ( nPress - 1 ) * 110 ) SAY "Thread " + StrZero( nPress + 1, 2 ) ;
            OF oPnel1 PIXEL COLOR CLR_BLACK
         //hb_mutexUnLock( pMutex )
         SysRefresh()
         hb_idleSleep( 0.8 )
      Next x
   else
      For x = 1 to 300 step 15
         //hb_mutexLock( pMutex )
         @ nF + x, 4 + ( ( nPress - 1 ) * 110 ) SAY "Thread " + StrZero( nPress, 2 ) ;
            OF oPnel1 PIXEL COLOR CLR_RED
         //hb_mutexUnLock( pMutex )
         SysRefresh()
         hb_idleSleep( 0.8 )
      Next x
   endif
   //AEVal( oPnel1:aControls, { | o | o:bValid := { || lExit } } )

Return nil

//----------------------------------------------------------------------------//

Function HazPnel( oWnd )

   @ 50, 400 PANEL oPnel1 OF oWnd SIZE 600, 550
   oPnel1:SetColor( CLR_BLACK, CLR_YELLOW )
   
Return oPnel1

//----------------------------------------------------------------------------//

Function CrearGif( oDlg )
   
   local oGif
   @ 60, 10 GIF oGif FILE "..\gifs\matrix.gif" OF oDlg SIZE 100, 100 //ADJUST //

Return nil

//----------------------------------------------------------------------------//

Function MsgW()

   MsgWait( "Process", "Modal", 5  )

Return nil

//----------------------------------------------------------------------------//

Function DlgW( oWnd )

   local oDlg
   
   DEFINE DIALOG oDlg OF oWnd
   
   ACTIVATE DIALOG oDlg CENTERED IN PARENT

Return nil

//----------------------------------------------------------------------------//
 


The example you attached, since it deals with model processes, does not demonstrate the use of multithreading.
I have tested the code you are using, although the results are not ALWAYS completely satisfactory for me, but you can try and make any adjustments you consider to the attached code.

Code: Select all  Expand view

//----------------------------------------------------------------------------//
// Programa: TESTMT03.PRG
// Autor...: Cristobal Navarro
//----------------------------------------------------------------------------//

#include "FiveWin.ch"
#include "hbthread.ch"

static aThreads := {}

function Main()

//   AAdd( aThreads, hb_ThreadStart( HB_THREAD_INHERIT_PUBLIC, { || Main2(1) } ) )
//                                 Public & Private
   AAdd( aThreads, hb_ThreadStart( HB_BITOR( 3, 4 ), { || Main2(1) } ) )
   SysWait( 1.0 )
   AAdd( aThreads, hb_ThreadStart( HB_BITOR( 3, 4 ), { || Main2(2) } ) )
   SysWait( 1.0 )
   AAdd( aThreads, hb_ThreadStart( HB_BITOR( 3, 4 ), { || Main2(3) } ) )
   SysWait( 1.0 )
   AAdd( aThreads, hb_ThreadStart( HB_BITOR( 3, 4 ), { || Main2(4) } ) )
   SysWait( 3.0 )
   SysRefresh()

   // hb_ThreadWaitForAll()
   AEval( aThreads, { | h | if( !Empty( h ), hb_threadJoin( h ), ) } )


RETURN Nil

FUNCTION Main2( nPos )

   Local oDlg
   Local oFld
   Local lVal := .T.
   Local lEnd := .F.
   Local oBrw
   Local nRow
   Local nCol

   Do Case
      Case nPos == 1
         nRow  := 10
         nCol  := 10
      Case nPos == 2
         nRow  := 340
         nCol  := 10
      Case nPos == 3
         nRow  := 10
         nCol  := 450
      Case nPos == 4
         nRow  := 340
         nCol  := 450

   EndCase
   USE "CUSTOMER.DBF" SHARED

   DEFINE DIALOG oDlg SIZE 400, 300 PIXEL TRUEPIXEL

   @ 0,0 FOLDER oFld OF oDLG PROMPTS "One", "Two", "Three" SIZE 380, 250 PIXEL

      @ 1,1 XBROWSE oBrw SIZE -1, -1 OF oFld:aDialogs[ 1 ] DATASOURCE Alias() PIXEL
      oBrw:CreateFromCode()

      @ 10, 10 CHECKBOX lVal PROMPT "Test" SIZE 80, 15 OF oFld:aDialogs[ 2 ]  PIXEL

      @ oDlg:nBottom - 42, oDlg:nRight - 100 BUTTON "Ok" SIZE 80, 40 OF oDLG ;
         ACTION ( hb_threadDetach( aThreads[ nPos ] ), lEnd := .T., oDlg:End() ) PIXEL

   ACTIVATE DIALOG oDlg ; // CENTERED
      ON INIT ( oDlg:Move( nRow, nCol ) ) ;
      VALID lEnd

   //hb_threadDetach( aThreads[ nPos ] )
   //hb_threadQuitRequest( aThreads[ nPos ] )

   RETURN Nil
 


Remember that:
- Dialogs are modal by default (for a dialog to be non-modal, the NOWAIT clause is used in the ACTIVATE, for example those used by TFolder and TFolderEx in each tab)
- Once the threads are launched, we have no control over their execution since it is the CPU that is responsible for giving priority and execution to all the threads that are running, both its own and those of the system.

Tell me your thoughts on this and we can move forward on the topic.
Cristobal Navarro
Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noción del tiempo
El secreto de la felicidad no está en hacer lo que te gusta, sino en que te guste lo que haces
User avatar
cnavarro
 
Posts: 6548
Joined: Wed Feb 15, 2012 8:25 pm
Location: España

Re: Browse of my ADO Class

Postby JoséQuintas » Mon Oct 07, 2024 4:08 pm

I think this could be a complex use of multithread.
Not sure if windows api and SendMessage() works between threads.

My multithread use is very simple, I already show here.
I will continue using it for at least 1/2 years.

I think on the simplest way:
Multithread is like several EXEs.
go back before go ahead.
First thing to do is fivewin working on a single thread.
If it works on a single thread, we have several fivewins.
This helps me too much.

Mix things from one thread to another, this is not possible while do not fix to one thread.
I do not think to use fivewin on this way, may be on fucture.

Caution:
Multithread is like several EXEs.
On EXE first thing is to apply our defaults.
From this point, default is not the same on all threads, error occurs for those who thinks default is the same.

I will post another test, may be things becames clear with it.
JoséQuintas
 
Posts: 33
Joined: Tue Feb 09, 2021 4:20 pm

Re: Browse of my ADO Class

Postby JoséQuintas » Mon Oct 07, 2024 7:29 pm

Image

All image is a single EXE.

It is a simple test.
My real application using GTWVG + multithread
I add 1 option on menu to call hwgui
I add 1 option on menu to call fivewin

Is it a extreme test ?
No.
Multithread is like several EXEs.
Each thread is using one library.

What happens?
problem on fivewin when close dialogs.
it's not about multithread, but about ONE thread.

Extra code for hwgui:
On each thread call to hwg_InitProc(), I think it is a hook limited to thead, I do not works with C language, I can't confirm what is done
I made simple changes on official source code, they are under #ifdef MT_EXPERIMENTAL, aWindows, aModalDialogs and aDialogs, change from CLASSVAR to THREAD STATIC. On this way, each thread do not use wrong previous dialog when closing a modal dialog.

Seems to me single changes to work on a thread, not complex changes to multithread.
I do not know about resources or anything else that was not destroyed after to close a thread.
As I said, my knowledge is limited, I just do tests to see what happens.
This is one of these tests.

For all libraries: hb_gtReload("WVG") and AppInitSets() to define same default on all threads.

Note: postimage is working again, I edit to add image.

About image:
- 4 threads using wvg
- 2 threads using hwgui application (2 dialogs on each thread)
- 2 threads using fivewin application (2 dialogs on each thread)
JoséQuintas
 
Posts: 33
Joined: Tue Feb 09, 2021 4:20 pm

Re: Browse of my ADO Class

Postby cnavarro » Tue Oct 08, 2024 1:52 am

Jose, I think we should continue this thread in the Spanish forum because it seems that we have a problem with the terms and definitions, or at least the translations I get do not seem correct to me.
I am waiting for some additional example from you that allows me to better understand what you mean
The typical and most used case of multithreading is in a web server
I have a web server in Fivewin, which works correctly, along with the rest of the application
I insist again that creating a multithreaded application with modal processes (dialogs) seems to me to be a wrong approach


Jose, creo que debemos seguir este hilo en el foro de Español porque parece que tenemos un problema en los términos y definiciones, o por lo menos las traducciones que obtengo no me parecen correctas.
Quedo pendiente de algún ejemplo adicional tuyo que me permita entender mejor lo que quieres decir
El caso típico y más usado de multihilo es en un servidor web
Tengo un servidor web en Fivewin, que funciona correctamente, junto al resto de la aplicación
Volver a insistir que crear una aplicación multihilo con procesos modales ( diálogos ) me parece un enfoque equivocado
Cristobal Navarro
Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noción del tiempo
El secreto de la felicidad no está en hacer lo que te gusta, sino en que te guste lo que haces
User avatar
cnavarro
 
Posts: 6548
Joined: Wed Feb 15, 2012 8:25 pm
Location: España

Re: Browse of my ADO Class

Postby Giovany Vecchi » Tue Oct 08, 2024 2:06 pm

Em Português
Grande José Quintas. Fico feliz de você adquirir o FW e participar desta maravilha de ferramenta conosco.

Uma instância multithreading cria outro processo de escalotamento na memória e os dialogos criados no FW tem como referência a instância do handle da janela principal WNDMAIN().
Neste caso você resolveria usando DEFINE WINDOW MDI para cada parte do programa que você deseja abrir, sendo que isto não faz o multithreading mais as janelas ficam independentes com funcionamento de núcleo separado.
Para isto o correto é usar classes.
Você tem meu Whats, qualquer coisa estou a disposição em te ajudar.

in English
Great José Quintas. I'm glad you purchased the FW and participated in this wonderful tool with us.
A multithreading instance creates another scheduling process in memory and the dialogs created in the FW have as a reference the main window handle instance WNDMAIN().
In this case you would solve it by using DEFINE WINDOW MDI for each part of the program you want to open, but this does not create multithreading, but the windows are independent and operate in separate cores.
For this, the correct way is to use classes.
You have my WhatsApp, if you need anything I'm available to help you.
User avatar
Giovany Vecchi
 
Posts: 223
Joined: Mon Jun 05, 2006 9:39 pm
Location: Brasil

Re: Browse of my ADO Class

Postby JoséQuintas » Tue Oct 08, 2024 10:43 pm

cnavarro wrote:I am waiting for some additional example from you that allows me to better understand what you mean


This is what I allways use on my application, not with fivewin, but want to do the same with fivewin.
May be if this sample works, all is solved.

On fivewin, crash on close
Code: Select all  Expand view

#include "FiveWin.ch"

function Main()

   hb_ThreadStart( { || Main2() } )
   hb_ThreadStart( { || Main2() } )
   hb_ThreadStart( { || Main2() } )
   hb_ThreadStart( { || Main2() } )
   hb_ThreadWaitForAll()

   RETURN Nil

FUNCTION Main2()

   LOCAL oDlg

   DEFINE DIALOG oDlg SIZE 400, 300

   ACTIVATE DIALOG oDlg CENTERED

   RETURN Nil
 


if it is needed a reference different than gtwvg, a working sample using hwgui

Code: Select all  Expand view

#include "hwgui.ch"

FUNCTION Main()

   hb_ThreadStart( { || Main2() } )
   hb_ThreadStart( { || Main2() } )
   hb_ThreadStart( { || Main2() } )
   hb_ThreadStart( { || Main2() } )
   hb_ThreadStart( { || Main2() } )
   hb_ThreadWaitForAll()
*
   RETURN Nil

FUNCTION Main2()

   LOCAL oDlg

   INIT DIALOG oDlg TITLE "Example" ;
     AT 200,0 SIZE 400,150

   ACTIVATE DIALOG oDlg

   RETURN Nil
 
JoséQuintas
 
Posts: 33
Joined: Tue Feb 09, 2021 4:20 pm

Re: Browse of my ADO Class

Postby Antonio Linares » Wed Oct 09, 2024 6:00 am

Dear José,

many thanks for your great feedback

We are reviewing it to fix it
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42099
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

PreviousNext

Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: Google [Bot] and 58 guests