Emit g_signal from thread to main in Python - multithreading

So I found this gist on how to create a "thread pooling" system and my issue is: when the executed function finished in the thread the "completed" signal must be emitted from (or to) the main thread. The solution presented on the gist was to overwrite GObject.emit function using GObject.idle_add(GObject.GObject.emit, self, *args) which does the trick in the gist example, but misteriously does not work for me. I created a slightly modified version of his code that does what I need, except from emitting the signals correctly/at all.
class _IdleObject(GObject.GObject):
""" Override GObject.GObject to always emit signals in the main thread by
emmitting on an idle handler """
#trace
def __init__(self):
GObject.GObject.__init__(self)
#trace
def emit(self, *args):
GLib.idle_add(GObject.GObject.emit, self, *args)
In summary, the signals are either not emitted or emitted on secondary threads (when the emit function overwrite is commented out) which can't update the UI therefore don't solve my problem. Any ideas on what's going on?
My version of his gist can be found here

Related

PyQT5 - how can i get the QApplication to call a method once it is loaded?

I would like to write in a QTextEdit as soon as the main window is loaded, how can I do that efficiently ?
I tried changing a boolean value once app.exec() is called but since that's the main application loop, it does not work.
The only current solutions I have ( and that I would like to avoid ) are doing a timer or asking the user to press a button that I link to the method.
I tried looking into the signals sent by QApplication, QGuiApplication and the parents but could not find a signal related to the main window having loaded anything.
If something has to happen as soon as a widget is [going to be] shown, you can do it in the showEvent() method:
class MainWindow(QtWidgets.QMainWindow):
firstShown = False
def showEvent(self, event):
super().showEvent(event)
if not self.firstShown:
self.firstShown = True
self.textEdit.setPlainText('hello')
Note that this does not exactly happen as soon as the window is shown (there's a moltitude of reason for this, including the fact that the system's "window manager" might need some time to actually show the widget); In such cases, it is safe enough to use a singleshot QTimer set to 0:
class MainWindow(QtWidgets.QMainWindow):
firstShown = False
def showEvent(self, event):
super().showEvent(event)
if not self.firstShown:
self.firstShown = True
QtCore.QTimer.singleShot(0, self.doStartupEvents)
def doStartupEvents(self):
self.textEdit.setPlainText('hello')
Another theoretical possibility is to do those events in the paintEvent (ensuring that they happen only the first time), but I wouldn't suggest it.

How do I connect a PyQt5 slot to a signal function in a class?

I'm trying to set up a pyqt signal between a block of UI code and a separate python class that is just for handling event responses. I don't want to give the UI code access to the handler (classic MVC style). Unfortunately, I am having difficulty connecting the slot to the signal. Here is the code:
from PyQt5 import QtCore
from PyQt5.QtCore import QObject
class UiClass(QObject):
mySignal = QtCore.pyqtSignal( str )
def __init__(self):
QObject.__init__(self)
def send_signal(self):
self.mySignal.emit("Hello world!")
class HandlerClass():
currentMessage = "none"
def register(self, mySignal):
mySignal.connect(self.receive_signal)
#QtCore.pyqtSlot(str)
def receive_signal(self, message):
self.currentMessage = message
print(message)
ui = UiClass()
handler = HandlerClass()
handler.register(ui.mySignal)
ui.send_signal()
When I run this code it fails at the handler.register line. Here is the error:
Traceback (most recent call last):
File "C:\git\IonControl\testpyqtslot.py", line 25, in
handler.register(ui.mySignal)
File "C:\git\IonControl\testpyqtslot.py", line 17, in register
mySignal.connect(self.receive_signal)
TypeError: connect() failed between UiClass.mySignal[str] and receive_signal()
I'd like this code to successfully register the signal to the slot and have the handler print "hello world" at the end. What did I do wrong here?
My basic question is this: how do I connect a signal to a slot function that is part of a class?
The error happens becuase you are using pyqtSlot decorator in a class which doesn't inherit from QObject. You can fix the problem by either getting rid of the decorator, or making HandlerClass a subclass of QObject.
The main purpose of pyqtSlot is to allow several different overloads of a slot to be defined, each with a different signature. It may also be needed sometimes when making cross-thread connections. However, these use-cases are relatively rare, and in most PyQt applications it is not necessary to use pyqtSlot at all. Signals can be connected to any python callable object, whether it is decorated as a slot or not.

