Page 1 of 1

[Solved] #PB_ANY or Gadget creation limitations

Posted: Tue Sep 02, 2025 8:52 pm
by jimcorr
It all started with me wondering if i created windows and gadgets all using #pb_any and the user working for several days opening and closing windows if it would be unlimited.

I created a code that opens and closes the same window for 500 times and i receive 0 from the gadget creation at some point.

Is it a limitation, of what? Or am i doing something wrong?

PS: this is a simplified version of the final code with the minimal parts for execution.

thanks,

Code: Select all

DeclareModule mglobal
  Enumeration #PB_Event_FirstCustomValue
    #EventBeginProcessing
    #EventUpdateThread
    #EventProcessingFinished
    #EventAtualizaGui
  EndEnumeration
  
  Define vi_tp_db.i
  vi_tp_db = 0
  
EndDeclareModule
Module mglobal
  
EndModule

DeclareModule mwnd
  
  Structure st_gadgets
    ;vs_nm_gadget.s ja eh a chave...
    vq0_id_gadget.q
  EndStructure
  
  Structure st_properties
    vq0_id_window.q
    vq0_handle.q
    vq0_close_window.q
    vs_nm_modulo.s
    vi_id_retorno_thread.i
    vs_nm_retorno_thread.s
    Map vm_gadgets.st_gadgets()
  EndStructure
  
  Define vq0_id_mae.q
  
  Declare.q create_window(*vst_properties.st_properties, pid_estrutura.q, pq0_id_window.q) 
  Declare.q create_gadget(*vst_properties.st_properties, pnm_gadget.s, pq0_gadget.q)
  
  Macro ID_Gadget(pnm_gadget)
    *vst_window\vst_properties\vm_gadgets(pnm_gadget)\vq0_id_gadget
  EndMacro
  
  Macro ID_Window()
    *vst_window\vst_properties\vq0_id_window
  EndMacro
  
  Macro ID_Handle()
    *vst_window\vst_properties\vq0_handle
  EndMacro
  
  Macro Add_Window(pq0_id_window)
    mwnd::create_window(*vst_window\vst_properties, *vst_window, pq0_id_window) 
  EndMacro
  
  Macro ADD_Gadget(pnm_gadget, pid_gadget)
    mwnd::create_gadget(*vst_window\vst_properties, pnm_gadget, pid_gadget) 
  EndMacro
  
  Define vq0_id_ult_janela.q
  
