Skip to content

Commit

Permalink
create a toggle switch widget
Browse files Browse the repository at this point in the history
  • Loading branch information
jborbely committed Aug 9, 2017
1 parent 383e55f commit 4216adc
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 9 deletions.
2 changes: 1 addition & 1 deletion docs/_api/msl.qt.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ Submodules

msl.qt.loop_until_abort
msl.qt.prompt

msl.qt.toggle_switch
7 changes: 7 additions & 0 deletions docs/_api/msl.qt.toggle_switch.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
msl\.qt\.toggle_switch module
=============================

.. automodule:: msl.qt.toggle_switch
:members:
:undoc-members:
:show-inheritance:
Binary file added docs/_static/toggle_switch.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 11 additions & 1 deletion docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ which has the following modules

msl.qt.prompt

the following Widgets

+----------------------------------+-------------------------------------------------------------------+
| :class:`msl.qt.ToggleSwitch | A toggle switch QWidget, |toggle_switch| |
| <msl.qt.toggle_switch>` | |
+----------------------------------+-------------------------------------------------------------------+

and the following classes

+----------------------------------+-------------------------------------------------------------------+
Expand All @@ -28,4 +35,7 @@ Package Structure

.. toctree::

_api/msl
_api/msl

.. |toggle_switch| image:: _static/toggle_switch.gif
:scale: 40 %
26 changes: 26 additions & 0 deletions msl/examples/qt/toggle_switch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"""
Example showing how to use the :obj:`ToggleSwitch <msl.qt.toggle_switch.ToggleSwitch>`.
"""
from PyQt5 import QtWidgets

from msl.qt import application, ToggleSwitch


def print_state(checked):
print('The switch is {}'.format('on' if checked else 'off'))


def main():
app = application()
window = QtWidgets.QWidget()
window.setWindowTitle('Toggle Switch Example')
hbox = QtWidgets.QHBoxLayout()
ts = ToggleSwitch(window)
ts.toggled.connect(print_state)
hbox.addWidget(ts)
window.setLayout(hbox)
window.show()
app.exec_()

