Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: [3.9, 3.8, 3.7, 3.6, 3.5]
python-version: ["3.12", "3.11", "3.10", "3.9", "3.8"]

steps:
- uses: actions/checkout@v2
Expand All @@ -29,7 +29,7 @@ jobs:
python -m ensurepip
python -m pip install --upgrade pip
python -m pip install flake8
python -m pip install PyQt5
python -m pip install PyQt6_SwitchControl
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
Expand Down
36 changes: 0 additions & 36 deletions .github/workflows/python-publish.yml

This file was deleted.

4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ wheels/
.installed.cfg
*.egg
MANIFEST
pyproject.toml

# PyInstaller
# Usually these files are written by a python script from a template
Expand Down Expand Up @@ -112,3 +113,6 @@ dmypy.json

# Pyre type checker
.pyre/

# PyCharm/Jetbrains project settings
.idea/
1 change: 1 addition & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
MIT License

Copyright (c) 2021 Parsa.py
Modified work Copyright (c) 2024 github/M1GW

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
MIT License

Copyright (c) 2021 Parsa.py
Modified work Copyright (c) 2024 github/M1GW

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand All @@ -21,9 +22,9 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
from PyQt5.QtCore import Qt, QPoint, pyqtSlot, pyqtProperty, QPropertyAnimation, QEasingCurve
from PyQt5.QtWidgets import QWidget, QCheckBox
from PyQt5.QtGui import QPainter, QColor
from PyQt6.QtCore import Qt, QPoint, pyqtSlot, pyqtProperty, QPropertyAnimation, QEasingCurve
from PyQt6.QtWidgets import QWidget, QCheckBox
from PyQt6.QtGui import QPainter, QColor


