PDA

View Full Version : Detecting a mouse press or click on QLineEdit set to Nofocus or .setReadOnly



dennisvz
19th August 2020, 21:41
Is it possible to detect a mouse press or mouse click on a QLineEdit that has been set to either .NoFocus or .setReadOnly, and then call a function to do something? If so, how?

Ginsengelf
20th August 2020, 07:26
Hi, you could try an event filter:
https://doc.qt.io/qt-5/qobject.html#installEventFilter
but I'm not sure if an object with NoFocus will receive any events.

What do you want to do?

Ginsengelf

dennisvz
25th August 2020, 15:09
Sorry for the delay -- went out of town.

I set several QLineEdits to .setReadOnly when I do not want the user to input any data. However, I wanted to remind the user why they cannot enter any data. I used a tooltip to accomplish what I want, but the best thing is to show a QMessageBox (or something like that) when the user "clicks" the LiineEdit to enter data (a tooltip does not show when clicking the line edit). I read about the event filters, but am such a newbie that I could not set it up to test. Could you help? Here is what I tried, but of course, it does not work:

in my init:


self.mousePressEvent = QtCore.QEvent.MouseButtonPress
self.ui.BTE.installEventFilter(self.ui.BTE)
self.ui.BTE.mousePressEvent(QMouseEvent=)


in a function:


def eventFilter(self, source, event):
if self.BTE.isReadOnly:
if event.type() == QtCore.QEvent.MouseButtonPress and source is self.ui.BTE:
message = 'Test'
self.blueboxmessage(message)
else:
return

thanks for looking

d_stranz
25th August 2020, 17:53
self.ui.BTE.mousePressEvent(QMouseEvent=)


If you are trying to fire a mouse event to test your code, this is not the way to do it. You need to post an actual event to the Qt event loop so it can be processed and eventually sent to your event filter. See QCoreApplication::postEvent() or QCoreApplication::sendEvent() for the details. I do not know for sure whether sendEvent() will activate your event filter or not, so you would have to test that. If it doesn't work, then you'll have to use postEvent() instead.

In C++, an eventFIlter() method must return a Boolean true or false to determine whether the event handling stops (true - the event filter "eats" the event) or continues (false - to be also handled by the object it is intended for). If you are not interested in the event at all, then you have to call the superclass eventFilter() method and return its true / false return value. If you don't follow these rules, then your line edit might fail to work at all.

See the documentation for QObject::eventFilter() which shows how to correctly implement eventFilter() in a MainWindow class.

If I were doing this, I would not use a dialog-based class to show the message. I would create a QToolTip instance as a member of your class, call QToolTip::showText() in the mouse pressed event, and call QToolTip::hideText() in both the mouse release and leave events for your line edit. You could also start a QTimer when you show the tooltip, and hide the tooltip when the timeout event fires.

Doing it with a QDialog means the user has to click somewhere else to dismiss the dialog, and it removes the focus from the line edit in the process. I guarantee this will lead to more UI problems.

dennisvz
27th August 2020, 21:12
Trying to implement what you suggested in last paragraph:
in init:


self.ui.BTFE.installEventFilter(self)



def eventFilter(self, source, event):
if event.type() == QtCore.QEvent.MouseButtonPress and source.isReadOnly:
self.ui.BTFE.setToolTip('Cannot enter data here')
QTimer.singleShot(5000, self.remove_tooltip)
return super(UIMainWindow, self).eventFilter(source, event)

def remove_tooltip(self):
self.ui.BTFE.setToolTip('')


I cannot figure out the pyqt code for "showing" and 'hiding" the tooltip -- I only know how to code .setTooltip, but that does not show the tip when the line edit is clicked -- only when hover. Plus, not sure if QTimer will do what I want. Ultimately, I'll have nine line edits that I need to test, all with the same tool tip. thanks

d_stranz
27th August 2020, 21:50
I am not a Qt Python expert, but I think you need something like this:



def eventFilter(self, source, event):
if event.type() == QtCore.QEvent.MouseButtonPress and source.isReadOnly:
QTimer.singleShot(5000, self.remove_tooltip)
QtWidgets.QTooltiip.showText( source.pos(), 'Cannot enter data here')
return super(UIMainWindow, self).eventFilter(source, event)

def remove_tooltip(self):
QtWidgets.QTooltiip.hideText()


In the eventFilter() "source" is the QWidget instance that is the focus of the event, so it -is- "self.ui.BTFE" in this case, since that's where you have installed the filter. So in the event filter code, you can simply replace "self.ui.BTFE" with "source" and it will work for all of your line edits.

I do not know for sure if QTooltip::showText() is a blocking method (ie, it suspends the rest of the code until it is hidden again), so I switched the order of starting the timer and showing the tip just to make sure the timer is running first.

You also need to check to see if you can TAB into a read-only QLineEdit, and if so, you will probably wnat to display the tooltip for an enter event as well.

dennisvz
27th August 2020, 22:52
My PyCharm IDE is telling me it does not recognize QtWidgets, even though I have this import:


from PyQt5.QtWidgets import QMainWindow, QMenu, QLineEdit, QComboBox, QFileDialog, QMessageBox, QPushButton, QToolTip, QWidget


I then added: (below import above):


from PyQt5 import QtWidgets


That import got rid of the 'not recognized' issue, and no errors when run. I changed the event to MouseButtonRelease so the message would show for the 5 seconds. However, 1) the tooltip shows well away from the line edit. Is the source.pos() supposed to make the tooltip show next to the line edit that was clicked?
thanks for your response

Ginsengelf
28th August 2020, 07:08
Hi, pos() returns the position in widget coordinates. I think globalPos() is what you need.

Ginsengelf

dennisvz
28th August 2020, 12:04
QtWidgets.QToolTip.showText(source.globalPos(), 'Cannot enter data here')


gives an AttributeError: 'QLineEdit' object has no attribute 'globalPos'

d_stranz
28th August 2020, 15:55
gives an AttributeError: 'QLineEdit' object has no attribute 'globalPos'

So you fire up your browser, type "Qt globalpos" into the Google search box, and what do you think you get as the first hit? Certainly faster than asking questions here and waiting for someone to answer.

And since you already imported QTooltip from QtWidgets, you can probably remove the QtWidgets part of QtWidgets.QTooltip.showText and just use QTooltip.showText. I said I wasn't a Python expert. Also get rid of the separate import of all of QtWidgets. It just bogs things down at runtime.