QDialog: how to use question mark (?) button? - qt

By default, QDialog windows have a question mark pushbutton in the upper-right corner. When I press it, the mouse cursor is changed to the 'Forbidden' cursor, and nothing else seems to happen.
While there is lots of information generated from those who want to remove the question mark (at least three SO threads are devoted to the topic), the documentation for QDialog doesn't have anything about how to actually use it.
How do I get my application to display information when the question mark is clicked? E.g., how do I get the clicked signal from the button? Better yet, where is this button documented?

The other answers were a bit misleading for me, focusing only on catching the question mark event, but not explaining the normal usage.
When this button is clicked and WhatsThisMode is triggered, the elements of the dialog are supposed to give info about themselves. And if mouse hovers over an element that supports this info then the pointer will become a pointing arrow with a question mark (on Windows at least), with a tooltip message displayed on mouse click.
Here's how to achieve it in PySide:
someWidget.setWhatsThis("Help on widget")
QWhatsThis documentation for PySide and Qt5 is also available.

It is not a button documented by Qt. You can detect this by catching events and checking event type:
http://qt-project.org/doc/qt-5/qevent.html#Type-enum
There are different types as QEvent::EnterWhatsThisMode QEvent::WhatsThisClicked and so on. I achieved something similar to what are you looking for using event filter in mainwindow.
if(event->type() == QEvent::EnterWhatsThisMode)
qDebug() << "click";
I saw "click" when I clicked on ? button.

Based on Chernobyl's answer, this is how I did it in Python (PySide):
def event(self, event):
if event.type() == QtCore.QEvent.EnterWhatsThisMode:
print "click"
return True
return QtGui.QDialog.event(self, event)
That is, you reimplement event when app enters 'WhatsThisMode'. Otherwise, pass along control back to the base class.
It almost works. The only wrinkle is that the mouse cursor is still turned into the 'Forbidden' shape. Based on another post, I got rid of that by adding:
QtGui.QWhatsThis.leaveWhatsThisMode()
As the line right before the print command in the previous.

Related

Tkinter Leave event firing only on program startup?