if __name__ == '__main__':
main()
22 changes: 15 additions & 7 deletions msl/qt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,16 +70,16 @@ def get_icon(obj):
for the possible enum values. Example::
msl.qt.get_icon(PyQt5.QtWidgets.QStyle.SP_TitleBarMenuButton)
* :obj:`bytes`: A `Base64 <https://en.wikipedia.org/wiki/Base64>`_ representation
of an encoded image. See also :func:`image_to_base64`.
of an encoded image.
See also :func:`image_to_base64`.
* :obj:`str`: The path to an image file or an icon embedded in a Windows DLL/EXE file.
If `obj` is a path to an image file and if only the filename is specified then the
directories in :obj:`sys.path` and :obj:`os.environ['PATH'] <os.environ>` are used
to search for the image file. If `obj` refers to an icon in a Windows DLL/EXE file
then `obj` is the path to the DLL/EXE file and the icon index separated by the ``|``
character. An overview of some Windows DLL/EXE files which contain icons can be found
`here <http://www.digitalcitizen.life/where-find-most-windows-10s-native-icons>`_.
character.
The following examples illustrate the various ways to request an icon by passing
in a :obj:`str`-type argument::
Expand All @@ -100,7 +100,7 @@ def get_icon(obj):
# load icon 0 from the Windows explorer.exe file
msl.qt.get_icon('C:/Windows/explorer.exe|0')
# by default it is assumed that the icon is located in a file in one of two directories:
# by default it is assumed that the file is in one of two directories:
# a DLL file in C:/Windows/System32/ or an EXE file in C:/Windows/
# so the following is a simplified way to load an icon in a Windows DLL file
msl.qt.get_icon('shell32|23')
Expand All @@ -120,6 +120,13 @@ def get_icon(obj):
If `obj` is of type :obj:`str` and the file cannot be found.
:obj:`TypeError`
If the data type of `obj` is not supported.
Example
-------
To view the standard icons that come with Qt and that come with Windows run.
>>> from msl.examples.qt import ShowStandardIcons
>>> ShowStandardIcons() # doctest: +SKIP
"""
if isinstance(obj, QtGui.QIcon):
return obj
Expand Down Expand Up @@ -256,7 +263,7 @@ def image_to_base64(image=None, size=None, mode=QtCore.Qt.KeepAspectRatio, fmt='
app = application()

if image is None:
title = 'Select An Image File To Convert To Base64'
title = 'Select an image file to convert to Base64'
filters = {'Images': ('bmp', 'jpg', 'jpeg', 'png'), 'All files': '*'}
image = prompt.filename(title=title, filters=filters)
if image is None:
Expand Down Expand Up @@ -295,5 +302,6 @@ def image_to_base64(image=None, size=None, mode=QtCore.Qt.KeepAspectRatio, fmt='
return bytes(array.toBase64())


from .loop_until_abort import LoopUntilAbort
from . import prompt
from .loop_until_abort import LoopUntilAbort
from .toggle_switch import ToggleSwitch
73 changes: 73 additions & 0 deletions msl/qt/toggle_switch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"""
A toggle switch QWidget.
"""
from PyQt5 import QtWidgets, QtCore, QtGui


class ToggleSwitch(QtWidgets.QAbstractButton):

def __init__(self, parent=None, checked_color='#009688', unchecked_color='#B4B4B4'):
"""Constructs a toggle switch, |switch|
.. |switch| image:: ../../docs/_static/toggle_switch.gif
:scale: 50 %
.. literalinclude:: ../../msl/examples/qt/toggle_switch.py
Parameters
----------
parent : :obj:`QWidget`
The parent :obj:`QWidget`.
checked_color : :obj:`str` or :obj:`QColor`
The color to draw the switch when it is in the checked state.
unchecked_color : :obj:`str` or :obj:`QColor`
The color to draw the switch when it is **not** in the checked state.
"""
super(ToggleSwitch, self).__init__(parent)

self._pad = 4
self._checked_brush = QtGui.QBrush(QtGui.QColor(checked_color))
self._unchecked_brush = QtGui.QBrush(QtGui.QColor(unchecked_color))
self.setCheckable(True)

def paintEvent(self, event):
"""Overrides the paintEvent method."""
diameter = self.height() - 2 * self._pad
radius = diameter * 0.5

if self.isChecked():
brush = self._checked_brush
x = self.width() - diameter - self._pad
opacity = 0.3
else:
brush = self._unchecked_brush
x = self._pad
opacity = 0.5

p = QtGui.QPainter(self)
p.setPen(QtCore.Qt.NoPen)
p.setRenderHint(QtGui.QPainter.Antialiasing, True)
ellipse = QtCore.QRect(x, self._pad, diameter, diameter)
w = max(diameter, self.width() - 2 * self._pad)
rect = QtCore.QRect(self._pad, self._pad, w, diameter)
if self.isEnabled():
p.setBrush(brush)
p.setOpacity(opacity)
p.drawRoundedRect(rect, radius, radius)
p.setOpacity(1.0)
p.drawEllipse(ellipse)
else:
p.setBrush(QtCore.Qt.black)
p.setOpacity(0.12)
p.drawRoundedRect(rect, radius, radius)
p.setOpacity(1.0)
p.setBrush(QtGui.QColor('#BDBDBD'))
p.drawEllipse(ellipse)

def enterEvent(self, event):
"""Overrides the enterEvent method."""
self.setCursor(QtCore.Qt.PointingHandCursor)

def sizeHint(self):
"""Overrides the sizeHint method."""
return QtCore.QSize(2 * (self.height() + self._pad), self.height() + 2 * self._pad)

0 comments on commit 4216adc

Please sign in to comment.