Files
Phoenix/wx/lib/checkbox.py
2021-08-07 18:55:49 +02:00

838 lines
30 KiB
Python

#----------------------------------------------------------------------
# Name: wx.lib.checkbox
# Purpose: Various kinds of generic checkbox stuff, (not native controls
# but self-drawn.)
#
# Author: wxPython Team and wxPyWiki Contributors
#
# Created: 22-June-2020
# Copyright: (c) 2020 by Total Control Software
# Licence: wxWindows license
# Tags: phoenix-port, py3-port, documented
#----------------------------------------------------------------------
"""
This module implements various forms of generic checkboxes, meaning that
they are not built on native controls but are self-drawn.
Description
===========
This module implements various forms of generic checkboxes, meaning that
they are not built on native controls but are self-drawn.
They should act like normal checkboxes but you are able to better control how they look, etc...
Usage
=====
Sample usage::
app = wx.App(redirect=False)
class MyFrame(wx.Frame, DefineNativeCheckBoxBitmapsMixin):
def __init__(self, parent, id=wx.ID_ANY, title=wx.EmptyString,
pos=wx.DefaultPosition, size=wx.DefaultSize,
style=wx.DEFAULT_FRAME_STYLE, name='frame'):
wx.Frame.__init__(self, parent, id, title, pos, size, style, name)
## self.DefineNativeCheckBoxBitmaps()
## self.checkbox_bitmaps = self.GetNativeCheckBoxBitmaps()
cb1 = GenCheckBox(self, label="PurePython Checkbox1", pos=(10, 10))
cb2 = GenCheckBox(self, label="PurePython Checkbox2", pos=(10, 50))
cb1.Bind(wx.EVT_CHECKBOX, self.OnCheckBox)
cb2.Bind(wx.EVT_CHECKBOX, self.OnCheckBox)
cb2.SetForegroundColour(wx.GREEN)
cb2.SetBackgroundColour(wx.BLACK)
sizer = wx.BoxSizer()
sizer.Add(cb1, 0, wx.ALL, 5)
sizer.Add(cb2, 0, wx.ALL, 5)
self.SetSizer(sizer)
def OnCheckBox(self, event):
evtObj = event.GetEventObject()
print(evtObj.GetLabel(), evtObj.IsChecked())
frame = MyFrame(None, wx.ID_ANY, "Test Pure-Py Checkbox")
frame.Show()
app.MainLoop()
"""
# Imports.---------------------------------------------------------------------
# -wxPython Imports.
import wx
class GenCheckBox(wx.Control):
"""
A generic class that replicates some of the functionalities of :class:`wx.Checkbox`,
while being completely owner-drawn with a nice check bitmaps.
"""
def __init__(self, parent, id=wx.ID_ANY, label="", pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.NO_BORDER, validator=wx.DefaultValidator,
name="GenCheckBox"):
"""
Default class constructor.
:param `parent`: Pointer to a parent window. Must not be ``None``.
:type `parent`: `wx.Window`
:param `id`: Window identifier. ``wx.ID_ANY`` indicates a default value.
:type `id`: int
:param `label`: Text to be displayed next to the checkbox.
:type `label`: str
:param `pos`: Window position. The value ``wx.DefaultPosition`` indicates
a default position, chosen by either the windowing system or wxWidgets, depending on platform.
:type `pos`: `wx.Point`
:param `size`: Window size. The value ``wx.DefaultSize`` indicates a default size,
chosen by either the windowing system or wxWidgets, depending on platform.
:type `size`: `wx.Size`
:param `style`: Window style. Not used in this widget, GenCheckBox has only 2 state.
:type `style`: long
:param `validator`: Window validator.
:type `validator`: `wx.Validator`
:param `name`: Window name.
:type `name`: str
"""
wx.Control.__init__(self, parent, id, pos, size, style, validator, name)
self.SYS_DEFAULT_GUI_FONT = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
# Initialize our cool bitmaps.
self.InitializeBitmaps()
# Initialize the focus pen colour/dashes, for faster drawing later.
self.InitializeColours()
# By default, we start unchecked.
self._checked = False
# Set the spacing between the check bitmap and the label to 3 by default.
# This can be changed using SetSpacing later.
self._spacing = 3
self._hasFocus = False
# Ok, set the wx.PyControl label, its initial size (formerly known an
# SetBestFittingSize), and inherit the attributes from the standard
# wx.CheckBox .
self.SetLabel(label)
self.SetInitialSize(size)
self.InheritAttributes()
# Bind the events related to our control: first of all, we use a
# combination of wx.BufferedPaintDC and an empty handler for
# wx.EVT_ERASE_BACKGROUND (see later) to reduce flicker.
self.Bind(wx.EVT_PAINT, self.OnPaint)
# Since the paint event draws the whole widget, we will use
# SetBackgroundStyle(wx.BG_STYLE_PAINT) and then
# implementing an erase-background handler is not necessary.
self.SetBackgroundStyle(wx.BG_STYLE_PAINT)
# Add a size handler to refresh so the paint won't smear when resizing.
self.Bind(wx.EVT_SIZE, self.OnSize)
# Then we want to monitor user clicks, so that we can switch our
# state between checked and unchecked.
self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseClick)
if wx.Platform == '__WXMSW__':
# MSW Sometimes does strange things...
self.Bind(wx.EVT_LEFT_DCLICK, self.OnMouseClick)
# We want also to react to keyboard keys, namely the space bar that can
# toggle our checked state. Whether key-up or key-down is used is based
# on platform.
if 'wxMSW' in wx.PlatformInfo:
self.Bind(wx.EVT_KEY_UP, self.OnKeyEvent)
else:
self.Bind(wx.EVT_KEY_DOWN, self.OnKeyEvent)
# Then, we react to focus event, because we want to draw a small
# dotted rectangle around the text if we have focus.
# This might be improved!!!
self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
def InitializeBitmaps(self):
""" Initializes the check bitmaps. """
# We keep 4 bitmaps for GenCheckBox, depending on the
# checking state (Checked/UnChecked) and the control
# state (Enabled/Disabled).
self._bitmaps = {
"CheckedEnable": _GetCheckedBitmap(self),
"UnCheckedEnable": _GetNotCheckedBitmap(self),
"CheckedDisable": _GetCheckedImage(self).ConvertToDisabled().ConvertToBitmap(),
"UnCheckedDisable": _GetNotCheckedImage(self).ConvertToDisabled().ConvertToBitmap()}
def InitializeColours(self):
""" Initializes the focus indicator pen. """
textClr = self.GetForegroundColour()
self._focusIndPen = wx.Pen(textClr, 1, wx.USER_DASH)
self._focusIndPen.SetDashes([1, 1])
self._focusIndPen.SetCap(wx.CAP_BUTT)
self.SYS_COLOUR_GRAYTEXT = wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)
def GetBitmap(self):
"""
Returns the appropriated bitmap depending on the checking state
(Checked/UnChecked) and the control state (Enabled/Disabled).
"""
if self.IsEnabled():
# So we are Enabled.
if self.IsChecked():
# We are Checked.
return self._bitmaps["CheckedEnable"]
else:
# We are UnChecked.
return self._bitmaps["UnCheckedEnable"]
else:
# Poor GenCheckBox, Disabled and ignored!
if self.IsChecked():
return self._bitmaps["CheckedDisable"]
else:
return self._bitmaps["UnCheckedDisable"]
def SetLabel(self, label):
"""
Sets the :class:`GenCheckBox` text label and updates the control's
size to exactly fit the label plus the bitmap.
:param `label`: Text to be displayed next to the checkbox.
:type `label`: str
"""
wx.Control.SetLabel(self, label)
# The text label has changed, so we must recalculate our best size
# and refresh ourselves.
self.InvalidateBestSize()
self.Refresh()
def SetFont(self, font):
"""
Sets the :class:`GenCheckBox` text font and updates the control's
size to exactly fit the label plus the bitmap.
:param `font`: Font to be used to render the checkboxs label.
:type `font`: `wx.Font`
"""
wx.Control.SetFont(self, font)
# The font for text label has changed, so we must recalculate our best
# size and refresh ourselves.
self.InvalidateBestSize()
self.Refresh()
def DoGetBestSize(self):
"""
Overridden base class virtual. Determines the best size of the control
based on the label size, the bitmap size and the current font.
"""
# Retrieve our properties: the text label, the font and the check
# bitmap.
label = self.GetLabel()
font = self.GetFont()
bitmap = self.GetBitmap()
if not font:
# No font defined? So use the default GUI font provided by the system.
font = self.SYS_DEFAULT_GUI_FONT
# Set up a wx.ClientDC. When you don't have a dc available (almost
# always you don't have it if you are not inside a wx.EVT_PAINT event),
# use a wx.ClientDC (or a wx.MemoryDC) to measure text extents.
dc = wx.ClientDC(self)
dc.SetFont(font)
# Measure our label.
textWidth, textHeight = dc.GetTextExtent(label)
# Retrieve the check bitmap dimensions.
bitmapWidth, bitmapHeight = bitmap.GetWidth(), bitmap.GetHeight()
# Get the spacing between the check bitmap and the text.
spacing = self.GetSpacing()
# Ok, we're almost done: the total width of the control is simply
# the sum of the bitmap width, the spacing and the text width,
# while the height is the maximum value between the text width and
# the bitmap width.
totalWidth = bitmapWidth + spacing + textWidth
totalHeight = max(textHeight, bitmapHeight)
best = wx.Size(totalWidth, totalHeight)
# Cache the best size so it doesn't need to be calculated again,
# at least until some properties of the window change.
self.CacheBestSize(best)
return best
def AcceptsFocusFromKeyboard(self):
""" Overridden base class virtual. """
# We can accept focus from keyboard, obviously.
return True
def AcceptsFocus(self):
""" Overridden base class virtual. """
# If it seems that wx.CheckBox does not accept focus with mouse, It does.
# You just can't see the focus rectangle until there's
# another keypress or navigation event (at least on some platforms.)
return True # This will draw focus rectangle always on mouse click.
def HasFocus(self):
""" Returns whether or not we have the focus. """
# We just returns the _hasFocus property that has been set in the
# wx.EVT_SET_FOCUS and wx.EVT_KILL_FOCUS event handlers.
return self._hasFocus
def SetForegroundColour(self, colour):
"""
Overridden base class virtual.
:param `colour`: Set the foreground colour of the checkboxs label.
:type `colour`: `wx.Colour`
"""
wx.Control.SetForegroundColour(self, colour)
# We have to re-initialize the focus indicator per colour as it should
# always be the same as the foreground colour.
self.InitializeColours()
self.Refresh()
def SetBackgroundColour(self, colour):
"""
Overridden base class virtual.
:param `colour`: Set the background colour of the checkbox.
:type `colour`: `wx.Colour`
"""
wx.Control.SetBackgroundColour(self, colour)
# We have to refresh ourselves.
self.Refresh()
def Enable(self, enable=True):
"""
Enables/Disables :class:`GenCheckBox`.
:param `enable`: Set the enabled state of the checkbox.
:type `enable`: bool
"""
wx.Control.Enable(self, enable)
# We have to refresh ourselves, as our state changed.
self.Refresh()
def GetDefaultAttributes(self):
"""
Overridden base class virtual. By default we should use
the same font/colour attributes as the native wx.CheckBox.
"""
return wx.CheckBox.GetClassDefaultAttributes()
def ShouldInheritColours(self):
"""
Overridden base class virtual. If the parent has non-default
colours then we want this control to inherit them.
"""
return True
def SetSpacing(self, spacing):
"""
Sets a new spacing between the check bitmap and the text.
:param `spacing`: Set the amount of space between the checkboxs bitmap and text.
:type `spacing`: int
"""
self._spacing = spacing
# The spacing between the check bitmap and the text has changed,
# so we must recalculate our best size and refresh ourselves.
self.InvalidateBestSize()
self.Refresh()
def GetSpacing(self):
""" Returns the spacing between the check bitmap and the text. """
return self._spacing
def GetValue(self):
"""
Returns the state of :class:`GenCheckBox`, True if checked, False
otherwise.
"""
return self._checked
def IsChecked(self):
"""
This is just a maybe more readable synonym for GetValue: just as the
latter, it returns True if the :class:`GenCheckBox` is checked and False
otherwise.
"""
return self._checked
def SetValue(self, state):
"""
Sets the :class:`GenCheckBox` to the given state. This does not cause a
``wx.wxEVT_COMMAND_CHECKBOX_CLICKED`` event to get emitted.
:param `state`: Set the value of the checkbox. True or False.
:type `state`: bool
"""
self._checked = state
# Refresh ourselves: the bitmap has changed.
self.Refresh()
def OnKeyEvent(self, event):
"""
Handles the ``wx.EVT_KEY_UP`` or ``wx.EVT_KEY_UP`` event (depending on
platform) for :class:`GenCheckBox`.
:param `event`: A `wx.KeyEvent` to be processed.
:type `event`: `wx.KeyEvent`
"""
if event.GetKeyCode() == wx.WXK_SPACE:
# The spacebar has been pressed: toggle our state.
self.SendCheckBoxEvent()
else:
event.Skip()
def OnSetFocus(self, event):
"""
Handles the ``wx.EVT_SET_FOCUS`` event for :class:`GenCheckBox`.
:param `event`: A `wx.FocusEvent` to be processed.
:type `event`: `wx.FocusEvent`
"""
self._hasFocus = True
# We got focus, and we want a dotted rectangle to be painted
# around the checkbox label, so we refresh ourselves.
self.Refresh()
def OnKillFocus(self, event):
"""
Handles the ``wx.EVT_KILL_FOCUS`` event for :class:`GenCheckBox`.
:param `event`: A `wx.FocusEvent` to be processed.
:type `event`: `wx.FocusEvent`
"""
self._hasFocus = False
# We lost focus, and we want a dotted rectangle to be cleared
# around the checkbox label, so we refresh ourselves.
self.Refresh()
def OnSize(self, event):
"""
Handles the ``wx.EVT_SIZE`` event for :class:`GenCheckBox`.
:param `event`: A `wx.SizeEvent` to be processed.
:type `event`: `wx.SizeEvent`
"""
self.Refresh()
def OnPaint(self, event):
"""
Handles the ``wx.EVT_PAINT`` event for :class:`GenCheckBox`.
:param `event`: A `wx.PaintEvent` to be processed.
:type `event`: `wx.PaintEvent`
"""
# If you want to reduce flicker, a good starting point is to
# use wx.BufferedPaintDC .
# wx.AutoBufferedPaintDC would be marginally better.
dc = wx.AutoBufferedPaintDC(self)
# Is is advisable that you don't overcrowd the OnPaint event
# (or any other event) with a lot of code, so let's do the
# actual drawing in the Draw() method, passing the newly
# initialized wx.AutoBufferedPaintDC .
self.Draw(dc)
def Draw(self, dc):
"""
Actually performs the drawing operations, for the bitmap and
for the text, positioning them centered vertically.
:param `dc`: device context to use.
:type `dc`: `wx.DC`
"""
# Get the actual client size of ourselves.
width, height = self.GetClientSize()
if not width or not height:
# Nothing to do, we still don't have dimensions!
return
# Initialize the wx.BufferedPaintDC, assigning a background
# colour and a foreground colour (to draw the text).
backColour = self.GetBackgroundColour()
backBrush = wx.Brush(backColour, wx.SOLID)
dc.SetBackground(backBrush)
dc.Clear()
if self.IsEnabled():
dc.SetTextForeground(self.GetForegroundColour())
else:
dc.SetTextForeground(self.SYS_COLOUR_GRAYTEXT)
dc.SetFont(self.GetFont())
# Get the text label for the checkbox, the associated check bitmap
# and the spacing between the check bitmap and the text.
label = self.GetLabel()
bitmap = self.GetBitmap()
spacing = self.GetSpacing()
# Measure the text extent and get the check bitmap dimensions.
textWidth, textHeight = dc.GetTextExtent(label)
bitmapWidth, bitmapHeight = bitmap.GetWidth(), bitmap.GetHeight()
# Position the bitmap centered vertically.
bitmapXpos = 0
bitmapYpos = (height - bitmapHeight) // 2
# Position the text centered vertically.
textXpos = bitmapWidth + spacing
textYpos = (height - textHeight) // 2
# Draw the bitmap on the DC.
try:
dc.DrawBitmap(bitmap, bitmapXpos, bitmapYpos, True)
except Exception as exc: # bitmap might be image and need converted. Ex: if disabled.
dc.DrawBitmap(bitmap.ConvertToBitmap(), bitmapXpos, bitmapYpos, True)
# Draw the text
dc.DrawText(label, textXpos, textYpos)
# Let's see if we have keyboard focus and, if this is the case,
# we draw a dotted rectangle around the text (Windows behavior,
# I don't know on other platforms...).
if self.HasFocus():
# Yes, we are focused! So, now, use a transparent brush with
# a dotted black pen to draw a rectangle around the text.
dc.SetBrush(wx.TRANSPARENT_BRUSH)
dc.SetPen(self._focusIndPen)
dc.DrawRectangle(textXpos, textYpos, textWidth, textHeight)
def OnMouseClick(self, event):
"""
Handles the ``wx.EVT_LEFT_DOWN`` event for :class:`GenCheckBox`.
:param `event`: A `wx.MouseEvent` to be processed.
:type `event`: `wx.MouseEvent`
"""
if not self.IsEnabled():
# Nothing to do, we are disabled.
return
self.SendCheckBoxEvent()
event.Skip()
def SendCheckBoxEvent(self):
""" Actually sends the wx.wxEVT_COMMAND_CHECKBOX_CLICKED event. """
# This part of the code may be reduced to a 3-liner code
# but it is kept for better understanding the event handling.
# If you can, however, avoid code duplication; in this case,
# I could have done:
#
# self._checked = not self.IsChecked()
# checkEvent = wx.CommandEvent(wx.wxEVT_COMMAND_CHECKBOX_CLICKED,
# self.GetId())
# checkEvent.SetInt(int(self._checked))
if self.IsChecked():
# We were checked, so we should become unchecked.
self._checked = False
# Fire a wx.CommandEvent: this generates a
# wx.wxEVT_COMMAND_CHECKBOX_CLICKED event that can be caught by the
# developer by doing something like:
# MyCheckBox.Bind(wx.EVT_CHECKBOX, self.OnCheckBox)
checkEvent = wx.CommandEvent(wx.wxEVT_COMMAND_CHECKBOX_CLICKED,
self.GetId())
# Set the integer event value to 0 (we are switching to unchecked state).
checkEvent.SetInt(0)
else:
# We were unchecked, so we should become checked.
self._checked = True
checkEvent = wx.CommandEvent(wx.wxEVT_COMMAND_CHECKBOX_CLICKED,
self.GetId())
# Set the integer event value to 1 (we are switching to checked state).
checkEvent.SetInt(1)
# Set the originating object for the event (ourselves).
checkEvent.SetEventObject(self)
# Watch for a possible listener of this event that will catch it and
# eventually process it.
self.GetEventHandler().ProcessEvent(checkEvent)
# Refresh ourselves: the bitmap has changed.
self.Refresh()
# -----------------------------------------------------------------------------
class DefineNativeCheckBoxBitmapsMixin():
"""
Inherit this mixin in your :class:`wx.Window` based subclass to easily
define the native CheckBox Bitmaps as attributes which can then be used
to customize a widgets appearance/functionality with.
Sample example usage::
class MyCheckListBoxSTC(wx.stc.StyledTextCtrl, DefineNativeCheckBoxBitmapsMixin):
'''Customized StyledTextCtrl Setup like a CheckListBox.'''
def __init__(self, parent, id=wx.ID_ANY,
pos=wx.DefaultPosition, size=wx.DefaultSize,
style=0, name='styledtextctrl'):
wx.stc.StyledTextCtrl.__init__(self, parent, id, pos, size, style, name)
# Define the checkbox bitmaps as attributes.
self.DefineNativeCheckBoxBitmaps()
# After the bitmaps have become attributes you can easily snag
# them all later on from inside a method with this inherited method.
## self.checkbox_bitmaps = self.GetNativeCheckBoxBitmaps()
# Setup a margin to hold bookmarks.
self.SetMarginType(1, wx.stc.STC_MARGIN_SYMBOL)
self.SetMarginSensitive(1, True)
self.SetMarginWidth(1, 16)
# Define the bookmark images.
self.MarkerDefineBitmap(0, self.native_checkbox_unchecked_bmp)
self.MarkerDefineBitmap(1, self.native_checkbox_checked_bmp)
# ... do something with the bitmaps when you click the margin event.
"""
def DefineNativeCheckBoxBitmaps(self):
"""
Define native checkbox bitmaps as attributes. Returns True if all bitmaps was defined Ok.
bitmaps defined::
self.native_checkbox_unchecked_bmp
self.native_checkbox_unchecked_disabled_bmp
self.native_checkbox_checked_bmp
self.native_checkbox_checked_disabled_bmp
self.native_checkbox_3state_bmp
self.native_checkbox_3state_disabled_bmp
self.native_checkbox_current_bmp
self.native_checkbox_pressed_bmp
:rtype: bool
"""
render = wx.RendererNative.Get()
cbX, cbY = render.GetCheckBoxSize(self)
bmp = wx.Bitmap(cbX, cbY)
dc = wx.MemoryDC(bmp)
DrawCheckBox = render.DrawCheckBox
DrawCheckBox(self, dc, (0, 0, cbX, cbY), wx.CONTROL_ISDEFAULT)
self.native_checkbox_unchecked_bmp = dc.GetAsBitmap((0, 0, cbX, cbY))
DrawCheckBox(self, dc, (0, 0, cbX, cbY), wx.CONTROL_ISDEFAULT | wx.CONTROL_DISABLED)
self.native_checkbox_unchecked_disabled_bmp = dc.GetAsBitmap((0, 0, cbX, cbY))
DrawCheckBox(self, dc, (0, 0, cbX, cbY), wx.CONTROL_CHECKED)
self.native_checkbox_checked_bmp = dc.GetAsBitmap((0, 0, cbX, cbY))
DrawCheckBox(self, dc, (0, 0, cbX, cbY), wx.CONTROL_CHECKED | wx.CONTROL_DISABLED)
self.native_checkbox_checked_disabled_bmp = dc.GetAsBitmap((0, 0, cbX, cbY))
DrawCheckBox(self, dc, (0, 0, cbX, cbY), wx.CONTROL_CHECKABLE)
self.native_checkbox_3state_bmp = dc.GetAsBitmap((0, 0, cbX, cbY))
DrawCheckBox(self, dc, (0, 0, cbX, cbY), wx.CONTROL_CHECKABLE | wx.CONTROL_DISABLED)
self.native_checkbox_3state_disabled_bmp = dc.GetAsBitmap((0, 0, cbX, cbY))
DrawCheckBox(self, dc, (0, 0, cbX, cbY), wx.CONTROL_CURRENT)
self.native_checkbox_current_bmp = dc.GetAsBitmap((0, 0, cbX, cbY))
DrawCheckBox(self, dc, (0, 0, cbX, cbY), wx.CONTROL_PRESSED)
self.native_checkbox_pressed_bmp = dc.GetAsBitmap((0, 0, cbX, cbY))
if (self.native_checkbox_unchecked_bmp.IsOk() and
self.native_checkbox_unchecked_disabled_bmp.IsOk() and
self.native_checkbox_checked_bmp.IsOk() and
self.native_checkbox_checked_disabled_bmp.IsOk() and
self.native_checkbox_3state_bmp.IsOk() and
self.native_checkbox_3state_disabled_bmp.IsOk() and
self.native_checkbox_current_bmp.IsOk() and
self.native_checkbox_pressed_bmp.IsOk()
):
return True
return False
def GetNativeCheckBoxBitmaps(self):
"""
Get a tuple of the defined checkbox bitmaps.
:rtype: tuple
"""
return (self.native_checkbox_unchecked_bmp,
self.native_checkbox_unchecked_disabled_bmp,
self.native_checkbox_checked_bmp,
self.native_checkbox_checked_disabled_bmp,
self.native_checkbox_3state_bmp,
self.native_checkbox_3state_disabled_bmp,
self.native_checkbox_current_bmp,
self.native_checkbox_pressed_bmp,
)
# -----------------------------------------------------------------------------
def _GetCheckedBitmap(self):
"""
Get a native checkbox(Checked) bitmap.
:rtype: `wx.Bitmap`
"""
render = wx.RendererNative.Get()
cbX, cbY = render.GetCheckBoxSize(self)
bmp = wx.Bitmap(cbX, cbY)
dc = wx.MemoryDC(bmp)
render.DrawCheckBox(self, dc, (0, 0, cbX, cbY), wx.CONTROL_CHECKED)
native_checkbox_checked_bmp = dc.GetAsBitmap((0, 0, cbX, cbY))
return native_checkbox_checked_bmp
def _GetCheckedImage(self):
"""
Get a native checkbox(Checked) image.
:rtype: `wx.Image`
"""
return _GetCheckedBitmap(self).ConvertToImage()
def _GetNotCheckedBitmap(self):
"""
Get a native checkbox(Unchecked) bitmap.
:rtype: `wx.Bitmap`
"""
render = wx.RendererNative.Get()
cbX, cbY = render.GetCheckBoxSize(self)
bmp = wx.Bitmap(cbX, cbY)
dc = wx.MemoryDC(bmp)
render.DrawCheckBox(self, dc, (0, 0, cbX, cbY), wx.CONTROL_ISDEFAULT)
native_checkbox_unchecked_bmp = dc.GetAsBitmap((0, 0, cbX, cbY))
return native_checkbox_unchecked_bmp
def _GetNotCheckedImage(self):
"""
Get a native checkbox(Unchecked) image.
:rtype: `wx.Image`
"""
return _GetNotCheckedBitmap(self).ConvertToImage()
# -----------------------------------------------------------------------------
def _GrayOut(anImage):
"""
Convert the given image (in place) to a grayed-out version,
appropriate for a 'disabled' appearance.
:param `anImage`: A `wx.Image` to gray out.
:type `anImage`: `wx.Image`
:rtype: `wx.Bitmap`
"""
factor = 0.7 # 0 < f < 1. Higher Is Grayer
if anImage.HasMask():
maskColor = (anImage.GetMaskRed(), anImage.GetMaskGreen(), anImage.GetMaskBlue())
else:
maskColor = None
data = map(ord, list(anImage.GetData()))
for i in range(0, len(data), 3):
pixel = (data[i], data[i + 1], data[i + 2])
pixel = _MakeGray(pixel, factor, maskColor)
for x in range(3):
data[i + x] = pixel[x]
anImage.SetData(''.join(map(chr, data)))
return anImage.ConvertToBitmap()
def _MakeGray(rgbTuple, factor, maskColor):
"""
Make a pixel grayed-out. If the pixel matches the maskcolor, it won't be
changed.
:type `rgbTuple`: red, green, blue 3-tuple
:type `factor`: float
:type `maskColor`: red, green, blue 3-tuple
"""
r, g, b = rgbTuple
if (r, g, b) != maskColor:
return map(lambda x: int((230 - x) * factor) + x, (r, g, b))
else:
return (r, g, b)
if __name__ == '__main__':
# Small sample program to test.
app = wx.App(redirect=False)
class MyFrame(wx.Frame, DefineNativeCheckBoxBitmapsMixin):
def __init__(self, parent, id=wx.ID_ANY, title=wx.EmptyString,
pos=wx.DefaultPosition, size=wx.DefaultSize,
style=wx.DEFAULT_FRAME_STYLE, name='frame'):
wx.Frame.__init__(self, parent, id, title, pos, size, style, name)
## self.DefineNativeCheckBoxBitmaps()
## self.checkbox_bitmaps = self.GetNativeCheckBoxBitmaps()
cb1 = GenCheckBox(self, label="PurePython Checkbox1", pos=(10, 10))
cb2 = GenCheckBox(self, label="PurePython Checkbox2", pos=(10, 50))
cb1.Bind(wx.EVT_CHECKBOX, self.OnCheckBox)
cb2.Bind(wx.EVT_CHECKBOX, self.OnCheckBox)
cb2.SetForegroundColour(wx.GREEN)
cb2.SetBackgroundColour(wx.BLACK)
sizer = wx.BoxSizer()
sizer.Add(cb1, 0, wx.ALL, 5)
sizer.Add(cb2, 0, wx.ALL, 5)
self.SetSizer(sizer)
def OnCheckBox(self, event):
evtObj = event.GetEventObject()
print(evtObj.GetLabel(), evtObj.IsChecked())
frame = MyFrame(None, wx.ID_ANY, "Test Pure-Py Checkbox")
frame.Show()
app.MainLoop()