I'm trying to place a small label hinting the user the keyboard shortcut bound to it, which works fine.
The problem arises when I'm leaving the button. The label disappears, but not quite. If I try to click the button in the area the label "used" to be, it won't fire, indicating that's it's somehow still there. So I thought maybe buttons have a Leave event already built in that raises them to the top level. I decided to try and override that, and basically tell the button go (or better yet, just stay) below the key-hint label hit_button.bind("<Leave>", hit_button.lower(hit_button_keyhint), to no avail. What am I doing wrong?
fg=hit_button['fg'])
hit_button_keyhint.place(relx=0.5, rely=0.85, anchor='center')
hit_button.bind("<Leave>", hit_button.lower(hit_button_keyhint))
You need to pass a function to the binding, Here you execute a function. (hit_button.lower(hit_button_keyhint))
To do so, you should use a lambda.
You can get some clarifications here:
Tkinter binding a function with arguments to a widget
But this should work:
hit_button.bind("<Leave>",lambda event, k=hit_button_keyhint:hit_button.lower(k)

How to intercept / modify excape key functionality in Qt

I am trying to fix a bug in a Qt app which I did not write. The window changes the background color of the entire window to red and puts up some buttons, dialog boxes, etc. When the escape key is pushed, the boxes and buttons go away, leaving an empty red screen. The Cancel button does the right thing in returning to the previous window. I think I need to somehow be notified of when the escape key is pushed, and then call the same function as the cancel pushbutton does. Hopefully, I can limit the scope of this special action to when the problem window is up. I am an experienced programmer but a complete Qt newbie. This app is purely C++. To my knowledge, it does not appear to use any QML. I am still searching through the Qt online documentation, but any suggestions / examples are appreciated.
This depends a lot on your specific Qt version and setup of your application. That said, I'll take a shot at helping. In the class where you're trying to intercept the escape key press, assuming it's inheriting QObject, simply override the virtual function eventFilter. Inside your overridden instance of eventFilter, check that the QEvent type is a QEvent::KeyPress, and then check whether the key of that KeyPress is the escape key, and handle as needed.
Be sure that you pass the event out of your function, else you'll see your overridden function eat all events. If you explicitly want the event to be "eaten", simply do not return it from your function. For specifics and examples, check out documentation of QObject::eventFilter().

How to stop a middle mouse click from deselecting items in a QGraphicsScene without blocking it from items in the scene?

I am creating a node graph and I want to be able to click the empty space in a scene and middle-mouse-drag to navigate without deselecting the currently selected items in the scene. Any suggestions?
I can block the middle click in the view's mousePressEvent and get the right behavior but then I no longer have middle-mouse click events working on items in the scene. I don't mind a middle-click resulting in a single selection when clicking on an item in the scene, but if I middle-click the empty space in the scene I don't want the selection altered.
This didn't cover the more complex behavior I am looking for: PyQt. How to block clear selection on mouse right click?
I didn't try using an eventFilter as I assume the issue would be the same
I am using PyQt/PySide, FWIW.
Before I roll my own workaround I thought I'd post here for the correct way or at least other workaround ideas.
Some workaround ideas:
Block the mousePressEvent to the scene but iterate over child items to deliver it directly
Restore selection while still in the mousePressEvent in the scene. Probably bad for performance at scale but simple I suppose.
Any feedback would be great!
[Edit:]
Here is my python version of the answer. Code tested. In my QGraphicsScene derived class:
def mousePressEvent(self, event):
# Prevent the QGraphicsScene default behavior to deselect-all when clicking on
# empty space by blocking the event in this circumstance.
item_under_the_mouse = self.itemAt(event.scenePos())
if event.button() == QtCore.Qt.MidButton and not item_under_the_mouse:
event.accept()
else:
super(GraphScene, self).mousePressEvent(event)
In your QGraphicsScene::mousePressEvent derived implementation, if it's a middle mouse click, check for items under the mouse click. If there aren't any, then accept the event and don't call the base class implementation. If something is under the click, then just call the base implementation; you don't have to try to reimplement that yourself. I think this is the general idea:
void MyScene::mousePressEvent (QGraphicsSceneMouseEvent *evt)
{
if ((evt->buttons () & Qt::MidButton) && items (evt->scenePos ().count ())
{
QGraphicsScene::mousePressEvent (evt);
}
else
{
evt->accept ();
}
}
I'm not sure if the accept is required in this case or not. I haven't compiled or tested this, but hopefully, it's helpful to get you going in the right direction.

Qt : keyboard focus

I am writing a program in Qt that looks like this:
The main window is my class Window : QWidget, it has a QGridLayout containing four other widgets (Input_Menu : QWidget and Output_Menu : QWidget, and then two Canvas : QWidget)
I would like to trigger certain events when the user strikes a key. The problem is, the Window sometimes loses focus (it goes, say to Input_Menu, or maybe a button in Input_Menu...)
I have tried the following solutions, but they seem unsatisfactory (and dirty):
Give Window the focus whenever it loses it.
Tell each widget who could have the focus to trigger Window's KeyPressEvent function (or a clone of it) whenever it receives a keyboard event.
Ideally, I would like that if a widget receives an event (say a keyboard event) and doesn't know what to do with it, it should automatically call its parent's event handler. I would have hoped this to be a default feature of Qt but it doesn't look like it. On the other hand I am really confused about the whole focus thing, I don't really get what's going on. Can someone explain this to me: I have included a std::cout << "key pressed" << std::endl; in my Window::KeyPressEvent function. When I first run my program, it seems the focus is on the top QComboBox in Input_Menu: if I hit the Up/Down keys, I navigate in that box and no "key pressed" is showed in my console. If I hit most letters, nothing happens. But if I hit Left/Right keys, I do get a "key pressed" in my console!?
Thanks a lot in advance for your insights.
You can install an event filter on QApplication to filter the relevant QEvent::KeyPress events globally. From the Qt documentation:
It is also possible to filter all events for the entire application,
by installing an event filter on the QApplication or QCoreApplication
object. Such global event filters are called before the
object-specific filters. This is very powerful, but it also slows down
event delivery of every single event in the entire application; the
other techniques discussed should generally be used instead.
Besides the performance considerations, remember to check if your window currently has the focus before you filter the key event, or you might break popup dialogs or input into other windows.
Actually, I found that for keys that are modifiers (such as Shift, Control), Qt supports finding out whether they are pressed.
Eg : if(QApplication::keyboardModifiers() == Qt::ShiftModifier) ...
This is good enough.

How to remove focus from a QLineEdit when anyplace else on the window is clicked

I'm working on a custom Qt button that allows you to edit the text on the button if you double click it. When the button is double clicked, a QLineEdit appears where the text on the button is allowing the user to edit the text on the button. My requirement is that if the user clicks anywhere in the application window, the QLineEdit should disappear and cancel the edit operation. This works in some cases. Specifically, it works if I click on anything that is capable of text entry. Other portions of the window don't work as expected. I'll click on a blank portion of the application window, and the QLineEdit retains its focus. How can I remove its focus in these cases?
I've found a solution that seems to work, though I'm still open to other options if there are any. I'm using PyQt4, so my example is in python:
Create a subclass of QLineEdit just so I have a new type. I don't want or need this behavior on all QLineEdit instances; just these specific ones.
class MyLineEdit(QtGui.QLineEdit):
pass
Now, in my QMainWindow subclass, I override the mousePressEvent() implementation. It gets the currently focused widget. If that widget is of type MyLineEdit, clear the focus.
class MyMainWindow(QtGui.QMainWindow):
def ...
def mousePressEvent(self, event):
focused_widget = QtGui.QApplication.focusWidget()
if isinstance(focused_widget, MyLineEdit):
focused_widget.clearFocus()
QtGui.QMainWindow.mousePressEvent(self, event)
def ...
This gets me the behavior I'm looking for so that if the user clicks anywhere on the application's window, the focus is cleared.
Edit: I did find one caveat to this. I have a QTreeView in the main window. If the user clicks on the tree view, focus is not removed from the text edit field.
Catch the clicked() signal of your parent widget and call yourLabel->clearFocus() (that unfortunatelly happens to not be a slot, making things more complicated) there.
I followed Grant Limberg instruction here but figured out that, in my case, a simple:
QApplication.focusWidget().clearFocus()
would fix the problem.
I'm not sure if this also works in Qt4 (I'm using PyQt5) but you can change the FocusPolicy of the QMainWindow or parent widget to clear the focus in the QLineEdit. As per https://doc.qt.io/qt-5/qwidget.html#focusPolicy-prop
I've changed the policy of my QMainWindow to Qt.StrongFocus and it worked like the functionality described in the question.
If done in C++ I would do something along the lines of:
connect(myWidgets->MyLineEdit, SIGNAL(returnPressed()), this, SLOT(onLineEditDone());
void onLineEditDone()
{
myWidgets->MyLineEdit->clearFocus();
}
For this particular case I would use editingFinished() instead of returnPressed(), probably, but I would NOT use textChanged(QString).

Resources