Página 1 de 2

Uma boa de migrar pra gráfico

Enviado: 09 Mai 2013 10:54
por JoséQuintas
Mudar pra LIB gráfica não é apenas fazer os desenhos. Tem também que pensar no multithread, tudo podendo rodar ao mesmo tempo.
Pra quem quiser brincar, uma forma excelente (eu adorei) é a que vou postar agora.
Basicamente é rodar módulos em threads separadas, e poder fazer o que quiser com cada módulo.

Preparei pra qualquer GT, mas não funcionou em GTWIN, só em GTWVT e GTWVG. Não tenho como testar com GTQT.
O exemplo permite abrir janelas infinitas, e pode usar o mouse no prompt da janela principal.
Uma vez módulos independentes, pode fazer o que quiser com eles, até adicionar visual gráfico.
E na prática, poderia misturar GTs, cada módulo numa GT.
Nada de comandos complicados, classes, ou algo parecido.

Mas... o que há de diferente neste exemplo?
É tão independente, que pode até fechar o menu principal, sem dar erro!!!!!

Bom divertimento.


Pra compilar pode ser:
hbmk2 test -mt -gtwvt
hbmk2 test -mt -gtwvg

Código: Selecionar todos

#include "hbgtinfo.ch"
#include "inkey.ch"

STATIC aThreadList := {}

PROCEDURE Main
   LOCAL nThreadId
   IF .NOT. hb_gtInfo( HB_GTI_VERSION ) $ "WVG,WVT" .OR. .NOT. hb_mtvm()
      CLS
      ? "Need GTWVG or GTWVT and Multithread"
      QUIT
   ENDIF
   nThreadId := hb_ThreadStart( { || Sistema() } )
   Aadd( aThreadList, nThreadId )
   DO WHILE IsThreadRunning()
      Inkey(2)
   ENDDO
   RETURN

PROCEDURE Sistema
   LOCAL nCont, nOpc := 0
   hb_gtReload( hb_GTInfo( HB_GTI_VERSION ) )
   SET SCOREBOARD OFF
   SET( _SET_EVENTMASK, INKEY_ALL - INKEY_MOVE + HB_INKEY_GTEVENT  )
   SetMode( 24, 80 )
   CLS
   DO WHILE .t.
      @ 15, 10 SAY hb_gtInfo( HB_GTI_VERSION )
      FOR nCont = 1 TO 10
         @ nCont, 10 PROMPT "OPCAO X"
      NEXT
      MENU TO nOpc
      IF LastKey() == K_ESC .OR. nOpc == 0
         EXIT
      ENDIF
      ExecuteModule()
   ENDDO
   RETURN

FUNCTION ExecuteModule()
   LOCAL nThreadId
   nThreadId := hb_ThreadStart( { || MyModule() } )
   Aadd( aThreadList, nThreadId )
   RETURN NIL

FUNCTION MyModule()
   LOCAL GetList := {}, cTexto
   hb_gtReload( hb_gtInfo( HB_GTI_VERSION ) )
   SetMode( 24, 80 )
   hb_gtInfo( HB_GTI_WINTITLE, "Modulo de Teste" )
   CLS
   cTexto := Pad( "Testando", 80 )
   @ 15, 10 SAY hb_gtInfo( HB_GTI_VERSION )
   @ 16, 10 SAY "MultiWindow:" + iif( hb_gtInfo( HB_GTI_ISMULTIWIN ), "Yes", "No" )
   @ 5, 5 SAY "Nome:" GET cTexto
   READ
   ThreadListRemove( hb_ThreadSelf() )
   RETURN NIL

STATIC FUNCTION ThreadListRemove( nThreadId )
   LOCAL nCont
   FOR nCont = 1 TO Len( aThreadList )
      IF aThreadList[ nCont ] == nThreadId
         aDel( aThreadList, nCont )
         aSize( aThreadList, Len( aThreadList ) - 1 )
         EXIT
      ENDIF
   NEXT
   RETURN NIL

FUNCTION IsThreadRunning()
   LOCAL lIsRunning := .f.
   IF Len( aThreadList ) != 0
      lIsRunning := hb_ThreadWait( aThreadList, 0.1, .t. ) != Len( aThreadList )
   ENDIF
   RETURN lIsRunning

