Search code examples
pythonuser-interfacematplotlibwxpythonpython-imaging-library

Using a variable in wx.Frame in wx.Panel


I have created an application that is split into two parts; the left is the frame which has sliders that I want the values to be used to modify the right panel.

Here is the code:

import wx
import numpy 
import matplotlib
import random
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import Image
import ImageEnhance

#from wx.lib.pubsub import pub 

class Main(wx.Frame):

    def __init__(self, title):
        wx.Frame.__init__(self, None, title=title, size=(1200,800))
        self.sp = wx.SplitterWindow(self)
        self.varPanel = wx.Panel(self.sp, style=wx.RAISED_BORDER)
        self.imgPanel = ImgPanel(self.sp)
        self.sp.SplitVertically(self.varPanel,self.imgPanel,300)
        self.conSlider = wx.Slider(self.varPanel, -1, 0, 1, 10, pos=(10,10), size=(250,-1), style=wx.SL_AUTOTICKS | wx.SL_LABELS)
        self.Bind(wx.EVT_SLIDER, self.sliderUpdate)
        self.Show(True)

    def sliderUpdate(self, event):
        self.conValue = self.conSlider.GetValue()
        #print "Contrast: ", self.conValue
        return self.conValue
        #pub.sendMessage("panelListener", message=self.conValue)

class ImgPanel(wx.Panel):

    def __init__(self, parent):     
        wx.Panel.__init__(self, parent,-1,size=(50,50))

        #pub.subscribe(self.myListener, "panelListener")

        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(self.sizer)
        self.fig = plt.figure()
        self.axes = self.fig.add_subplot(111)
        self.canvas = FigureCanvas(self, -1, self.fig)
        self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)

        self.drawImg()

    '''def myListener(self, message, arg2=None):
        """
        Listener function
        """
        return message'''

    def contrast(self, img, value):
        enhancer = ImageEnhance.Contrast(img)
        conImg = enhancer.enhance(value)
        return conImg

    def drawImg(self):

        img = Image.open("d50.tif").convert("L")

        #cIm = self.contrast(img, random.uniform(0, 3))
        #cIm = self.contrast(img, message)
        cIm = self.contrast(img, self.conValue) # how to get slider value?? 

        arr = numpy.array(cIm) 
        im  = plt.imshow(arr, cmap=plt.cm.gray)

if __name__ == '__main__':
    app = wx.App()
    frame = Main("Title")
    app.MainLoop()

I want the value of my slider in the frame to be passed down to the drawImg() method in the panel. I was under the impression this was possible because the frame is parent to the panel. However, when run I get an attribute not found error for conValue.

I tried using messages as described here http://www.blog.pythonlibrary.org/2013/09/05/wxpython-2-9-and-the-newer-pubsub-api-a-simple-tutorial/ but without any luck (my code trying this has been commented out)

Please could someone help explain what I have done wrong and how I can use the slider variable in my panel.

-----Edit-----

New code based on Sundars help:

import wx
import numpy 
import matplotlib
import random
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import Image
import ImageEnhance

#from wx.lib.pubsub import pub 

class Main(wx.Frame):

    def __init__(self, title):
        wx.Frame.__init__(self, None, title=title, size=(1200,800))

        self.conValue=''
        self.sp = wx.SplitterWindow(self)
        self.varPanel = wx.Panel(self.sp, style=wx.RAISED_BORDER)
        self.imgPanel = ImgPanel(self, self.sp)
        self.sp.SplitVertically(self.varPanel,self.imgPanel,300)
        self.conSlider = wx.Slider(self.varPanel, -1, 0, 1, 10, pos=(10,10), size=(250,-1), style=wx.SL_AUTOTICKS | wx.SL_LABELS)
        self.Bind(wx.EVT_SLIDER, self.sliderUpdate)
        self.Show(True)
        self.conValue = ""

    def sliderUpdate(self, event):
        self.conValue = self.conSlider.GetValue()
        #print "Contrast: ", self.conValue
        return self.conValue
        #pub.sendMessage("panelListener", message=self.conValue)

class ImgPanel(wx.Panel):

    def __init__(self, frameclass, parent):     
        wx.Panel.__init__(self, parent,-1,size=(50,50))
        self.frameclass=frameclass
        #pub.subscribe(self.myListener, "panelListener")
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(self.sizer)
        self.fig = plt.figure()
        self.axes = self.fig.add_subplot(111)
        self.canvas = FigureCanvas(self, -1, self.fig)
        self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)

        self.drawImg()

    '''def myListener(self, message, arg2=None):
        """
        Listener function
        """
        return message'''

    def contrast(self, img, value):
        '''
        Method to alter the contrast of an image. 
        A factor of 0.0 gives a solid grey image. A factor of 1.0 gives the original image.
        Returns the altered image.
        '''
        enhancer = ImageEnhance.Contrast(img)
        conImg = enhancer.enhance(value)
        return conImg

    def drawImg(self):

        img = Image.open("d50.tif").convert("L")

        #cIm = self.contrast(img, random.uniform(0, 3)) # contrast change 
        #cIm = self.contrast(img, message)
        cIm = self.contrast(img, self.frameclass.conValue)

        arr = numpy.array(cIm) 
        im  = plt.imshow(arr, cmap=plt.cm.gray)

if __name__ == '__main__':
    app = wx.App()
    frame = Main("Title")
    app.MainLoop()

I am now receiving this error:

Traceback (most recent call last):
  File "C:\Users\Nathan\Documents\Visual Studio 2013\Projects\VSEM\VSEM\module2.
py", line 78, in <module>
    frame = Main("Title")
  File "C:\Users\Nathan\Documents\Visual Studio 2013\Projects\VSEM\VSEM\module2.
py", line 21, in __init__
    self.imgPanel = ImgPanel(self, self.sp)
  File "C:\Users\Nathan\Documents\Visual Studio 2013\Projects\VSEM\VSEM\module2.
py", line 47, in __init__
    self.drawImg()
  File "C:\Users\Nathan\Documents\Visual Studio 2013\Projects\VSEM\VSEM\module2.
py", line 71, in drawImg
    cIm = self.contrast(img, self.frameclass.conValue)
  File "C:\Users\Nathan\Documents\Visual Studio 2013\Projects\VSEM\VSEM\module2.
py", line 62, in contrast
    conImg = enhancer.enhance(value)
  File "C:\Anaconda\lib\site-packages\PIL\ImageEnhance.py", line 36, in enhance
    return Image.blend(self.degenerate, self.image, factor)
  File "C:\Anaconda\lib\site-packages\PIL\Image.py", line 2008, in blend
    return im1._new(core.blend(im1.im, im2.im, alpha))
TypeError: a float is required
Press any key to continue . . .

Solution

  • first thing :

    in Frame class inside init create the variable

    self.conValue=''
    

    next,while calling imagepanel pass the Frame class also

    self.imgPanel = ImgPanel(self,self.sp)
    

    next inside init of image class

    class ImgPanel(wx.Panel):
    
        def __init__(self,frameclass, parent): 
    
           self.frameclass=frameclass
    

    now,you can call it as

    cIm = self.contrast(img, self.frameclass.conValue)