Search code examples
pythonpython-3.xwxpython

Image is not displaying at runtime in panel, wxpython


I am trying to display all images from image folder using for loop and that all displayed correctly. But i want to add another image at runtime so I use threading here threading.Timer(2.0, self.basicgui).start() whenever I add new image to folder i can see the name of image in image list but it can't be updated. i want to refresh panel to show updated image how can i fix this.

    import wx
    import threading
    from PIL import Image
    import wx.lib.scrolledpanel
    import os


    class windowclass(wx.Frame):

        def __init__(self, *args, **kwargs):
            super(windowclass, self).__init__(*args, **kwargs)
            global panel1
            panel1 = wx.Panel(self,size=(1000,28), pos=(0,0), style=wx.SIMPLE_BORDER)
            panel1.SetBackgroundColour('#FDDF99')
            global panel2
            panel2 = wx.lib.scrolledpanel.ScrolledPanel(panel1,-1, size=(350,710), pos=(1010,0), style=wx.SIMPLE_BORDER)
            panel2.SetupScrolling()
            panel2.SetBackgroundColour('#FFFFFF')
            self.basicgui()


        def basicgui(self):
            padding = 0
            bSizer = wx.BoxSizer( wx.VERTICAL )
            self.jpgs = GetJpgList("./image")
            allimage = len(self.jpgs)
            print(allimage)


            for i in range(0,allimage):
                #print("i=",i)
                bitmap = wx.Bitmap(self.jpgs[i])
                image = wx.ImageFromBitmap(bitmap)
                image = image.Scale(300, 200, wx.IMAGE_QUALITY_HIGH)
                bitmap = wx.BitmapFromImage(image)
                control = wx.StaticBitmap(panel2, -1, bitmap)
                #print(control)
                control.SetPosition((10, padding+10))
                padding += 210
                bSizer.Add( control, 0, wx.ALL, 5 )
            panel2.SetSizer( bSizer )
            panel2.Layout()
            threading.Timer(2.0, self.basicgui).start()        
            self.Show()
            return


    def GetJpgList(dir):
        jpgs = [f for f in os.listdir(dir) if f[-4:] == ".jpg"]
        # print "JPGS are:", jpgs
        return [os.path.join(dir, f) for f in jpgs]


    def main():
        app = wx.App()
        windowclass(None)
        app.MainLoop()


    main()

Solution

  • Here is your code, amended to be a bit more efficient.
    Currently, you generate the images every time, which with a small number may be fine but if there are a lot of images this will eat your cpu.
    Here, I've built a dictionary of the images, so only additions and deletions need to be transformed. It's also useful to discover if any work needs to be done at all, so I've assumed that a simple count can tell me that nothing has changed and therefore no work needs to be done.

    import wx
    import wx.lib.scrolledpanel
    import glob
    
    class windowclass(wx.Frame):
        def __init__(self, *args, **kwargs):
            super(windowclass, self).__init__(*args, **kwargs)
            self.panel1 = wx.Panel(self,size=(1000,28), style=wx.SIMPLE_BORDER)
            self.panel1.SetBackgroundColour('#FDDF99')
            self.panel2 = wx.lib.scrolledpanel.ScrolledPanel(self.panel1,-1, size=(350,550))
            self.panel2.SetupScrolling()
            self.panel2.SetBackgroundColour('#FFFFFF')
            self.panel2.SetMinSize((350,550))
            self.timer = wx.Timer(self)
            self.Bind(wx.EVT_TIMER, self.basicgui, self.timer)
            self.dict = {}
    
            self.bSizer = wx.BoxSizer( wx.VERTICAL )
            self.panel2.SetSizer(self.bSizer)
            self.mainsizer = wx.BoxSizer( wx.HORIZONTAL )
            self.mainsizer.Add(self.panel1,1,wx.EXPAND)
            self.SetSizer(self.mainsizer)
            self.timer.Start(2000)
    
        def basicgui(self,event):
            self.GetJpgList("./images")
            allimage = len(self.dict)
            items = self.bSizer.GetChildren()
            #if the image count is the same as before nothing has changed - bail
            if len(items) == allimage:
                return
            #remove existing images from the sizer
            for i in items:
                i.GetWindow().Destroy()
            # add images to the sizer
            for item, bitmap in self.dict.items():
                control = wx.StaticBitmap(self.panel2, -1, bitmap)
                self.bSizer.Add( control, 0, wx.CENTER|wx.ALL, 5 )
            #reset scrolling
            self.panel2.SetupScrolling(scrollToTop=False)
            self.Layout()
            self.Show()
    
        def GetJpgList(self, dir):
            #use glob rather than os.listdir
            jpgs = glob.glob(dir+"/*.jpg")
    
            #Build a dictionary of the images
            #this way we only have to create them once
            for i in jpgs:
                #if image already in dict bail
                if i in self.dict:
                    continue
                print("adding", i)
                bitmap = wx.Bitmap(i)
                image = bitmap.ConvertToImage()
                image = image.Scale(300, 200, wx.IMAGE_QUALITY_HIGH)
                bitmap = wx.Bitmap(image)
                self.dict[i] = bitmap
    
            #make a list of any deleted images
            del_list = []
            for i in self.dict:
                if i not in jpgs:
                    del_list.append(i)
            #remove deleted images from the dictionary
            for i in del_list:
                self.dict.pop(i)
                print("deleting",i)
    
            return
    
    def main():
        app = wx.App()
        windowclass(None)
        app.MainLoop()
    
    main()