How to call independent or async func in PyQt5 - python

I have a basic PyQt5 application. I want to make it so that when a certain button is clicked, a function is called that will run until another button is clicked. How is it possible to implement it?
Something like this (of course it doesn't work):
...
self.ui.start_button.clicked.connect(infinity_before_cancel_method)
self.ui.stop_button.clicked.connect(infinity_before_cancel_method)
...
def infinity_before_cancel_method():
...
while True:
do_something()
I have absolutely no idea how to do this in PyQt5. I've seen that this can be done using a multiprocessing library or similar, but I don't quite understand how to apply it to a PyQt5 application. Any hints would be helpful!

Related

How to elegantly connect many signals to a function in PyQt5?

I am currently building an interface using PyQt5 and I was wondering if there is an elegant way to connect several signals to the same function?
The straight-forward solution is this:
self.ui.button1.clicked.connect(self.Function)
self.ui.button2.clicked.connect(self.Function)
self.ui.button3.clicked.connect(self.Function)
self.ui.button4.clicked.connect(self.Function)
but is there a nicer, more readable option? For example something that would look like:
self.Function.connect(self.ui.button1.clicked,
self.ui.button2.clicked,
self.ui.button3.clicked,
self.ui.button4.clicked)
Also I started reading about QSignalMappers but if they can be avoided it's nice.
Thank you in advance!
You could make a function that takes a tuple or list of buttons as an argument, then connects the click signal for each one.
self.connect_buttons((self.ui.button1, self.ui.button2, self.ui.button3, self.ui.button4))
def connect_buttons(self, button_tup):
for button in button_tup:
button.clicked.connect(self.Function)

PyQt5 receivers

I wanted to port a PyQt4 app of mine to PyQt5 and came across a subtle problem.
At some point I check if a custom QThread object (worker) has still some specific signal connected, which I have done in PyQt4 like so (exemplary code):
if worker.receivers(PyQt4.QtCore.SIGNAL("signalFinished(QString,QString)")):
do_stuff()
Is there any way to do this in PyQt5? The PyQt5 reference is not very helpful, and always leeds me to the C++ reference, where it is still the same behaviour.
Of course there is a more 'pythonic' solution using a try-except-pass block instead of an if statement, but I am still wondering for the 'PyQt signal' way.
With the new-style syntax, the equivalent code would simply be:
if worker.receivers(worker.signalFinished[str, str])):
do_stuff()

Keeping a dialog from showing PySide for testing

I'm writing some test functions for a form I made. There are a couple of QMessageBox that are invoked(one through QMessageBox.question method and one through the QMessageBox.information method. While my custom widget is not shown on screen, these two actually show up on screen.
I tried dismissing them by looping through widgets I get in QApplication.topLevelWidgets() and dismissing the right one, however, it seems my code only continues executing after I manually dismiss the MessageBox.
So my question is two-fold:
1) How do I keep the QMessageBox (or any widget really) from showing on screen during testing.
2) How can I programmatically accept/reject/dismiss this widget.
You can set up a timer to automatically accept the dialog. If the timeout is long, the dialog will still display for a while:
w = QtGui.QDialog(None)
t = QtCore.QTimer(None)
t.timeout.connect(w.accept)
t.start(1)
w.exec_()
For your specific case, if you don't want to touch the code being testes, you can have the timer run a function to accept all current modal widgets, as you were suggesting:
def accept_all():
for wid in app.topLevelWidgets():
if wid.__class__ == QtGui.QDialog: #or QMessageBox, etc:
wid.accept()
t = QtCore.QTimer(None)
t.timeout.connect(accept_all)
t.start(10)
I decided to use the mock module instead. It seemed better since the other solution would actually draw on screen, which is not optimal for testing.
If you have the same problem and would like to mock a question QMessageBox you can something like this:
#patch.object(path.QMessageBox, "question", return_value=QtGui.QMessageBox.Yes)
Would simulate a MessageBox in which the Yes button was clicked.
I think it makes sense with Qt testing (including PySide/PyQt) to mock your GUI interaction and do dedicated GUI testing separately as necessary.
For mocking GUI interaction, I'd use the mock library, as I myself do regularly. The drawback of this is that you have to depend on mock definitions, which may drift out of sync with respect to your production application. On the other hand, your tests will be speedier than involving the actual GUI.
For testing the GUI itself, I'd write a separate layer of tests using a GUI testing tool such as Froglogic Squish. It'll typically lead to more involved/slower tests, but you'll test your application directly, and not merely simulate the GUI layer. My approach in this regard is invest in such a tool if the budget allows, and run these tests as necessary keeping in mind they'll be relatively slow.

Working with PyQt4

I''ve been experimenting with PyQt4 and I'm having a hard time with getting it to run the way I need it to. What I'm looking for is a way to have my own code run in a widget independent of gui events. Is there something like an 'onRender' command for your widget to run bckground code?

convert ahk to python

I am learning both autohotkey and python. I wrote this script in ahk (and it works!) that automatically joins tables (using tableninja) in the pokerstars client--
^q::
Loop
{
Send q
Sleep 500
Send {PgUp}
Sleep 500
Send w
Sleep 60000
}
return
I'd like to convert this into python--could you give me an idea as to which modules I can use to accomplish this?
What the python script needs to do is to (while looping) type in a letter (on a notepad that's already open), go down two lines, type in another letter, then wait one minute before starting over.
I am thinking--
import module to auto-type letters
import module that works as timer
def function
type letter q
enter
enter
def function
type letter w
def function
sleep
while True
function
function
function
I am teaching myself how to code. I haven't reached that part about python modules just yet. Thanks!
Assuming you work on windows(don't think AHK runs on anything else), you should check out sendkeys. It will make sending keystrokes a piece of cake. If you want somthing a little more robust, take a look at pywinauto
For the shortcut part, take a look at pyhook
I suggest these modules:
SendKeysCtypes for any sending of keystrokes and sending shortcuts to a window.
SendKeysCtypes is a new and more stable version of SendKeys. I have had issues with SendKeys in the past.
PYHK to deal with global hotkeys - receive hotkeys and trigger functions.
PYHK is based on pyHook and makes hotkey registration very simple. I wrote it because I had the exact same idea as you - I wanted to to do AHK functionality in python.
win32gui for window handling such as moving resizing.
I personally prefer win32gui for short, simple tasks. I use pywinauto for more complex tasks. An example would be if I had to access a menu within a program (like File-New).
mouse.py to control the mouse. This is the most robust way I have found so far. The version I use is an extension of a module I found here at stackoverflow - ctypes mouse_events.
I have personally done several programs for poker with python. I have released source code of my smaller programs. You can find them with source on my website schurpf.com/poker-software.
there's also AutoPy, a cross-platform library for this purpose.

Categories