How to create a customized toggle button bitmap (Phoenix)
Keywords : ToggleButtonBitmap, ToggleButton, Custom.
Contents
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
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
Additional Information
Link :
- - - - -
https://wiki.wxpython.org/TitleIndex
https://discuss.wxpython.org/t/an-on-off-button-alternative-to-checkbox/36304
Thanks to
J. Healey (aka RolfofSaxony), 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....