Qt disable QShortcut to pushbutton when button is disabled - qt

I'm a beginner to QT. I have used QShortcuts to bind keys to pushbuttons.
QShortcut *sb_0 = new QShortcut(QKeySequence(Qt::Key_0), this);
connect(sb_0, SIGNAL(activated()), ui.b_0, SIGNAL(clicked()));
However, when when b_0 is disabled, the shortcut still works.
ui.b_0->setEnabled(FALSE);
I would like, somehow, that the shortcut be disabled when I disable the pushbutton. I am thinking that I could disconnect the QShortcut from the QPushbutton; however, this doesn't seem like it would be the best idea.
Also, I'm wondering if it'd be possible to have it so that when the key '0' is pressed, the button goes down (gets pushed down), and then when it is released, the button goes back to normal. So basically, pushing '0' is like holiding down left-click on b_0.
If this has already been answered (I couldn't find an answer to this), please let me know.
Thank you.

Why don't you just call setShortcut on the QPushButton?
void setShortcut ( const QKeySequence & key )
This is provided on the QAbstractButton class, so it might not be the most obvious thing to find in the documentation.
ui.b_0->setShortcut(QKeySequence(Qt::Key_0));
That should do the trick. The button already handles what should happen if the button is not enabled.

Related

How to keep a pushButton of Qt be down after I click it?

I would like to implement a group of pushButtons like painting tool chose in Adobe Ps:
only one button can be checked at any time
keep button be down after I click it
I have used setAutoExclusive(true) to meet the first requirement. So the next step is to deal with the second... Please give me some advice or suggestion?
QPushbutton button;
button->setCheckable(true);
or just click on the "Checkable" check box in designer
Like suggested by another answer, you can create a QPushButton by e.g.
button = new QPushButton("Button text", this);
and then make it checkable with
button->setCheckable(true);
For this to have a visual effect, you need a section in your stylesheet (.qss) for
QPushButton:checked. If you have a section for QPushButton:pressed, you can just add it there, i.e. change
QPushButton:pressed {
to
QPushButton:pressed,
QPushButton:checked {
If you don't, the styling you need depend on the appearance of the button in its pressed state, which in turn depends on your operating system, so you have some guesswork to do.

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

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.

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.

QAction Qt::Key_Return shortcut is triggered by user entering values in GUI

I have an issue with associating a keypress to a QAction. I'm mapping Enter to an action like this:
myAction->setShortcut(Qt::Key_Return);
The problem is that the QAction is also triggered when I type a value in a QSpinBox and then press Enter. I was expecting the spinbox to consume the event (so it's not caught by the mainwindow) but it's not working like that.
I've seen that I can add a context to my shortcut, I tried all values but this does not solve my issue.
#Matthew It is indeed rejecting the event:
case Qt::Key_Enter:
case Qt::Key_Return:
d->edit->d_func()->control->clearUndo();
d->interpret(d->keyboardTracking ? AlwaysEmit : EmitIfChanged);
selectAll();
event->ignore();
emit editingFinished();
return;
I find this behavior quite strange.
From my knowledge the QSpinBox default behavior does wait until you press return to accept the value. Technically the value is set/accepted as soon as you change it.
If you're looking to change that behaviour, i.e. when you hit return on your QSpinBox you the value is actually set/accepted, then you will most likely have to handle the associated key press event yourself on the QSpinBox and mark it as accepted (i.e. event->accepted() ).
Otherwise, this sounds like it is working as originally designed although not as you want.
I have exactly the same problem, only in PyQt and with QLineEdit
It may be that QActions are always considered menu actions, or global, and have a higher priority than Widget Default keys.
My "solution" was to create a global list of my actions with important keys (Return, Tab, Backspace etc.) as shortcuts.
Then I hook into QLineEdit focusInEvent and focusOutEvent. Each time the event happens I loop over the actions-list and deactivate them all on focusIn and activate them again on focusOut. Then I give the event to the original focus event handlers.
I really hope there is a better solution.

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