PyQT QtCore.SIGNAL - python

Is there any list of the signals that can be use with PyQT4 or at least there is one that is the opposite of lostFocus()?

There is a QFocusEvent event generated by 'QWidget', but not a signal. There is however a convenient event handler that catches these events: focusInEvent.
You can add your own signal by reimplementing this handler. For example (not tested):
class MyWidget(QtGui.QWidget):
focus_in = QtCore.pyqtSignal(int, name='focusIn')
def focusInEvent(self, event):
self.focus_in.emit()
QtGui.QWidget.focusInEvent(self, event)
Now you get a focusIn signal.

Related

How to correctly override qscintilla mousePressEvent?

I have class MainWindow and it have qscintilla editor, i want to add listener to editor mousePressEvent
class MainWindow(QtWidgets.QMainWindow, gui.Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.editor.mousePressEvent = self.on_editor_click
def on_editor_click(self, QMouseEvent):
// here i want add my code
return QsciScintilla.mousePressEvent(self, QMouseEvent)
If i override mousePressEvent - editor will broke (mouse clicks will not work). I tried call initial mousePressEvent, but it dont work, app crashing
Assigning the mousePressEvent method to another function is not correct, mousePressEvent is not a signal, it is a function that is part of QsciScintilla.
A possible solution is that you create a personalized QsciScintilla that emits a signal created as shown below:
class ClickQsciScintilla(QsciScintilla):
clicked = QtCore.pyqtSignal()
def mousePressEvent(self, event):
self.clicked.emit()
QsciScintilla.mousePressEvent(self, event)
Then you create an instance of ClickQsciScintilla and connect to that signal:
self.__editor = ClickQsciScintilla()
self.__editor.clicked.connect(self.on_editor_click)
Your handler:
def on_editor_click(self):
print "Editor was clicked!"

How to Catch Hover and Mouse Leave Signal In PyQt5

QPushButton has a signal which is named clicked(), and we can catch click events through it. Is there a method or signal which catches hover and leave events?
How can I catch mouse-over button and mouse-leave button, like this:
button = QPushButton(window)
button.clicked.connect(afunction)
Note: I use python3.
You need to subclass the QPushButton class and reimplement the enterEvent and leaveEvent:
class Button(QPushButton):
def __init__(self, parent=None):
super(Button, self).__init__(parent)
# other initializations...
def enterEvent(self, QEvent):
# here the code for mouse hover
pass
def leaveEvent(self, QEvent):
# here the code for mouse leave
pass
You can then handle the event locally, or emit a signal (if other widgets needs to react on this event you could use a signal to notify the event to other widgets).

PyQt5 focusIN/Out events

I am using Python 3.4 and Qt 5 for the first time. It's easy and I can understand most of functionality which I need. But (there is always "but") I don't understand how to use focusOut/clearFocus/focusIn events.
Am I right that old way:
QObject.connect(self.someWidget, QtCore.SIGNAL('focusOutEvent()'), self.myProcedure)
...does not work in Qt5?
I tried to understand this unsuccessfully. I'll be very thankful for a short example how to catch an event when e.g some of many QLineEdit has lost focus.
The issue here is that focusInEvent/clearFocus/focusOutEvent are not signals, they are event handlers. See for example here. If you want to catch these events you will need to re-implement the event handler on your object, for example by subclassing QLineEdit.
class MyQLineEdit(QLineEdit):
def focusInEvent(self, e):
# Do something with the event here
super(MyQLineEdit, self).focusInEvent(e) # Do the default action on the parent class QLineEdit
In PyQt5 the syntax for signals themselves is simpler. Taking for example the textEdited signal from QLineEdit, you can use that as follows:
self.someWidget.textEdited.connect( self.myProcedure )
This will connect the textEdited signal to your self.myProcedure method. The target method will need to accept the signal outputs, for example:
void textEdited ( const QString & text )
So you could define your self.myProcedure in your class as follows and it will receive the QString sent by that signal.
def myProcedure(self, t):
# Do something with the QString (text) object here
You can also define custom signals as follows:
from PyQt5.QtCore import QObject, pyqtSignal
class Foo(QObject):
an_event = pyqtSignal()
a_number = pyqtSignal(int)
In each of these cases pyqtSignal is used to define a property of the Foo class which you can connect to like any other signal. So for example to handle the above we could create:
def an_event_handler(self):
# We receive nothing here
def a_number_handler(self, i):
# We receive the int
You could then connect() and emit() the signals as follows:
self.an_event.connect( self.an_event_handler )
self.a_number.connect( self.a_number_handler )
self.an_event.emit() # Send the signal and nothing else.
self.a_number.emit(1) # Send the signal wih an int.
The link you posted gives more information on custom signals, signal naming and overloading with the new syntax.
It took me a while to get this figured out so I thought I would post it here to help anyone else having this problem. It is in Python 3.9.6 and PyQt 6.1.2.
This changes the color of the widget when it is in focus and again when it is out of focus.
import sys
from PyQt6 import QtWidgets
class Main(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("Qt Testing")
self.setGeometry(0, 0, 640, 120)
h = QtWidgets.QHBoxLayout()
w = ColorQLineEdit("one")
h.addWidget(w)
w = ColorQLineEdit("two")
h.addWidget(w)
self.setLayout(h)
class ColorQLineEdit(QtWidgets.QLineEdit):
def focusInEvent(self, event):
print("in")
self.setStyleSheet("background-color: yellow; color: red;")
super().focusInEvent(event)
def focusOutEvent(self, event):
print("out")
self.setStyleSheet("background-color: white; color: black;")
super().focusOutEvent(event)
app = QtWidgets.QApplication(sys.argv)
main = Main()
main.show()
sys.exit(app.exec())

Qt ShortcutOverride default action

I understand that QEvent::ShortcutOverride occurs when there is a shortcut registered in the parent and the child wants to "go against the rule". The example given on the Qt Wiki is of a media player which pauses with Space but a QLineEdit might want to use the Space, which makes a lot of sense.
Furthermore, if the event is accepted then a QEvent::KeyPress is generated to the child widget so you can treat your particular case.
Now, my question is, why does it seem that the default action is to actually accept the QEvent::ShortcutOverride when a standard shortcut is used? This seems to me like the opposite of what the name suggest, i.e., it's overriden by default and you have to treat the event to let the shortcut pass.
In the code below, if you don't install the event filter you don't see the message.
from PySide.QtGui import QApplication
from PySide import QtGui, QtCore
app = QApplication([])
class Test(QtGui.QWidget):
def __init__(self, parent=None):
super(Test, self).__init__(parent)
self.setLayout(QtGui.QVBoxLayout())
self.w_edit = QtGui.QLineEdit(parent=self)
self.layout().addWidget(self.w_edit)
# If we install the event filter and ignore() the ShortcutOverride
# then the shortcut works
self.w_edit.installEventFilter(self)
# Ctrl+Left is already in use (jump to previous word)
shortcut = QtGui.QShortcut(QtGui.QKeySequence('Ctrl+Left'), self)
shortcut.setContext(QtCore.Qt.ApplicationShortcut)
shortcut.activated.connect(self.test_slot)
def test_slot(self):
print('ctrl+left pressed!')
def eventFilter(self, obj, event):
if obj is self.w_edit and event.type() == QtCore.QEvent.ShortcutOverride:
# Send the event up the hierarchy
event.ignore()
# Stop obj from treating the event itself
return True
# Events which don't concern us get forwarded
return super(Test, self).eventFilter(obj, event)
widget = Test()
widget.show()
if __name__ == '__main__':
app.exec_()
My actual scenario is a tab widget for which I want to use Ctrl+Left/Right to cycle through the tabs, which works unless something like a QLineEdit has focus. I feel that there should be a better way other than calling event->ignore(); return true on all QLineEdits and any other widgets which could use the key combo, am I missing something here?
Thanks!
You can set one event filter on the application instance and then filter accordingly:
QtGui.qApp.installEventFilter(self)
# self.w_edit.installEventFilter(self)
...
def eventFilter(self, source, event):
if event.type() == QtCore.QEvent.ShortcutOverride:
# filter by source object, source.parent(), or whatever...
if isinstance(source, QtGui.QLineEdit):
event.ignore()
return True
return super(Test, self).eventFilter(source, event)

How to set a "read-only checkbox" in PySide/PyQt

I am trying to display the value of a Boolean variable using a QCheckBox widget, and render the user unable to change the displayed value. I don't want to disable it, as the resulting graying doesn't look good. I have tried to approximate the effect by changing the new value back to its previous value when the user clicks the QCheckBox. However, the problem is compounded by the fact that the state of the widget is described by the "checked" properties of the QAbstractButton parent class, and the "state" properties of the QCheckBox class itself. This gives rise to a combinatorial exercise of signals and slots, of which I have been unable to obtain any good result.
var_ctrl = QtGui.QCheckBox( 'some name' )
def rdslot1(state):
if state == QtCore.Qt.Checked:
var_ctrl.setCheckState( QtCore.Qt.Unchecked )
else:
var_ctrl.setCheckState( QtCore.Qt.Checked )
def rdslot2(state):
if var_ctrl.isChecked():
var_ctrl.setChecked(False)
else:
var_ctrl.setChecked(True)
# Signal/Slot combinations (only one should be active)
var_ctrl.stateChanged.connect( rdslot1 )
var_ctrl.toggled.connect( rdslot2 )
var_ctrl.stateChanged.connect( rdslot2 )
var_ctrl.toggled.connect( rdslot1 )
I'm late to the party - it seems like you got a solution that works. For future reference tho, another way you can do it would be to consume the mouse events - which keeps all of your signals working the way they should:
from PyQt4 import QtGui, QtCore
class MyCheckBox(QtGui.QCheckBox):
def __init__( self, *args ):
super(MyCheckBox, self).__init__(*args) # will fail if passing **kwargs
self._readOnly = False
def isReadOnly( self ):
return self._readOnly
def mousePressEvent( self, event ):
if ( self.isReadOnly() ):
event.accept()
else:
super(MyCheckBox, self).mousePressEvent(event)
def mouseMoveEvent( self, event ):
if ( self.isReadOnly() ):
event.accept()
else:
super(MyCheckBox, self).mouseMoveEvent(event)
def mouseReleaseEvent( self, event ):
if ( self.isReadOnly() ):
event.accept()
else:
super(MyCheckBox, self).mouseReleaseEvent(event)
# Handle event in which the widget has focus and the spacebar is pressed.
def keyPressEvent( self, event ):
if ( self.isReadOnly() ):
event.accept()
else:
super(MyCheckBox, self).keyPressEvent(event)
#QtCore.pyqtSlot(bool)
def setReadOnly( self, state ):
self._readOnly = state
readOnly = QtCore.pyqtProperty(bool, isReadOnly, setReadOnly)
Setting the code up this way gets you a few things (which you may or may not care about) but can be useful when developing custom Qt widgets:
Consuming the event blocks the signal emission, so you can still connect other slots to things like clicked & toggled. If you're looking for those signals and then just switching the value on/off - then other widgets listening for those signals will be triggered incorrectly
Using isReadOnly/setReadOnly keeps the class following the Qt coding style
Creating pyqtSignals & pyqtSlots will help if you expose the plugin to Qt's Designer
Well later on I came up with a shortcut, which simply catches the clicks of the user and handles them according to a specifiable 'Modifiable' property. I have made this class:
class MyQCheckBox(QtGui.QCheckBox):
def __init__(self, *args, **kwargs):
QtGui.QCheckBox.__init__(self, *args, **kwargs)
self.is_modifiable = True
self.clicked.connect( self.value_change_slot )
def value_change_slot(self):
if self.isChecked():
self.setChecked(self.is_modifiable)
else:
self.setChecked(not self.is_modifiable)
def setModifiable(self, flag):
self.is_modifiable = flag
def isModifiable(self):
return self.is_modifiable
It behaves just like a normal QCheckBox, being modifiable by default. However, when you call setModifiable(False), everytime you click it, it keeps the current state of the widget. The trick was to catch the clicked signal, not toggled neither stateChanged.
Try to disable the checkbox widget, but override its look using widget palette or style

Categories