Ultimatelistctrl dont show button when run in thread

Hi, when i run my ulc without threads everything load fine but when i run inside a thread the buttons dont show:

    def onBtnFecha(self, event):
        workThread = threading.Thread(target=self.pagos) 
        workThread.start()

    def pagos(self):
        self.lista.indice = 0 
        self.lista.rellenar_ulc()  # load info in ulc

->self.lista its my myultimatelistctrl

How i run my ulc without threads:


    def onBtnFecha(self, event):
        self.lista.indice = 0 
        self.lista.rellenar_ulc()

everythings loads fine

anyone can help me? i dont have experience with threads but i think its ok.

this is how i add buttons but i think is not the problem:

def rellenar_ulc(self):
        self.DeleteAllItems()
        self.pagos = Pagos(parent=self, ingresado='no',
                               fecha_desde=self.parent.fecha_desde.GetValue(), fecha_hasta=self.parent.fecha_hasta.GetValue())


        for (row, link) in zip(self.pagos.lista_datos, self.pagos.lista_links):
            dic = {'j' : row[0],
                    'd' : row[1],
                    'i' : row[2],
                    'f' : row[3],
                    'fc' : row[4],
                    'fl' : row[5],
                    'i' : row[6],
                    'mrn' : row[7],
                    'index' : self.indice,
                    'link' : link
                   }
            padre = self.Append(row)
            item_0 = self.GetItem(self.indice, 0)  # capturamos item
            item_0.SetPyData(dic)                   # le metemos el diccionoario
            item_0.SetText('')                      # quitamos el texto porque lo vamos a poner en el boton
            self.SetItem(item_0)                    # y reestablecemos el item

            btn0= wx.Button(self, wx.ID_ANY, row[0], style= wx.BORDER_NONE | wx.BU_NOTEXT)
            btn0.Bind(wx.EVT_BUTTON, self.onboton_fila)
            btn0.Row = self.indice  
            self.SetItemWindow(self.indice, col=0, wnd=btn0, expand=True)
            self.indice = self.indice + 1

sorry for my english and thanks in advance

full example with python 3.8.3, wxpython 4.1.0 and Windows 10

import wx

import wx.lib.agw.ultimatelistctrl as ULC

import threading


