How to create a customized toggle button bitmap (Phoenix)

Keywords : ToggleButtonBitmap, ToggleButton, Custom.


Demonstrating :

Tested py3.8.10, wx4.x and Linux.

Tested py3.10.5, wx4.2.1 and Win11.

Are you ready to use some samples ? ;)

Test, modify, correct, complete, improve and share your discoveries ! (!)


First example

Latest version here : https://discuss.wxpython.org/t/an-on-off-button-alternative-to-checkbox/36304

img_sample_one.png

   1 '''
   2     ToggleButtonBitmap.py
   3 
   4     A custom class On/Off clickable image, where you supply an Off image and an On image
   5     The images are scaled according to the size parameter you supply
   6 
   7     Events: EVT_TBB_ON_OFF          Generic event on binary change
   8 
   9             EVT_TBB_ON              The control changed to On
  10 
  11             EVT_TBB_OFF             The control changed to Off
  12 
  13     Event Notes:
  14         All events return GetValue() i.e.
  15 
  16             def OnOff(self,event):
  17                 current_value = event.GetValue()
  18 
  19     Functions:
  20         GetValue()              Returns numeric value in the control On (True) = 1 Off (False) = 0
  21 
  22         SetValue(int)           Set numeric value in the control
  23 
  24         Enable(Bool)            Enable/Disable the control
  25                                 On Disable the control value is frozen
  26 
  27         IsEnabled()             Is the control Enabled - Returns True/False
  28 
  29         SetBitmapOn(image)      Set the On image
  30 
  31         SetBitmapOff(image)     Set the Off image
  32 
  33         SetToolTip(str)         Set tooltip for the control
  34 
  35     Default Values:
  36         initial -       0 (False) Off
  37 
  38 Author:     J Healey
  39 Created:    31/01/2021
  40 Copyright:  J Healey - 2021-2023
  41 License:    GPL 3 or any later version
  42 Version:    2.0.0
  43 Email:      <rolfofsaxony@gmx.com>
  44 Written & tested: Linux, Python 3.8.10
  45 
  46 Change log:
  47 version 2.0.0
  48     Adds Tooltips
  49     Adds OnDisabled and OffDisabled bitmaps
  50     Removes wx.EmptyBitmap as deprecated
  51     Uses wx.Bitmap.ConvertToDisabled() to generate disabled bitmaps
  52     Adds Disable function default True
  53 
  54 Usage example:
  55 
  56 import wx
  57 import ToggleButtonBitmap as tbb
  58 class Frame(wx.Frame):
  59     def __init__(self, parent):
  60         wx.Frame.__init__(self, parent, -1, "On Off button Demo")
  61         panel = wx.Panel(self)
  62         panel.SetBackgroundColour("#f0ffff")
  63         self.onoff = tbb.ToggleButtonBitmap(panel, -1, bitmapon="G1.png", bitmapoff="G2.png", size=(200,200), initial=0)
  64         self.Show()
  65 
  66 app = wx.App()
  67 frame = Frame(None)
  68 app.MainLoop()
  69 '''
  70 
  71 import wx
  72 
  73 #Events OnOff, On and Off
  74 tbbEVT_ON_OFF = wx.NewEventType()
  75 EVT_ON_OFF = wx.PyEventBinder(tbbEVT_ON_OFF, 1)
  76 tbbEVT_ON = wx.NewEventType()
  77 EVT_ON = wx.PyEventBinder(tbbEVT_ON, 1)
  78 tbbEVT_OFF = wx.NewEventType()
  79 EVT_OFF = wx.PyEventBinder(tbbEVT_OFF, 1)
  80 
  81 class OnOffEvent(wx.PyCommandEvent):
  82     """ Event sent from the :class:`OnOff` when the control changes. """
  83 
  84     def __init__(self, eventType, eventId=1, value=0, size=(0,0)):
  85         """
  86         Default class constructor.
  87 
  88         :param `eventType`: the event type;
  89         :param `eventId`: the event identifier.
  90         """
  91 
  92         wx.PyCommandEvent.__init__(self, eventType, eventId)
  93         self._eventType = eventType
  94         self.value = value
  95         self.size = size
  96 
  97     def GetValue(self):
  98         """
  99         Retrieve the value of the control at the time
 100         this event was generated."""
 101         return self.value
 102 
 103     def GetSize(self):
 104         """
 105         Retrieve the value of the control at the time
 106         this event was generated."""
 107         return self.size
 108 
 109 class ToggleButtonBitmap(wx.Control):
 110 
 111     def __init__(self, parent, id=wx.ID_ANY, bitmapon=wx.NullBitmap, bitmapoff=wx.NullBitmap, pos=wx.DefaultPosition, size=wx.DefaultSize, initial=0, style=wx.BORDER_NONE, name="OnOffButton"):
 112         """
 113         Default class constructor.
 114 
 115         @param parent:  Parent window. Must not be None.
 116         @param id:      identifier. A value of -1 indicates a default value.
 117         @param pos:     Position. If the position (-1, -1) is specified
 118                         then a default position is chosen.
 119         @param size:    If the default size (-1, -1) is specified then the image size is chosen.
 120         @param initial: Initial value 0 False or 1 True.
 121         @param style:   border style.
 122         @param name:    Widget name.
 123         """
 124 
 125         wx.Control.__init__(self, parent, id, pos=pos, size=size, style=style, name=name)
 126 
 127         self.parent = parent
 128         self._initial = initial
 129         self._frozen_value = initial
 130         self._pos = pos
 131         self._size = wx.Size(size)
 132         self._name = name
 133         self._id = id
 134         self.SetSize(self._size)
 135         self.SetBackgroundColour(parent.GetBackgroundColour())
 136         self.SetBackgroundStyle(wx.BG_STYLE_PAINT)
 137         if not bitmapon:
 138             bitmapon=wx.Bitmap(20,20)
 139         if not bitmapoff:
 140             bitmapoff=wx.Bitmap(20,20)
 141         self._bitmaps = {
 142             "On": self.SetImageSize(bitmapon),
 143             "Off": self.SetImageSize(bitmapoff),
 144             }
 145         self._bitmaps["OnDisabled"] = self.DisableImage(self._bitmaps["On"])
 146         self._bitmaps["OffDisabled"] = self.DisableImage(self._bitmaps["Off"])
 147         if self._initial > 1:
 148             self._initial = 1
 149         if self._initial < 0:
 150             self._initial = 0
 151 
 152         self._value = initial
 153 
 154         self._enabled = True
 155         self.InitUI()
 156 
 157     def InitUI(self):
 158         self.img = wx.StaticBitmap(self, -1, bitmap=wx.Bitmap(self.GetBitmap()))
 159         self.Bind(wx.EVT_SIZE, self.OnSize)
 160         self.img.Bind(wx.EVT_LEFT_DOWN, self.OnClick)
 161         self.Show()
 162 
 163     def OnSize(self, event):
 164         """
 165         Handles the ``wx.EVT_SIZE`` event for :class:`OnOffButton`.
 166 
 167         :param `event`: A `wx.SizeEvent` to be processed.
 168         :type `event`: `wx.SizeEvent`
 169         """
 170         self._size = self.DoGetBestSize()
 171         self.Refresh()
 172 
 173     def OnClick(self, e):
 174         if not self._enabled:
 175             return
 176         self._value = not self._value
 177         self.img.SetBitmap(self.GetBitmap())
 178         tp = self.GetToolTip()
 179         if self._value:
 180             tt = tp + " [On] "
 181         else:
 182             tt = tp + " [Off] "
 183         self.img.SetToolTip(tt)
 184 
 185         event = OnOffEvent(tbbEVT_ON_OFF, self.GetId(), self._value, self.img.GetSize())
 186         event.SetEventObject(self)
 187         self.GetEventHandler().ProcessEvent(event)
 188         if not self._value:
 189             #event Off
 190             event = OnOffEvent(tbbEVT_OFF, self.GetId(), self._value, self.img.GetSize())
 191             event.SetEventObject(self)
 192             self.GetEventHandler().ProcessEvent(event)
 193         else:
 194             #event On
 195             event = OnOffEvent(tbbEVT_ON, self.GetId(), self._value, self.img.GetSize())
 196             event.SetEventObject(self)
 197             self.GetEventHandler().ProcessEvent(event)
 198         self.Refresh()
 199 
 200     def GetValue(self):
 201         return self._value
 202 
 203     def SetValue(self, value):
 204         self._value = value
 205         self.Refresh()
 206 
 207     def Disable(self, value=True):
 208         self.Enable(not value)
 209 
 210     def Enable(self, value=True):
 211         self._enabled = value
 212         if value and self.IsEnabled(): # If value = current state do nothing
 213             return
 214         if not value and not self.IsEnabled():
 215             return
 216         wx.Control.Enable(self, value)
 217         bmp = self.GetBitmap()
 218         self.img.SetBitmap(bmp)
 219         tp = self.GetToolTip()
 220         if value:
 221             if self._value:
 222                 tt = tp + " [On] "
 223             else:
 224                 tt = tp + " [Off] "
 225         else:
 226             tt = tp + " [Disabled] "
 227         self.img.SetToolTip(tt)
 228         self.Refresh()
 229 
 230     def DisableImage(self, bmp):
 231         bmp = bmp.ConvertToDisabled()
 232         return bmp
 233 
 234     def SetToolTip(self, tip):
 235         wx.Control.SetToolTip(self, tip)
 236         self.Refresh()
 237 
 238     def GetToolTip(self):
 239         tp = wx.Control.GetToolTip(self)
 240         if not tp:
 241             tp = ''
 242         else:
 243             tp = tp.GetTip()
 244         return tp
 245 
 246     def IsEnabled(self):
 247         return wx.Control.IsEnabled(self)
 248 
 249     def DoGetBestSize(self):
 250         bitmap = self.GetBitmap()
 251         # Retrieve the bitmap dimensions.
 252         bitmapWidth, bitmapHeight = bitmap.GetWidth(), bitmap.GetHeight()
 253         best = wx.Size(bitmapWidth, bitmapHeight)
 254         self.SetSize(best)
 255         self.CacheBestSize(best)
 256         return best
 257 
 258     def SetForegroundColour(self, colour):
 259         """
 260         Overridden base class virtual.
 261 
 262         :param `colour`: Set the foreground colour of the checkboxs label.
 263         :type `colour`: `wx.Colour`
 264         """
 265         wx.Control.SetForegroundColour(self, colour)
 266         self.InitializeColours()
 267         self.Refresh()
 268 
 269     def SetBackgroundColour(self, colour):
 270         """
 271         Overridden base class virtual.
 272 
 273         :param `colour`: Set the background colour of the checkbox.
 274         :type `colour`: `wx.Colour`
 275         """
 276         wx.Control.SetBackgroundColour(self, colour)
 277         self.Refresh()
 278 
 279     def SetImageSize(self, bmp):
 280         bmp = wx.Bitmap(bmp)
 281         imgsize = bmp.GetSize()
 282         imgh = imgsize[1]
 283         imgw = imgsize[0]
 284         w = self._size[0]
 285         h = self._size[1]
 286         if w <= 0:
 287             w = imgw
 288         if h <= 0:
 289             h = imgh
 290         img = bmp.ConvertToImage()
 291         img = img.Scale(w,h,quality=wx.IMAGE_QUALITY_HIGH)
 292         bmp = img.ConvertToBitmap()
 293         return bmp
 294 
 295     def GetBitmap(self):
 296         """
 297         Returns the appropriate bitmap depending on state
 298         (On/Off/Disabled).
 299         """
 300         if not self.IsEnabled():
 301             if not self._value:
 302                 return self._bitmaps["OffDisabled"]
 303             else:
 304                 return self._bitmaps["OnDisabled"]
 305         if not self._value:
 306             return self._bitmaps["Off"]
 307         else:
 308             return self._bitmaps["On"]
 309 
 310     def SetBitmapOn(self, bitmap):
 311         self._bitmaps["On"] = self.SetImageSize(bitmap)
 312         self._bitmaps["OnDisabled"] = self.DisableImage(self._bitmaps["On"])
 313         self.img.SetBitmap(self.GetBitmap())
 314         self.Refresh()
 315 
 316     def SetBitmapOff(self, bitmap):
 317         self._bitmaps["Off"] = self.SetImageSize(bitmap)
 318         self._bitmaps["OffDisabled"] = self.DisableImage(self._bitmaps["Off"])
 319         self.img.SetBitmap(self.GetBitmap())
 320         self.Refresh()
 321 
 322 if __name__ == '__main__':
 323 
 324     class MyFrame(wx.Frame):
 325 
 326         def __init__(self, parent):
 327 
 328             wx.Frame.__init__(self, parent, -1, "Toggle Button Bitmap Demo", size=(-1, 680))
 329 
 330             panel = wx.Panel(self, -1, size=(400, 500))
 331             panel.SetBackgroundColour('#f0ffff') # Azure
 332             sizer = wx.BoxSizer(wx.VERTICAL)
 333             self.onoff = ToggleButtonBitmap(panel, -1, bitmapon="G1.png", bitmapoff="G2.png", size=(200,200), initial=0)
 334             self.onoff1 = ToggleButtonBitmap(panel, -1, bitmapon="G1.png", bitmapoff="G2.png", size=(40,40), initial=1)
 335             self.txt = wx.TextCtrl(panel, -1, "Off", size=(50,30))
 336             self.onoff2 = ToggleButtonBitmap(panel, -1, bitmapon="G3.png", bitmapoff="G4.png", size=(40,20), initial=1)
 337             self.onoff3 = ToggleButtonBitmap(panel, -1, bitmapon="G3.png", bitmapoff="G4.png", initial=0)
 338             self.Bind(EVT_ON_OFF, self.OnOff, id=self.onoff.GetId())
 339             self.Bind(EVT_ON, self.SwOn)
 340             self.Bind(EVT_OFF, self.SwOff)
 341             sizer.Add(self.onoff, 0, wx.ALL, 20)
 342             sizer.Add(self.txt, 0, wx.LEFT, 90)
 343             sizer.Add(self.onoff1, 0, wx.ALL, 20)
 344             sizer.Add(self.onoff2, 0, wx.ALL, 20)
 345             sizer.Add(self.onoff3, 0, wx.ALL, 20)
 346             panel.SetSizer(sizer)
 347             self.onoff2.SetToolTip("Button 2")
 348             self.onoff2.Enable(False)
 349             self.timer = wx.Timer(self)
 350             self.Bind(wx.EVT_TIMER, self.Toggle)
 351             self.timer.Start(5000)
 352 
 353 
 354         def Toggle(self, event):
 355             self.onoff2.Enable(not self.onoff2.IsEnabled())
 356 
 357         def OnOff(self, event):
 358             print("Event on/off click")
 359             if event.GetValue():
 360                 self.txt.SetValue("On")
 361             else:
 362                 self.txt.SetValue("Off")
 363             event.Skip()
 364 
 365         def SwOn(self, event):
 366             obj = event.GetEventObject()
 367             print(obj.Name + "Event On")
 368 
 369         def SwOff(self, event):
 370             obj = event.GetEventObject()
 371             print(obj.Name + "Event Off")
 372 
 373     app = wx.App()
 374     frame = MyFrame(None)
 375     app.SetTopWindow(frame)
 376     frame.Show()
 377     app.MainLoop()


Download source

source.zip


Additional Information

Link :

- - - - -

https://wiki.wxpython.org/TitleIndex

https://docs.wxpython.org/

https://discuss.wxpython.org/t/an-on-off-button-alternative-to-checkbox/36304


Thanks to

J. Healey (ToggleButtonBitmap.py coding), the wxPython community...


About this page

Date(d/m/y) Person (bot) Comments :

11/01/23 - Ecco (Created page for wxPython Phoenix).


Comments

- blah, blah, blah....

How to create a customized toggle button bitmap (Phoenix) (last edited 2023-11-28 09:29:48 by Ecco)

NOTE: To edit pages in this wiki you must be a member of the TrustedEditorsGroup.