1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837
|
#----------------------------------------------------------------------
# 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()
|