FUNCTION Main - novo módulo principal
PROCEDURE Sistema - o programa principal
FUNCTION ExecuteModule() - Rotina pra executar módulos em multithread e adicionar a thread à lista
FUNCTION MyModule() - O módulo/programa/janela
FUNCTION ThreadListRemove() - Remove a thread da lista
FUNCTION IsThreadRunning() - Verifica se alguma thread ainda está rodando
Variável aThreadList - Contém a lista de threads
hb_gtReload() - como a GT é padrão, e já é aberta por default (mesmo sem tela), as próximas janelas são criadas com gt_Reload, só isso.

Uma boa de migrar pra gráfico

Enviado: 09 Mai 2013 17:02
por JoséQuintas
Gostaria de ver comentários.
E até testes que não pude fazer: GTWVW e GTQTC.

Uma boa de migrar pra gráfico

Enviado: 09 Mai 2013 21:00
por JoséQuintas
Postei no Harbour developer, meio receioso por reclamações, pra confirmar se estava ok,
Falta o tratamento pra mutex, porque vai estar mexendo no array por várias threads.

Confirmaram que funcionou também com GTXWC e GTQTC.

Pelo jeito não era só eu que estava à procura de deixar os módulos independentes do programa principal.
Fiquei feliz pelo resultado do post lá, sinal de que é um caminho interessante.

Uma boa de migrar pra gráfico

Enviado: 09 Mai 2013 22:33
por alxsts
Olá!

Não parei ainda para ver o que isto significa mas, parabéns pelo sucesso. Se possível, poste o link do seu post no grupo de desenvolvedores.

Uma boa de migrar pra gráfico

Enviado: 10 Mai 2013 00:09
por JoséQuintas
Detalhe: gtxwc é Linux e gtqtc Linux/Windows (QT). O mesmo fonte funcionando nas 4 GTs sem alteração.
Já postei um mais atualizado, pois o Pitpal Bedi comentou de incluir nos samples (acho que da gtwvg).

https://groups.google.com/forum/?hl=pt& ... RuFtYAmnRA

Uma boa de migrar pra gráfico

Enviado: 10 Mai 2013 23:15
por carlos_dornelas
José,

Aqui só consegui compilar com as seguintes opções:

hbmk2 test -mt -gtwvt
hbmk2 test -mt -gtwvg

Baixei o teu exemplo mais recente de
https://groups.google.com/forum/?hl=pt& ... RuFtYAmnRA

Com o -gtqtc e o -gtxwc deu o seguinte erro na compilação e o .exe não foi gerado:

hbmk2: Erro: Executando linkeditor. 1

Ainda estou meio cru no harbour e talvez a configuração do meu ambiente não esteja 100%. Você poderia dar uma analisada no meu bat de configuração para ver se está ok?

Código: Selecionar todos

@echo off
set Path=%Path%;c:\hb32\bin;c:\hb32\comp\mingw\bin;c:\hb32\comp\mingw\lib;c:\hb32\comp\mingw\include;c:\hb32\lib;
set Include=%Include%;c:\hb32\include;c:\hb32\comp\mingw\Include;
Baixei e instalei o harbour nightly no C:\hb32; idem para o pacote do contrib;

Grato por suas considerações.

Antonio Carlos

Uma boa de migrar pra gráfico

Enviado: 11 Mai 2013 12:00
por JoséQuintas
Informaram lá no grupo que funcionou, como pode ver.

GTWXC é Linux, não dá pra usar no Windows
GTQTC é a GT pra QT, o Harbour não cria por default - ainda não consegui gerar aqui

Uma boa de migrar pra gráfico

Enviado: 11 Mai 2013 14:03
por JoséQuintas
Sobre a configuração:
só precisa o harbour\bin no path e nada mais, a não ser que use algo externo ao harbour padrão.
O hbmk2 pega tudo automático.

Ainda não sei como gerar a GTQTC.