def take_closest(num, collection):
Expand All @@ -42,8 +43,8 @@ def __init__(self, parent, move_range: tuple, color, animation_curve, animation_
def paintEvent(self, event):
painter = QPainter()
painter.begin(self)
painter.setRenderHint(QPainter.HighQualityAntialiasing)
painter.setPen(Qt.NoPen)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
painter.setPen(Qt.PenStyle.NoPen)
painter.setBrush(QColor(self.color))
painter.drawEllipse(0, 0, 22, 22)
painter.end()
Expand All @@ -54,18 +55,18 @@ def set_color(self, value):

def mousePressEvent(self, event):
self.animation.stop()
self.oldX = event.globalX()
self.oldX = event.globalPosition().x()
return super().mousePressEvent(event)

def mouseMoveEvent(self, event):
delta = event.globalX() - self.oldX
delta = event.globalPosition().x() - self.oldX
self.new_x = delta + self.x()
if self.new_x < self.move_range[0]:
self.new_x += (self.move_range[0] - self.new_x)
if self.new_x > self.move_range[1]:
self.new_x -= (self.new_x - self.move_range[1])
self.move(self.new_x, self.y())
self.oldX = event.globalX()
self.move(int(self.new_x), self.y())
self.oldX = event.globalPosition().x()
return super().mouseMoveEvent(event)

def mouseReleaseEvent(self, event):
Expand All @@ -88,15 +89,15 @@ def mouseReleaseEvent(self, event):

class SwitchControl(QCheckBox):
def __init__(self, parent=None, bg_color="#777777", circle_color="#DDD", active_color="#aa00ff",
animation_curve=QEasingCurve.OutBounce, animation_duration=500, checked: bool = False,
animation_curve=QEasingCurve.Type.OutBounce, animation_duration=500, checked: bool = False,
change_cursor=True):
if parent is None:
super().__init__()
else:
super().__init__(parent=parent)
self.setFixedSize(60, 28)
if change_cursor:
self.setCursor(Qt.PointingHandCursor)
self.setCursor(Qt.CursorShape.PointingHandCursor)
self.bg_color = bg_color
self.circle_color = circle_color
self.animation_curve = animation_curve
Expand Down Expand Up @@ -172,8 +173,8 @@ def start_animation(self, checked):
def paintEvent(self, event):
painter = QPainter()
painter.begin(self)
painter.setRenderHint(QPainter.HighQualityAntialiasing)
painter.setPen(Qt.NoPen)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
painter.setPen(Qt.PenStyle.NoPen)
if not self.isChecked():
painter.setBrush(QColor(self.bg_color))
painter.drawRoundedRect(0, 0, self.width(), self.height(), self.height() / 2, self.height() / 2)
Expand All @@ -186,11 +187,11 @@ def hitButton(self, pos):

def mousePressEvent(self, event):
self.auto = True
self.pos_on_press = event.globalPos()
self.pos_on_press = event.globalPosition()
return super().mousePressEvent(event)

def mouseMoveEvent(self, event):
if event.globalPos() != self.pos_on_press:
if event.globalPosition() != self.pos_on_press:
self.auto = False
return super().mouseMoveEvent(event)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
MIT License

Copyright (c) 2021 Parsa.py
Modified work Copyright (c) 2024 github/M1GW

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand All @@ -21,10 +22,10 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
from PyQt5.QtDesigner import QPyDesignerCustomWidgetPlugin
from PyQt5.QtGui import QIcon, QPixmap
from PyQt6.QtDesigner import QPyDesignerCustomWidgetPlugin
from PyQt6.QtGui import QIcon, QPixmap

from QSwitchControl import SwitchControl
from PyQt6_SwitchControl import SwitchControl


class SwitchControlPlugin(QPyDesignerCustomWidgetPlugin):
Expand Down Expand Up @@ -63,12 +64,12 @@ def isContainer(self):

def domXml(self):
return (
'<widget class="SwitchControl" name=\"switchControl\">\n'
'<widget class="SwitchControl" name="switchControl">\n'
"</widget>\n"
)

def includeFile(self):
return "QSwitchControl"
return "PyQt6_SwitchControl"


_logo_16x16_xpm = []
Expand Down
11 changes: 9 additions & 2 deletions QSwitchControl/__init__.py → PyQt6_SwitchControl/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""MIT License

Copyright (c) 2021 Parsa.py
Modified work Copyright (c) 2024 github/M1GW

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand All @@ -19,6 +20,12 @@
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE."""
from .QSwitchControl import SwitchControl
from .PyQt6_SwitchControl import SwitchControl
from .PyQt6_SwitchControl_plugin import SwitchControlPlugin

__version__ = "1.0.4"

def registerCustomWidgets():
return [SwitchControlPlugin()]


__version__ = "1.0.4.post1"
17 changes: 10 additions & 7 deletions QSwitchControl/__main__.py → PyQt6_SwitchControl/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
MIT License

Copyright (c) 2021 Parsa.py
Modified work Copyright (c) 2024 github/M1GW

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand All @@ -23,10 +24,10 @@
"""
import sys

from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QApplication, QWidget, QHBoxLayout

from QSwitchControl import SwitchControl
from PyQt6_SwitchControl import SwitchControl


class Form(QWidget):
Expand All @@ -42,12 +43,14 @@ def init_ui(self):
""")
switch_control = SwitchControl()
h_box = QHBoxLayout()
h_box.addWidget(switch_control, Qt.AlignCenter, Qt.AlignCenter)
h_box.addWidget(switch_control, Qt.AlignmentFlag.AlignCenter, Qt.AlignmentFlag.AlignCenter)
self.setLayout(h_box)
self.show()


app = QApplication(sys.argv)
form = Form()
if __name__ == '__main__':
sys.exit(app.exec_())
app = QApplication(sys.argv)
form = Form()
form.show()
app.exec()

73 changes: 43 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,66 +1,67 @@
# QSwitchControl
## Custom toggle-switch widget implemented in PyQt5 for PyQt5 applications!
[![CodeFactor](https://www.codefactor.io/repository/github/prx001/qswitchcontrol/badge)](https://www.codefactor.io/repository/github/prx001/qswitchcontrol)

# SwitchControl for PyQt6 <br/> (forked from [Prx001/QSwitchControl](https://github.com/Prx001/QSwitchControl))
## Custom toggle-switch widget implemented for \*PyQt6\* applications!
##

https://user-images.githubusercontent.com/67240789/128912103-b24d7321-a7d6-4b1b-bbdc-562dbd20b358.mp4



### An easy-to-use and modern toggle switch for Qt Python binding PyQt
QSwitchControl is a custom toggle-switch widget inherited from 'QCheckBox' class, and acts as a checkbox alternative widget in your PyQt5 application.
PyQt6_SwitchControl is a custom toggle-switch widget inherited from 'QCheckBox' class, and acts as a checkbox alternative widget in your PyQt6 application.
>This repository is a fork from [Prx001](https://github.com/Prx001/)'s [QSwitchControl](https://github.com/Prx001/QSwitchControl) project but the code has been modified to work with PyQt6.

## How to use?
### Installation
The package is available on [PyPi](https://pypi.org) so as always use pip for installation:
The package is available on [PyPi](https://pypi.org/project/PyQt6_SwitchControl) so as always use pip for installation:
```
pip install QSwitchControl
pip install PyQt6_SwitchControl
```

### Usage in your Python application
First of all, as expected, you need to import the package.
Import 'SwitchControl' class from the package:
```python
from QSwitchControl import SwitchControl
from PyQt6_SwitchControl import SwitchControl
```
Now the class is ready to use!
SwitchControl is an alternative widget for QCheckBox from Qt framework, same methods, same usage and that's how it works.
There are things you can define for your SwitchControl, like the circle color, background color, active color, animation easing curve, animation duration and some other things, but you can use default values. The package contains a '__main__' script so you can test the widget easily:
There are things you can define for your SwitchControl, like the circle color, background color, active color, animation easing curve, animation duration and some other things, but you can use default values. The package contains a '__main__' script, so you can test the widget easily:
```
python -m QSwitchControl
python -m PyQt6_SwitchControl
```
Bellow is the '__main__' script:
```python
import sys

from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QApplication, QWidget, QHBoxLayout

from QSwitchControl import SwitchControl
from PyQt6_SwitchControl import SwitchControl


class Form(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def __init__(self):
super().__init__()
self.init_ui()

def initUI(self):
self.resize(400, 400)
self.setWindowTitle("SwitchControl test")
self.setStyleSheet("""
def init_ui(self):
self.resize(400, 400)
self.setWindowTitle("SwitchControl test")
self.setStyleSheet("""
background-color: #222222;
""")
switch_control = SwitchControl()
hbox = QHBoxLayout()
hbox.addWidget(switch_control, Qt.AlignCenter, Qt.AlignCenter)
self.setLayout(hbox)
self.show()
switch_control = SwitchControl()
h_box = QHBoxLayout()
h_box.addWidget(switch_control, Qt.AlignmentFlag.AlignCenter, Qt.AlignmentFlag.AlignCenter)
self.setLayout(h_box)
self.show()


app = QApplication(sys.argv)
form = Form()
if __name__ == '__main__':
sys.exit(app.exec_())
app = QApplication(sys.argv)
form = Form()
form.show()
app.exec()
```
In this script we used the default values for our widget:
```python
Expand All @@ -71,5 +72,17 @@ You can define the values yourself. Bellow is an example:
switch_control = SwitchControl(bg_color="#777777", circle_color="#DDD", active_color="#aa00ff", animation_curve=QtCore.QEasingCurve.InOutCubic, animation_duration=300, checked=True, change_cursor=False)
```
# Qt Designer integration
Qt Designer is a very extensible tool, even can support your custom widgets! It means you can interact with your custom widget just as you do with Qt widgets, like QPushButton, QCheckBox, you can drag and drop them on your form, change their sizes, set properties and so on.
Qt Designer can load plugins, and you can load your custom widgets through plugins, then your custom widget is available in Qt Designer Widget Box. In C++, using Qt Creator IDE you can create your custom widgets and compile them to .dll file, then you put the dll file (your plugin) into Qt Designer's relative path for plugins, and that's it you can use your widget in Designer. But, here in python the story is a little different. PyQt supports this plugin developement and integrate *Python based* Qt custom widgets in Qt Designer. [Learn more about integrating PyQt custom widgets in Qt Designer](https://wiki.python.org/moin/PyQt/Using_Python_Custom_Widgets_in_Qt_Designer) There is the Qt Designer plugin for QSwitchControl in package, [QSwitchControlplugin.py](https://github.com/Prx001/QSwitchControl/blob/main/QSwitchControlplugin.py). You can load it to your Qt Designer.
Qt Designer is a very extensible tool, even can support your custom widgets!
It means you can interact with your custom widget just as you do with Qt
widgets, like QPushButton, QCheckBox, you can drag and drop them on your
form, change their sizes, set properties and so on. Qt Designer can load
plugins, and you can load your custom widgets through plugins, then your
custom widget is available in Qt Designer Widget Box. In C++, using Qt
Creator IDE you can create your custom widgets and compile them to .dll file,
then you put the dll file (your plugin) into Qt Designer's relative path for
plugins, and that's it you can use your widget in Designer. But, here in python
the story is a little different. PyQt supports this plugin development and
integrate *Python based* Qt custom widgets in Qt Designer. [Learn more about integrating PyQt custom widgets in Qt Designer](https://wiki.python.org/moin/PyQt/Using_Python_Custom_Widgets_in_Qt_Designer)
There is the Qt Designer
plugin for PyQt6_SwitchControl in package, [PyQt6_SwitchControl_plugin.py](https://github.com/M1GW/PyQt6_SwitchControl/blob/main/PyQt6_SwitchControl/PyQt6_SwitchControl_plugin.py).
You can load it to your Qt Designer.
4 changes: 4 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[egg_info]
tag_build =
tag_date = 0

Loading