class Ventana(wx.Frame):
    def __init__(self, *args, **kwargs):
        super().__init__(parent=None, title='Titulo')
        self.panel = wx.Panel(self, wx.ID_ANY)
        self.tabla = ULC.UltimateListCtrl(self.panel, wx.ID_ANY,agwStyle=ULC.ULC_REPORT | ULC.ULC_VRULES | ULC.ULC_HRULES | ULC.ULC_STICKY_HIGHLIGHT |
                                             ULC.ULC_NO_HIGHLIGHT  | ULC.ULC_SINGLE_SEL | ULC.ULC_HAS_VARIABLE_ROW_HEIGHT | ULC.ULC_FOOTER)

        self.indice = 0

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.tabla, 1, wx.EXPAND, 0)
        self.cabecera()
        self.panel.SetSizer(sizer)
        self.SetSize((800,600))
        
        # self.rellenar_tabla()   # No problem, button showed in col 0

        workThread = threading.Thread(target=self.rellenar_tabla)   # button dont showss
        workThread.start()

    def cabecera(self):
        font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
        titulo_col = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
        titulo_col.SetWeight(wx.BOLD)
        titulo_col.SetPointSize(9)

        info = ULC.UltimateListItem()
        # info._format = wx.LIST_FORMAT_RIGHT
        info.SetAlign(2)  # 0: LIST_FORMAT_LEFT (align_left), 1: LIST_FORMAT_RIGhT (align_right), 2: LIST_FORMAT_CENTER (align_center
        # info._mask = wx.LIST_MASK_TEXT | ULC.ULC_MASK_PYDATA | wx.LIST_MASK_FORMAT | ULC.ULC_MASK_FONT | ULC.ULC_MASK_HYPERTEXT
        info.SetMask(wx.LIST_MASK_TEXT | ULC.ULC_MASK_PYDATA | wx.LIST_MASK_FORMAT | ULC.ULC_MASK_FONT)
        # info._image = []
        info.SetImage([])
        # info._text = "Title"
        info.SetText("Justificante")
        info._font = titulo_col
        # info.SetFont(boldfont)
        # info.SetPyData(pyObject) # pyObject puede ser cualquier objeto python (diccionario, lista, clase propia etc)
        # info.SetWidth(-3)  # autofill
        self.tabla.InsertColumnInfo(0, info)

        info = ULC.UltimateListItem()
        info.SetAlign(2)  # 0: LIST_FORMAT_LEFT (align_left), 1: LIST_FORMAT_RIGhT (align_right), 2: LIST_FORMAT_CENTER (align_center
        info.SetMask(wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT | ULC.ULC_MASK_FONT )
        info.SetText("Documento")
        info._font = titulo_col
        # info.SetFont(boldfont)
        # info.SetWidth(100)
        self.tabla.InsertColumnInfo(1, info)

        info = ULC.UltimateListItem()
        info.SetAlign(
            2)  # 0: LIST_FORMAT_LEFT (align_left), 1: LIST_FORMAT_RIGhT (align_right), 2: LIST_FORMAT_CENTER (align_center
        info.SetMask(wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT | ULC.ULC_MASK_FONT  )
        info.SetText("Importador")
        info._font = titulo_col
        # info.SetFont(boldfont)
        # info.SetWidth(100)
        self.tabla.InsertColumnInfo(2, info)

        info = ULC.UltimateListItem()
        info.SetAlign(
            2)  # 0: LIST_FORMAT_LEFT (align_left), 1: LIST_FORMAT_RIGhT (align_right), 2: LIST_FORMAT_CENTER (align_center
        info.SetMask(wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT | ULC.ULC_MASK_FONT)
        info.SetText("Declarante")
        info._font = titulo_col
        # info.SetFont(boldfont)
        # info.SetWidth(200)
        self.tabla.InsertColumnInfo(3, info)

        info = ULC.UltimateListItem()
        info.SetAlign(
            2)  # 0: LIST_FORMAT_LEFT (align_left), 1: LIST_FORMAT_RIGhT (align_right), 2: LIST_FORMAT_CENTER (align_center
        info.SetMask(wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT | ULC.ULC_MASK_FONT)
        info.SetText("Fecha de Contraccion")
        info._font = titulo_col
        # info.SetFont(boldfont)
        # info.SetWidth(100)
        self.tabla.InsertColumnInfo(4, info)

        info = ULC.UltimateListItem()
        info.SetAlign(
            2)  # 0: LIST_FORMAT_LEFT (align_left), 1: LIST_FORMAT_RIGhT (align_right), 2: LIST_FORMAT_CENTER (align_center
        info.SetMask(wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT | ULC.ULC_MASK_FONT)
        info.SetText("Fecha Limite")
        info._font = titulo_col
        # info.SetFont(boldfont)
        # info.SetWidth(100)

        self.tabla.InsertColumnInfo(5, info)

        info = ULC.UltimateListItem()
        info.SetAlign(2)  # 0: LIST_FORMAT_LEFT (align_left), 1: LIST_FORMAT_RIGhT (align_right), 2: LIST_FORMAT_CENTER (align_center
        info.SetMask(wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT | ULC.ULC_MASK_FONT)
        info.SetText("Importe")
        info._font = titulo_col
        # info.SetFont(titulo_col)
        # info.SetWidth(100)

        self.tabla.InsertColumnInfo(6, info)

        info = ULC.UltimateListItem()
        info.SetAlign(2)  # 0: LIST_FORMAT_LEFT (align_left), 1: LIST_FORMAT_RIGhT (align_right), 2: LIST_FORMAT_CENTER (align_center
        info.SetMask(wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT | ULC.ULC_MASK_FONT)
        info.SetText("MRN")
        info._font = titulo_col
        # info.SetFont(boldfont)
        # info.SetWidth(100)
        self.tabla.InsertColumnInfo(7, info)

        self.tabla.SetColumnWidth(0, -3)
        self.tabla.SetColumnWidth(1, 170)  # -1,-2,-3 #https: // docs.wxpython.org / wx.lib.agw.ultimatelistctrl.UltimateListCtrl.html  # wx.lib.agw.ultimatelistctrl.UltimateListCtrl.SetColumnWidth
        self.tabla.SetColumnWidth(2, 100)
        self.tabla.SetColumnWidth(3, 100)
        self.tabla.SetColumnWidth(4, 150)
        self.tabla.SetColumnWidth(5, 150)
        self.tabla.SetColumnWidth(6, 100)
        self.tabla.SetColumnWidth(7, 200)
        # self.SetColumnWidth(8, 100)        
    
    def rellenar_tabla(self):
        print('rellenar')
        fila= ( 'col1','col2','col3', 'col4', 'col5', 'col6', 'col7', 'col8')
        self.tabla.Append(fila)

        boton_justificante = wx.Button(self.tabla, wx.ID_ANY, 'value', style= wx.BORDER_NONE | wx.BU_NOTEXT)
        boton_justificante.Row = self.indice  
        self.tabla.SetItemWindow(self.indice, col=0, wnd=boton_justificante, expand=True)
        self.indice = self.indice + 1


class App(wx.App):
    def __init__(self, *args, **kwargs):
        super().__init__()
    def OnInit(self):
        ventana = Ventana()
        self.SetTopWindow(ventana)
        ventana.Show()

        return True
    
    def InitLocale(self): 
        self.ResetLocale()
        import locale
        lang, enc = locale.getdefaultlocale()
        self._initial_locale = wx.Locale(lang, lang[:2], lang)
        locale.setlocale(locale.LC_ALL, lang)
if __name__ == '__main__':

    app = App()
    app.MainLoop()

Only the main thread can interact with wxPython / the GUI.
There’s lots of good info on the internet about this. For
example, see
or or
, the top 3 Google
hits I got on the topic.

Hope that helps,

David

thanks you David u are correct!. Then i need to changes things in my class Pagos. I Need advices: while i collect data from my class Pagos (from a thread), i send pubsub message to Update my ProgressBar, then thread still alive in this pub message so i dont know how to call self.tabla.rellenar_tabla when the thread is end, in full example before .join() works fine after .start() but in my entire app when I try with join() thread get stopped, if i try join(5) my thread starts in 5sec but not wait to end:confused:
I put another button that with the collected data from before i fill ULC with self.tabla.rellenar_tabla() and the buttons works fine

thanks in advance and again sorry for my english, is not very strong :slight_smile:

When your thread is finished simply use:

wx.CallAfter(self.tabla.rellenar_tabla)

Note: no parentheses at the end.

Now yes… thanks you Andrea!!!