You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Use QtPy abstraction layer (#144). GHA tests with PySide2 and PyQt5 (#146)
- Use `qtpy` as virtual Qt binding package. GHA unit tests are run with PySide2 and PyQt5 (#146)
- Add `pyqt_env.yml` and `pyside_env.yml` environment files (#146)
- Update `CONTRIBUTING.md`, `README.md` and add documentation file (#146)
Co-authored-by: Sam Tygier <[email protected]> Danica Sugic <[email protected]>
Copy file name to clipboardexpand all lines: CONTRIBUTING.md
+9
Original file line number
Diff line number
Diff line change
@@ -32,6 +32,15 @@ cd eqt
32
32
mamba env create -f recipe/eqt_env.yml
33
33
```
34
34
35
+
`eqt` uses the [`qtpy`](https://github.com/spyder-ide/qtpy) abstraction layer for Qt bindings, meaning that it works with either PySide or PyQt bindings. Thus, `eqt_env` does not depend on either. The environment can be updated with either `pyside2` or `pyqt5`, as follows.
To run a function in a separate thread we use a `Worker` which is a subclass of a `QRunnable`.
6
+
7
+
For the `Worker` to work one needs to define:
8
+
9
+
1. the function that does what you need
10
+
2. Optional callback methods to get the status of the thread by means of `QtCore.QSignal`s
11
+
12
+
On [initialisation](https://github.com/TomographicImaging/eqt/blob/535e487d09d928713d7d6aa1123657597627c4b0/eqt/threading/QtThreading.py#L32-L38) of the `Worker` the user needs to pass the function that has to run in the thread, i.e. `fn` below, and additional optional positional and keyword arguments, which will be passed on to the actual function that is run in the `QRunnable`.
13
+
14
+
```python
15
+
classWorker(QtCore.QRunnable):
16
+
def__init__(self, fn, *args, **kwargs):
17
+
self.fn = fn
18
+
self.args = args
19
+
self.kwargs = kwargs
20
+
self.signals = WorkerSignals()
21
+
```
22
+
23
+
In practice the user will need to pass to the `Worker` as many parameters as there are listed in the [function](https://github.com/TomographicImaging/eqt/blob/535e487d09d928713d7d6aa1123657597627c4b0/eqt/threading/QtThreading.py#L56) to be run.
24
+
25
+
```python
26
+
result =self.fn(*self.args, **self.kwargs)
27
+
```
28
+
29
+
But `Worker` will [add](https://github.com/TomographicImaging/eqt/blob/535e487d09d928713d7d6aa1123657597627c4b0/eqt/threading/QtThreading.py#L41-L43) to the `**kwargs` the following `QSignal`.
Therefore it is advisable to always have `**kwargs` in the function `fn` signature so that you can access the `QSignal` and emit the signal required. For instance one could emit a progress by:
This is done just after one has defined the `Worker`:
52
+
53
+
```python
54
+
defhandle_progress(num_iter):
55
+
# do something with the progress
56
+
print ("Current progress is ", num_iter)
57
+
58
+
worker = Worker(fn, 10)
59
+
worker.signals.progress.connect(handle_progress)
60
+
```
61
+
62
+
So, each time `fn` comes to `progress_callback.emit( i )` the function `handle_progress` will be called with the parameter `i` of its `for` loop.
63
+
64
+
### Signals available
65
+
66
+
The signals that are available in the `Worker` class are defined in [`WorkerSignal`](https://github.com/TomographicImaging/eqt/blob/535e487d09d928713d7d6aa1123657597627c4b0/eqt/threading/QtThreading.py#L66) and are the following. Below you can also see the type of data that each signal can emit.
67
+
68
+
```python
69
+
finished = QtCore.Signal()
70
+
error = QtCore.Signal(tuple)
71
+
result = QtCore.Signal(object)
72
+
73
+
progress = QtCore.Signal(int)
74
+
message = QtCore.Signal(str)
75
+
status = QtCore.Signal(tuple)
76
+
```
77
+
78
+
Read more on [Qt signals and slots](https://doc.qt.io/qt-5/signalsandslots.html) and on how to use them in [PySide2](https://wiki.qt.io/Qt_for_Python_Signals_and_Slots).
Copy file name to clipboardexpand all lines: README.md
+9-78
Original file line number
Diff line number
Diff line change
@@ -4,12 +4,13 @@
4
4
5
5
Templates & tools to develop Qt GUIs in Python.
6
6
7
-
One use case is accepting user input while running another task asynchronously (so that the UI is still responsive).
8
-
7
+
Some example classes are
9
8
1.`UIFormWidget`: a class to help creating Qt forms programmatically, useable in `QDockWidgets` and `QWidget`
10
9
2.`FormDialog`: a `QDialog` with a form inside with <kbd>OK</kbd> and <kbd>Cancel</kbd> buttons
11
10
3.`Worker`: a class that defines a `QRunnable` to handle worker thread setup, signals and wrap up
12
11
12
+
One use case is accepting a user input while running another task asynchronously (so that the UI is still responsive).
13
+
13
14
## Installation
14
15
15
16
Via `pip`/`conda`/`mamba`, i.e. any of the following:
@@ -18,86 +19,16 @@ Via `pip`/`conda`/`mamba`, i.e. any of the following:
18
19
-`conda install -c conda-forge eqt`
19
20
-`mamba install -c conda-forge eqt`
20
21
21
-
## Examples
22
-
23
-
See the [`examples`](examples) directory, e.g. how to launch a `QDialog` with a form inside using `eqt`'s [`QWidget`](examples/dialog_example.py) or [`FormDialog`](examples/dialog_example_2.py).
24
-
25
-
### Running asynchronous tasks
26
-
27
-
To run a function in a separate thread we use a `Worker` which is a subclass of a `QRunnable`.
28
-
29
-
For the `Worker` to work one needs to define:
30
-
31
-
1. the function that does what you need
32
-
2. Optional callback methods to get the status of the thread by means of `QtCore.QSignal`s
33
-
34
-
On [initialisation](https://github.com/TomographicImaging/eqt/blob/535e487d09d928713d7d6aa1123657597627c4b0/eqt/threading/QtThreading.py#L32-L38) of the `Worker` the user needs to pass the function that has to run in the thread, i.e. `fn` below, and additional optional positional and keyword arguments, which will be passed on to the actual function that is run in the `QRunnable`.
35
-
36
-
```python
37
-
classWorker(QtCore.QRunnable):
38
-
def__init__(self, fn, *args, **kwargs):
39
-
self.fn = fn
40
-
self.args = args
41
-
self.kwargs = kwargs
42
-
self.signals = WorkerSignals()
43
-
```
44
-
45
-
In practice the user will need to pass to the `Worker` as many parameters as there are listed in the [function](https://github.com/TomographicImaging/eqt/blob/535e487d09d928713d7d6aa1123657597627c4b0/eqt/threading/QtThreading.py#L56) to be run.
46
-
47
-
```python
48
-
result =self.fn(*self.args, **self.kwargs)
49
-
```
50
22
51
-
But `Worker` will [add](https://github.com/TomographicImaging/eqt/blob/535e487d09d928713d7d6aa1123657597627c4b0/eqt/threading/QtThreading.py#L41-L43) to the `**kwargs` the following `QSignal`.
23
+
#### Note:
24
+
`eqt` uses the [`qtpy`](https://github.com/spyder-ide/qtpy) abstraction layer for Qt bindings, meaning that it works with either PySide or PyQt bindings. Thus, the package does not depend on either. If the environment does not already have a Qt binding then the user *must* install either `pyside2` or `pyqt5`.
Therefore it is advisable to always have `**kwargs` in the function `fn` signature so that you can access the `QSignal` and emit the signal required. For instance one could emit a progress by:
This is done just after one has defined the `Worker`:
74
-
75
-
```python
76
-
defhandle_progress(num_iter):
77
-
# do something with the progress
78
-
print ("Current progress is ", num_iter)
79
-
80
-
worker = Worker(fn, 10)
81
-
worker.signals.progress.connect(handle_progress)
82
-
```
83
-
84
-
So, each time `fn` comes to `progress_callback.emit( i )` the function `handle_progress` will be called with the parameter `i` of its `for` loop.
85
-
86
-
### Signals available
87
-
88
-
The signals that are available in the `Worker` class are defined in [`WorkerSignal`](https://github.com/TomographicImaging/eqt/blob/535e487d09d928713d7d6aa1123657597627c4b0/eqt/threading/QtThreading.py#L66) and are the following. Below you can also see the type of data that each signal can emit.
89
-
90
-
```python
91
-
finished = QtCore.Signal()
92
-
error = QtCore.Signal(tuple)
93
-
result = QtCore.Signal(object)
26
+
## Examples
94
27
95
-
progress = QtCore.Signal(int)
96
-
message = QtCore.Signal(str)
97
-
status = QtCore.Signal(tuple)
98
-
```
28
+
See the [`examples`](examples) directory, e.g. how to launch a `QDialog` with a form inside using `eqt`'s [`QWidget`](examples/dialog_example.py) or [`FormDialog`](examples/dialog_example_2.py).
99
29
100
-
Read more on [Qt signals and slots](https://doc.qt.io/qt-5/signalsandslots.html) and on how to use them in [PySide2](https://wiki.qt.io/Qt_for_Python_Signals_and_Slots).
0 commit comments