EndDeclareModule
Module mwnd
  EnableExplicit
  
  Procedure.q create_gadget(*vst_properties.st_properties, pnm_gadget.s, pq0_gadget.q)
    
    Define vq0_id_procedure.q    
    
    If pq0_gadget > 0
      *vst_properties\vm_gadgets(pnm_gadget)\vq0_id_gadget = pq0_gadget
      
      vq0_id_procedure = GetRuntimeInteger(*vst_properties\vs_nm_modulo + "::" + pnm_gadget + "_event()")
      If vq0_id_procedure
        BindGadgetEvent(pq0_gadget, vq0_id_procedure)
      EndIf      
      
    Else
      Debug "fail to create gadget: " + pnm_gadget + "id: " + pq0_gadget
      End
    EndIf
    
    ProcedureReturn pq0_gadget
    
  EndProcedure
  
  Procedure.q create_window(*vst_properties.st_properties, pid_estrutura.q, pq0_id_window.q)
    
    Define vq0_id_procedure.q
    
    If pq0_id_window
      *vst_properties\vq0_handle = WindowID(pq0_id_window)
      *vst_properties\vq0_id_window = pq0_id_window
      
      vq0_id_procedure = GetRuntimeInteger(*vst_properties\vs_nm_modulo + "::" + "window_event()")
      If vq0_id_procedure
        BindEvent(#PB_Event_CloseWindow, vq0_id_procedure, pq0_id_window)
        BindEvent(#PB_Event_SizeWindow, vq0_id_procedure, pq0_id_window)
        BindEvent(#PB_Event_MoveWindow, vq0_id_procedure, pq0_id_window)
        BindEvent(#PB_Event_MinimizeWindow, vq0_id_procedure, pq0_id_window)
        BindEvent(#PB_Event_RestoreWindow, vq0_id_procedure, pq0_id_window)
        BindEvent(#PB_Event_ActivateWindow, vq0_id_procedure, pq0_id_window)
        BindEvent(#PB_Event_DeactivateWindow, vq0_id_procedure, pq0_id_window)
        BindEvent(#PB_Event_WindowDrop, vq0_id_procedure, pq0_id_window)
        BindEvent(#PB_Event_RightClick, vq0_id_procedure, pq0_id_window)
        BindEvent(#PB_Event_LeftClick, vq0_id_procedure, pq0_id_window)
        BindEvent(#PB_Event_LeftDoubleClick, vq0_id_procedure, pq0_id_window)
      EndIf
      
      SetWindowData(pq0_id_window, pid_estrutura)
      
      mwnd::vq0_id_ult_janela = pq0_id_window
    EndIf

    ProcedureReturn pq0_id_window
  EndProcedure
 
  
EndModule

;do programa atual
DeclareModule mimporta_csv
  
  Structure st_thread_csv
    vq0_id_ativo.q
    vq0_id_dados_ativos.q
    vs_descricao_dados_ativos.s
    vs_fl_sobrescrever.s
    vs_nm_arquivo.s
    vs_origem_dados.s
    vi_pc_barra.i
    vq0_id_window.q
  EndStructure
  
  Structure st_window
    vst_properties.mwnd::st_properties
    vst_thread_csv.st_thread_csv

  EndStructure  
  
  Declare init() 
  Declare clique_importar()
  Declare clique_destino()
  Declare thread_importa_csv(*xxx.st_window)
  Declare callback_thread() 
  
  Global vs_nm_modulo.s = "mimporta_csv"
  
  
EndDeclareModule
Module mimporta_csv
  
  EnableExplicit
  
  Procedure destroy()
    Define *vst_window.st_window = GetWindowData(EventWindow())
    
    FreeStructure(*vst_window)
    
  EndProcedure
  
  Procedure callback_thread()
    Define *vst_window.st_window = GetWindowData(EventWindow())
    
    If Event() = mglobal::#EventUpdateThread 
      SetGadgetState(mwnd::ID_Gadget("pb_importacao"), *vst_window\vst_thread_csv\vi_pc_barra)
    ElseIf Event() = mglobal::#EventProcessingFinished
      SetGadgetText(mwnd::ID_Gadget("txt_log"), GetGadgetText(mwnd::ID_Gadget("txt_log")) + #CRLF$ +  "Fim: " + FormatDate("%hh:%ii:%ss", Date()))
      
      SetGadgetState(mwnd::ID_Gadget("pb_importacao"), 100)
      DisableGadget(mwnd::ID_Gadget("btn_iniciar"), #False)
      DisableWindow(mwnd::ID_Window(), #False)
      MessageRequester("Fim", "Operação Finalizada!")
      SetGadgetState(mwnd::ID_Gadget("pb_importacao"), 0)
    EndIf
  EndProcedure
  
  Procedure prepara_tela(ps_destino.s, *vst_window.st_window)
    
    If ps_destino = "rb_base"
      
      DisableGadget(mwnd::ID_Gadget("cmb_ativo"), #False)
      DisableGadget(mwnd::ID_Gadget("edt_id_dados_ativo"), #False)
      DisableGadget(mwnd::ID_Gadget("edt_descricao_dados_ativo"), #False)
      DisableGadget(mwnd::ID_Gadget("btn_id_dados_ativo"), #False)
      DisableGadget(mwnd::ID_Gadget("btn_limpa_dados_ativo"), #False)
      DisableGadget(mwnd::ID_Gadget("edt_nm_arquivo_db"), #True)
      DisableGadget(mwnd::ID_Gadget("btn_db"), #True)
      
    Else
      
      DisableGadget(mwnd::ID_Gadget("cmb_ativo"), #True)
      DisableGadget(mwnd::ID_Gadget("edt_id_dados_ativo"), #True)
      DisableGadget(mwnd::ID_Gadget("edt_descricao_dados_ativo"), #True)
      DisableGadget(mwnd::ID_Gadget("btn_id_dados_ativo"), #True)
      DisableGadget(mwnd::ID_Gadget("btn_limpa_dados_ativo"), #True)
      DisableGadget(mwnd::ID_Gadget("edt_nm_arquivo_db"), #False)
      DisableGadget(mwnd::ID_Gadget("btn_db"), #False)      
      
    EndIf
    
  EndProcedure
  
  Procedure init()
    
    Define *vst_window.st_window
    *vst_window.st_window = AllocateStructure(st_window)
    *vst_window\vst_properties\vs_nm_modulo = vs_nm_modulo

    If mwnd::Add_Window(OpenWindow(#PB_Any, 100, 300, 500, 440, "Importa CSV", 
                                   #PB_Window_MinimizeGadget | #PB_Window_WindowCentered | #PB_Window_Invisible, 
                                   WindowID(mwnd::vq0_id_mae)))    
      
      BindEvent(mglobal::#EventProcessingFinished, @callback_thread(), mwnd::ID_Window())
      BindEvent(mglobal::#EventUpdateThread, @callback_thread(), mwnd::ID_Window())
      
      mwnd::ADD_Gadget("frm_origem", FrameGadget(#PB_Any, 5, 10, 490, 90, "CSV Origem"))
      
      mwnd::ADD_Gadget("frm_formato_dados", FrameGadget(#PB_Any, 10, 25, 195, 40, "Formato dos dados"))
      mwnd::ADD_Gadget("rb_mt5", OptionGadget(#PB_Any, 25, 40, 60, 20, "MT5"))
      mwnd::ADD_Gadget("rb_profit", OptionGadget(#PB_Any, 105, 40, 70, 20, "Profit"))
      SetGadgetState(mwnd::ID_Gadget("rb_mt5"), 1)
      
      mwnd::ADD_Gadget("lbl_csv", TextGadget(#PB_Any, 10, 72, 200, 24, "Arquivo"))
      mwnd::ADD_Gadget("edt_nm_arquivo_csv", StringGadget(#PB_Any, 70, 70, 390, 22, ""))
      mwnd::ADD_Gadget("btn_csv", ButtonGadget(#PB_Any, 469, 69, 20, 24, "..."))
      
      mwnd::ADD_Gadget("frm_destino_dados", FrameGadget(#PB_Any, 5, 105, 195, 40, "Destino Importação"))
      mwnd::ADD_Gadget("rb_base", OptionGadget(#PB_Any, 20, 120, 70, 20, "DB Base"))
      mwnd::ADD_Gadget("rb_db", OptionGadget(#PB_Any, 100, 120, 70, 20, "DB SQLite Avulso"))
      SetGadgetState(mwnd::ID_Gadget("rb_base"), 1)
      BindGadgetEvent(mwnd::ID_Gadget("rb_base"), @clique_destino())    
      BindGadgetEvent(mwnd::ID_Gadget("rb_db"), @clique_destino())    
      
      mwnd::ADD_Gadget("frm_arquivo_db", FrameGadget(#PB_Any, 5, 150, 490, 50, "Informações DB SQLite Avulso"))
      
      mwnd::ADD_Gadget("lbl_db", TextGadget(#PB_Any, 10, 172, 200, 24, "Arquivo"))
      mwnd::ADD_Gadget("edt_nm_arquivo_db", StringGadget(#PB_Any, 70, 170, 390, 22, ""))
      mwnd::ADD_Gadget("btn_db", ButtonGadget(#PB_Any, 469, 169, 20, 24, "..."))
      
      mwnd::ADD_Gadget("frm_dados_ativo", FrameGadget(#PB_Any, 5, 205, 490, 110, "Informações DB Base"))
      
      mwnd::ADD_Gadget("lbl_id_ativo", TextGadget(#PB_Any, 10, 227, 200, 24, "Ativo"))
      ; TODO isso aqui deveria carregar atraves de um select...
      mwnd::ADD_Gadget("cmb_ativo", ComboBoxGadget(#PB_Any, 70, 225, 200, 22))
      AddGadgetItem(mwnd::ID_Gadget("cmb_ativo"), -1,"Mini Índice B3")
      SetGadgetItemData(mwnd::ID_Gadget("cmb_ativo"), CountGadgetItems(mwnd::ID_Gadget("cmb_ativo")) - 1, 1)
      AddGadgetItem(mwnd::ID_Gadget("cmb_ativo"), -1,"Mini Dólar B3")
      SetGadgetItemData(mwnd::ID_Gadget("cmb_ativo"), CountGadgetItems(mwnd::ID_Gadget("cmb_ativo")) - 1, 2)
      SetGadgetState(mwnd::ID_Gadget("cmb_ativo"), 0)
      
      
      mwnd::ADD_Gadget("lbl_id_dados_ativo", TextGadget(#PB_Any, 12, 257, 200, 24, "ID"))
      mwnd::ADD_Gadget("edt_id_dados_ativo", StringGadget(#PB_Any, 70, 255, 70, 22, ""))
      
      mwnd::ADD_Gadget("btn_id_dados_ativo", ButtonGadget(#PB_Any, 144, 254, 20, 24, "..."))
      mwnd::ADD_Gadget("btn_limpa_dados_ativo", ButtonGadget(#PB_Any, 166, 254, 20, 24, "X"))
      
      mwnd::ADD_Gadget("lbl_descricao_dados_ativo", TextGadget(#PB_Any, 12, 287, 200, 24, "Descrição"))
      mwnd::ADD_Gadget("edt_descricao_dados_ativo", StringGadget(#PB_Any, 70, 285, 420, 22, ""))
      
      
      mwnd::ADD_Gadget("btn_iniciar", ButtonGadget(#PB_Any, 10, 320, 100, 24, "Importar"))
      BindGadgetEvent(mwnd::ID_Gadget("btn_iniciar"), @clique_importar())    
      
      mwnd::ADD_Gadget("pb_importacao", ProgressBarGadget(#PB_Any, 115, 321, 373, 22, 0, 100, #PB_ProgressBar_Smooth))
      SetGadgetState(mwnd::ID_Gadget("pb_importacao"), 0)
      
      mwnd::ADD_Gadget("txt_log", EditorGadget(#PB_Any, 10, 350, 480, 85))
      DisableGadget(mwnd::ID_Gadget("txt_log"), #True)

      
      SetActiveGadget(mwnd::ID_Gadget("rb_base"))
      prepara_tela("rb_base", *vst_window.st_window)
      
      ;HideWindow(mwnd::ID_Window(), #False)
      
    Else
      MessageRequester("Error!", "Error...!")      
    EndIf
    
  EndProcedure
  
  Runtime Procedure window_event()

    Select Event()
      Case #PB_Event_CloseWindow
        destroy()
        CloseWindow(EventWindow())
    EndSelect
    
  EndProcedure
  
    
  Runtime Procedure rb_profit_event()
    Define *vst_window.st_window = GetWindowData(EventWindow())
    
    Select EventType()
      Case -#PB_EventType_LeftClick 
        MessageRequester("", "Não implementado!")
        SetGadgetState(mwnd::ID_Gadget("rb_mt5"), 1)
    EndSelect
    
  EndProcedure        
    
    Procedure clique_destino()
      If  EventType() = #PB_EventType_LeftClick
        Define *vst_window.st_window = GetWindowData(EventWindow())
        Select EventGadget()
          Case mwnd::ID_Gadget("rb_base")
            prepara_tela("rb_base", *vst_window.st_window)
          Default
            prepara_tela("rb_db", *vst_window.st_window)
        EndSelect
      EndIf      
    EndProcedure
    
    Runtime Procedure btn_csv_event()
    EndProcedure
    
  
  Procedure clique_importar()
    

    
  EndProcedure  

  
  Procedure thread_importa_csv(*vst_window.st_window) 
  EndProcedure
    
EndModule


DeclareModule mapp
  Declare init()
  Declare destroy()
  Declare test()
  Declare load_connections()
  
  Define vs_nm_dir_dados.s
  Define vs_nm_dir_logs.s
  Define vs_nm_dir_csv.s
  
EndDeclareModule
Module mapp
  EnableExplicit
  
  ;eh global do modulo, nao da aplicacao toda, fica inacessivel para fora...
  Global vq0_id_menu.q
  
  Procedure executa_menu()
    Define item.i
    
    item = EventMenu()
    
    If item = 1 
      test()
    EndIf
    
    ;End
  EndProcedure
  
  Procedure init()
    ;abrir uma janela init, que será a base do sistema...
    Define event.i
    Define quit.i
    
    load_connections()
    
    mwnd::vq0_id_mae = OpenWindow(#PB_Any, 0, 0, 800, 600, "Main", #PB_Window_ScreenCentered|#PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget|#PB_Window_Invisible)
    SetWindowState(mwnd::vq0_id_mae, #PB_Window_Maximize)
    HideWindow(mwnd::vq0_id_mae, #False)
    
    vq0_id_menu = CreateMenu(#PB_Any, WindowID(mwnd::vq0_id_mae))
    If vq0_id_menu
      MenuTitle("Geral")
        MenuItem(1, "Test")
        BindMenuEvent(vq0_id_menu, 1, @executa_menu())
    EndIf
    
    Repeat
      Event = WaitWindowEvent()
      If Event = #PB_Event_CloseWindow
        If EventWindow() = mwnd::vq0_id_mae
          destroy()
        EndIf
      EndIf
    Until Quit = 1    
  EndProcedure
  
  Procedure destroy()
    ; TODO precisa ver o que mais temos que fazer free, para nao ficar leak de memoria...
    End
  EndProcedure
  
  Procedure load_connections()

  EndProcedure
  
  Procedure test()
    Define i.i
    
    For i = 1 To 500
      ;it'll create the window but it wont show it, just set it's gadget id on  mwnd::vq0_id_ult_janela
      mimporta_csv::init()
      Debug Str(i) + ": " + mwnd::vq0_id_ult_janela
      ;send event to close the window
      PostEvent(#PB_Event_CloseWindow, mwnd::vq0_id_ult_janela, #PB_Ignore)
    Next i
  EndProcedure
EndModule

mapp::init()

End

Re: #PB_ANY or Gadget creation limitations

Posted: Wed Sep 03, 2025 10:53 am
by Axolotl
I would always assume that everything has a maximum value, even if the maximum values can be very large.
Just some thoughts about this.... (You don't have to agree with me)
There is a reason why there are return values that also represent an error case.
When dealing with dynamic objects, you have to pay particular attention to resource consumption. (You learned this when programming under Win16, where pens and brushes ran out faster than you could blink.)
Use a tool (e.g., Task Manager) to monitor consumption.
The longer the program runs continuously, the more important this becomes.

Re: #PB_ANY or Gadget creation limitations

Posted: Wed Sep 03, 2025 1:41 pm
by jimcorr
Thanks for the answer, Axolotl, i'll keep that in mind

I found out that the issue was due to the fact that i was doing it inside a for and it wasn't processing the closewindow events, therefore, the windows were not being closed.

Once i closed the window, i was able to recreate the window as many times as needed.

Re: [Solved] #PB_ANY or Gadget creation limitations

Posted: Wed Sep 03, 2025 1:42 pm
by Fred
also all your '.q' type is wrong, it should be '.i' (or better, nothing as specified in the doc)

Re: [Solved] #PB_ANY or Gadget creation limitations

Posted: Wed Sep 03, 2025 6:54 pm
by jimcorr
Thanks, Fred, i'll fix that too.

Re: [Solved] #PB_ANY or Gadget creation limitations

Posted: Fri Sep 05, 2025 4:22 pm
by SMaag
maybe you explain what is your goal.
Your code looks complicated and it is not the best for debugging.
I'm sure there are more clear solutions for your problem.