Foi isso que achei legal: Fiz pra qualquer gt pensando nas que testei gtwvt ou gtwvg, mas acabou funcionando até fora do Windows.
Pelo jeito não era só eu tentando encontrar um jeito diferente dos exemplos complicados existentes.

Uma boa de migrar pra gráfico

Enviado: 13 Mai 2013 18:30
por carlos_dornelas
Valeu!

Antonio Carlos

Uma boa de migrar pra gráfico

Enviado: 13 Mai 2013 18:53
por JoséQuintas
O fonte atualizado.
Agora tem opção de janela modal em windows.
E o tratamento de variável acessada por várias threads de uma vez.

Código: Selecionar todos

#include "hbgtinfo.ch"
#include "inkey.ch"

// comment this if not Windows OS
#define OS_WIN

PROCEDURE Main
   LOCAL nThreadId
   
   IF .NOT. ( hb_mtvm() .AND. hb_gtInfo( HB_GTI_VERSION ) $ "WVG,WVT,XWC,QTC" )
      CLS
      ? "Compile using -mt and the GT of your choice (-gtwvg, -gtwvt, -gtxwc, -gtqtc)"
      QUIT
   ENDIF
   nThreadId := hb_ThreadStart( { || MainMenu() } ) 
   ThreadRunning( nThreadId )
   DO WHILE ThreadRunning()
      Inkey(2)
   ENDDO
   RETURN

PROCEDURE MainMenu
   LOCAL nCont, nOpc := 0, nThreadId
#ifdef OS_WIN
   LOCAL hWnd
#endif 
   hb_gtReload( hb_gtInfo( HB_GTI_VERSION ) )
   SET SCOREBOARD OFF
   SET( _SET_EVENTMASK, INKEY_ALL - INKEY_MOVE + HB_INKEY_GTEVENT  )
   SetMode( 24, 80 )
   CLS
   DO WHILE .t.
      @ 10, 30 SAY hb_gtInfo( HB_GTI_VERSION )
      FOR nCont = 1 TO 10
         @ nCont + 1, 10 PROMPT "Option " + StrZero( nCont, 2 )
      NEXT
#ifdef OS_WIN
      @ Row() + 1, 10 PROMPT "Test Modal"
#endif      
      @ Row() + 2, 10 SAY "ESC exit"
      MENU TO nOpc
      IF LastKey() == K_ESC .OR. nOpc == 0
         EXIT
      ENDIF
      IF nOpc == 11
#ifdef OS_WIN
         hWnd := wapi_GetActiveWindow()
         nThreadId := hb_ThreadStart( { || WAPI_EnableWindow( hWnd, 0 ), MyModule(), WAPI_EnableWindow( hWnd, 1 ), WAPI_SetForegroundWindow( hWnd ) } )
         ThreadRunning( nThreadId )
#endif         
      ELSE
         nThreadId := hb_ThreadStart( { || MyModule() } )
         ThreadRunning( nThreadId )
      ENDIF
   ENDDO
   RETURN

FUNCTION MyModule()
   LOCAL GetList := {}, cText
   hb_gtReload( hb_gtInfo( HB_GTI_VERSION ) )
   SetMode( 24, 80 )
   CLS
   hb_gtInfo( HB_GTI_WINTITLE, "This is the test module" )
   cText := Pad( "Testing", 50 )
   @ 5, 10 SAY hb_gtInfo( HB_GTI_VERSION )
   @ Row() + 1, 10 SAY "AnyText:" GET cText
   READ
   RETURN NIL

FUNCTION ThreadRunning( nThreadId )
   STATIC aThreadList := {}, s_Mutex := hb_MutexCreate()
   LOCAL  nCont, lIsRunning := .f.
   
   hb_MutexLock( s_Mutex ) // because var aThreadList will be used by all threads
   
   IF nThreadId == NIL
      IF Len( aThreadList ) != 0
         lIsRunning := .f.
         FOR nCont = Len( aThreadList ) TO 1 STEP -1
            IF hb_ThreadWait( aThreadList[ nCont ], 0.1, .t. ) != 1
               lIsRunning := .t.
            ELSE
               aDel( aThreadList, nCont )
               aSize( aThreadList, Len( aThreadList ) - 1 )
            ENDIF
         NEXT
      ENDIF
   ELSE
      Aadd( aThreadList, nThreadId )
   ENDIF   
   hb_MutexUnlock( s_Mutex )
   RETURN lIsRunning