Second Thread doesn't start until first thread ends

I haven't used threading in python yet and I'm trying to get a working example going but it doesn't seem to be working. Once my first thread begins my program just hangs while that "thread" does it's work. It appears to be acting as if I just called a function normally. My second thread which is setup to run alongside thread1 doesn't start until thread1 finishes. Is there something I'm doing wrong?
class MainDialog(QDialog, Gui.Ui_Dialog):
def __init__(self,parent=None):
super(MainDialog,self).__init__(parent)
self.setupUi(self)
threading.Thread(target=thread1()).start()
threading.Thread(target=thread2()).start()
def thread1(self):
//Do stuff
def thread2(self):
//Do other stuff

PyQt signal with Twisted: Cannot catch custom signal

Problem Description:
A server process which keeps a database (Cacheable)
A client which reads and displays the data in UI (RemoteCache)
They talk to each other through Twisted PB
I'd like to refresh my UI when the server database changes.
My client has a method, _mutation_handler, which is notified by the server
To notify my UI, I created a singleton Notifier class which emits a signal.
Then in my Qt widget, I wire the signal to the widget's slot.
# inside the RemoteCache subclass on my client
# notified by the PB server when something happens
def __mutation_handler(self):
notifier = Notifier()
notifier.notify()
# inside notify.py
class Notifier(QObject):
def __new__(cls):
# Make it a singleton
def notify(self):
self.emit(SIGNAL('SomethingChanged'))
# inside the RemoteCache subclass on my client
def __mutation_handler(self):
# singleton notifier
notifier = Notifier()
notifier.notify()
# inside my widget.py
class MyWidget(QWidget):
def __init__(self):
... # code
self.notifier = Notifier()
self._create_signal_slot_connections()
... # more code
def _create_signal_slot_connections(self):
self.connect(self.notifier, SIGNAL('SomethingChanged'),self.shout)
def shout(self):
print 'Server's database changed!!!'
Problem:
When I change something in my server's database, _mutation_handler gets called
correctly, then the signal is emitted alright.
However, MyWidget is NOT able to catch the signal.
Note: I am using qt4reactor to adapt Twisted's event loop to suit qt's
I really appreciate your help!!!
There seems to be a new API for signals in PyQt4. See http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/new_style_signals_slots.html for examples on its use. Perhaps this will work better.

Exiting a Jython application that uses Swing

I'm using Swing from Jython, and I found that while System.exit() (from java.lang) or JFrame.setDefaultCloseOperation(EXIT_ON_CLOSE) work properly, calling sys.exit() hangs.
Apparently, a function is registered through atexit.register that waits for all threads to exit, as it is expected from Python (this is actually different from Java).
This means that if an ActionListener gets called (for instance when clicking on a JButton), AWT's Event Dispatching Thread gets spawned, and calling sys.exit() will hang forever, waiting for it to exit.
Here is an example: https://gist.github.com/2877919. Closing the frame exits the program, unless the button is clicked first.
What is the best way to exit my Jython application? Using EXIT_ON_CLOSE or System.exit() would completely ignore atexit...
I don't think you need multithreading for this, you just need to make sure the window is not closed until you want so. When you close the window, you close the system:
from javax.swing import JFrame, JButton, JOptionPane
from java.awt.event import ActionListener, WindowAdapter
import sys
class Frame(JFrame, ActionListener):
def __init__(self):
self.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE)
button = JButton("Hello", actionCommand='button')
button.addActionListener(self)
self.getContentPane().add(button)
self.pack()
self.setResizable(False)
def actionPerformed(self, event):
print event.getActionCommand();
class Adapter(WindowAdapter):
def windowClosing(self, event):
if JOptionPane.showConfirmDialog(None, "Wanna exit?","Jython Test", JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION:
sys.exit(0)
if __name__ == '__main__':
frame = Frame();
frame.setVisible(True)
frame.addWindowListener(Adapter())

Resources