#ifdef OS_WIN

#include "hbdyn.ch"
#define WAPI_KERNEL32    1
#define WAPI_USER32      2
#define WAPI_ADVAPI32    3

// Available in hbwin
FUNCTION wapi_EnableWindow( hWnd, nEnable )
   wapi_DllFunction( "EnableWindow", WAPI_USER32, hWnd, nEnable )
   RETURN NIL

// Available in hbwin
FUNCTION wapi_GetActiveWindow()
   LOCAL hWnd
   hWnd := wapi_DllFunction( "GetActiveWindow", WAPI_USER32 )
   RETURN hWnd

FUNCTION wapi_SetForegroundWindow( hWnd )
   wapi_DllFunction( "SetForegroundWindow", WAPI_USER32, hWnd )
   RETURN NIL

// caution: can cause GPF in wrong use
FUNCTION wapi_DllFunction( cFunctionName, nDll, ... )
   LOCAL hHandleDll, nVar, cDllName
   
   DO CASE
   CASE nDll == WAPI_USER32
      cDllName := "user32.dll"
   CASE nDll == WAPI_KERNEL32
      cDllName := "kernel32.dll"
   CASE nDll == WAPI_ADVAPI32
      cDllName := "advapi32.dll"
   OTHERWISE
      RETURN "*dll error*"
   ENDCASE
   hHandleDll := hb_LibLoad( cDllName )
   nVar := hb_DynCall( { cFunctionName, hHandleDll, HB_DYN_CALLCONV_STDCALL }, ... )
   hb_LibFree( hHandleDll )
   RETURN nVar
#endif

Uma boa de migrar pra gráfico

Enviado: 16 Mai 2013 12:34
por Duda 'Sgluber'
Quintas,

parabéns pelo trabalho e pelo sucesso "international"! :-)

Curiosidade: o q seria acrescentado neste seu exemplo se quiséssemos exibir uma imagem de fundo em cada janela aberta?

Imagino q seja simples, mas como nunca pesquisei sobre isto, gostaria de aproveitar este tópico e um pouco do seu conhecimento. ;-)

Uma boa de migrar pra gráfico

Enviado: 16 Mai 2013 14:22
por JoséQuintas
Esta é a parte básica, valida pra qualquer GT.
A partir dai cada GT tem sua função diferente, que pode ou não ter tela de fundo.
Eu cheguei a colocar na gtwvg, mas por causa de como foi projetada, qualquer espaço em branco cobre o fundo, e um CLS apaga tudo.

Uma boa de migrar pra gráfico

Enviado: 05 Jun 2013 13:54
por JoséQuintas
Foi incluso no harbour 3.2 o fonte: tests\mt\mttest10.prg
É praticamente essa rotina, ao mesmo tempo simplificada e melhorada.
Como é um exemplo e usa somente 3 janelas adicionais, não tem menu, nem o tratamento de reduzir o tamanho de array, mas tem indicação de algo diferente pra QTC.

Como eu mesmo já reclamei de exemplos do Harbour que complicam, entendo porque não foi o fonte original.

Não tem meu nome.... mas pensei...
Não é meu fonte, não sou eu que vou melhorar/modificar o exemplo, é uma parte muito simples no conjunto, e se for colocar o nome de todo mundo que construir/melhorar uma rotina, vamos acabar tendo 50% de código fonte só com nomes.

Fiquei feliz, já que uso isso no meu sistema, e fazer parte de exemplos do Harbour indica que a idéia realmente é boa.
É uma coisa relativamente simples, mas minha sensação foi como estar em uma corrida, e deixar de ser um dos últimos.
Só compartilhando a sensação.

Uma boa de migrar pra gráfico

Enviado: 05 Jun 2013 18:03
por Vlademiro
:D

Valeu!

Uma boa de migrar pra gráfico

Enviado: 05 Jun 2013 19:03
por Hasse
Não vi qualquer menção à MiniGUI. Nela não funciona ?