How can I move the keyboard cursor/focus to a QLineEdit? - qt

I am opening a QDialog which contains a QLineEdit. I want the QLineEdit to have keyboard focus initially, with the blinking cursor as a visual cue. Simple, right?
Calling line_edit->setFocus() has no effect.
Calling line_edit->grabKeyboard() gives it input focus BUT
the blinking caret doesn't move to line_edit
if I click into a different QLineEdit, the blinking caret goes there but keypresses are still delivered to line_edit
If I do neither, I have to click into line_edit to get the caret and input focus. Looking at the source code for QLineEdit::mousePressEvent it seems that the critical function is QWidgetLineControl::moveCursor, but that's not accessible via the public API and peeking further into the source doesn't show anything promising.
So how do I move the damn keyboard input cursor?

How do I set the keyboard input cursor to QLineEdit widget?
From one of replies to this thread: Set QLineEdit focus in Qt.
QTimer::singleShot(0, line_edit, SLOT(setFocus()));
Before I found that elegant way to set focus I developed my own:
void forceFocus(QWidget* widget)
{
// unless set active, no stable set focus here
widget->activateWindow();
// the event object is released then in event loop (?)
QFocusEvent* eventFocus = new QFocusEvent(QEvent::FocusIn);
// posting event for forcing the focus with low priority
qApp->postEvent(widget, (QEvent *)eventFocus, Qt::LowEventPriority);
}

The accepted answer did not work for me. The qApp->focusWidget() is correctly updated, but the caret does not appear. I tried a great deal many variations on things like grabKeyboard(), setReadOnly(), setCursorPosition(), activateWindow(), cursorBackward(), cursorForward(), cursorFlashTime() and so on, but to no avail. They revealed that the cursor was in the right place, just not being drawn.
Not sure how my scenario differs to the OP. Like in Activate cursor in QTextEdit I'm calling setFocus() after responding to another button press but otherwise pretty standard.
Finally, using the clues in the OP, this sledgehammer approach got me there:
QPoint pos(line_edit->width()-5, 5);
QMouseEvent e(QEvent::MouseButtonPress, pos, Qt::LeftButton, Qt::LeftButton, 0);
qApp->sendEvent(line_edit, &e);
QMouseEvent f(QEvent::MouseButtonRelease, pos, Qt::LeftButton, Qt::LeftButton, 0);
qApp->sendEvent(line_edit, &f);

Related

Is there a way to configure popup menu delay for a QToolButton with popupMode == DelayedPopup?

I'm creating an app with a history like in a web browser: back and forward buttons with a popup menu which is showed on press and hold. The DelayedPopup mode was created exactly for my scenario and it kind of works.
The problem is that the delay used to detect a hold is too short. While I have no trouble with back-forward buttons in, say, Google Chrome, in my app popup menus are popping up regulary when I intend just a simple click.
I suppose setting the delay to a larger value will solve the issue but I can't find a way to do this. The doc says
The default delay is 600 ms; you can adjust it with setPopupDelay()
but it's clearly wrong or outdated info because there is no setPopupDelay in sight.
Any suggestions?
Upd: Though increased delay considerably helped the popup menu still gets shown from time to time. I think there is a bug in Qt.
setPopupDelay was used by Qt 3. Now you have to create your own style by subclassing QStyle or one of its subclasses, and re-implementing the QStyle::styleHint method.
int MyStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const
{
if (hint == QStyle::SH_ToolButton_PopupDelay)
return 1200;
return QStyle::styleHint(hint, option, widget, returnData);
}

Why does my QGraphicsWidget receive events it shouldn't after QDrag?

I have a simple QGraphicsWidget, MyGraphicsWidget. Here's my mouseMoveEvent(), which seems to work fine :
void MyGraphicsWidget::mouseMoveEvent (QGraphicsSceneMouseEvent *event)
{
QPointF p = event->scenePos() - m_StartPos;
if(p.manhattanLength() < 20)
return;
//omitted drawing a rounded rect on the drag
QDrag *drag = new QDrag(event->widget());
drag->start(Qt::MoveAction);
}
The scene's dropEvent() just moves this widget to its new position, and I don't have a press/move event for the scene itself, so those should get passed on correctly to the widgets within.
However, once the drag completes, the next mouse press will be on this widget. So if I try to click and drag another widget, I'll be stuck dragging this one on accident, despite the fact that my cursor is not on this widget. I've printed out the event->pos() and event->scenePos(), and both reported that the cursor is where it appears to be (not on the widget at all). If I click once before trying to click and drag, everything works normally. Is there maybe something I need to implement within mouseReleaseEvent() or my mouseMoveEvent() ?
Thanks.
It's working now. I'm pretty sure this was the issue:
MyGraphicsWidget had another custom GraphicsWidget sitting on top of it, and in its mousePressEvent, I was calling QGraphicsWidget::mousePressEvent(event); at the start of the event. The rest of the event was never getting triggered, which was messing it all up. I moved that line to the end of the method, and everything seems okay now.

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 show pixel position and color from a QGraphicsPixmapItem

I'm developing a custom widget with QGraphicsScene/View and I have no prior experience with it.
The custom widget is an image viewer that needs to track mouse movement and send signal(s) to it's parent dialog / window. The signal(s) will be the position of the pixel under the mouse cursor and it's color (in RGB). A status bar will use that information.
I use a QGraphicsPixmapItem to display the image I load from a file in the scene.
Thanks.
First of all you have to implement the mouseMoveEvent in your custom item. In this function you can easily get the mouse position calling the pos function. You can get the rgb value if you transform the item's pixmap into image and call the pixel function. You should consider storing the QImage as member variable in order to avoid multiple transformations. Finally you have to emit a custom signal. Sample code follows:
void MyPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent * event)
{
QPointF mousePosition = event->pos();
QRgb rgbValue = pixmap().toImage().pixel(mousePosition.x(), mousePostion.y());
emit currentPositionRgbChanged(mousePosition, rgbValue);
}
Notice that QGraphicsItems do not inherit from QObject so by default signals/slots are not supported. You should inherit from QObject as well. This is what QGraphicsObject does. Last but not least I would advise you to enable mouse tracking on your QGraphicsView
I found the mouseMoveEvent approach to not work at all, at least not with Qt5.5. However, enabling hover events with setAcceptHoverEvents(true) on the item and reimplementing hoverMoveEvent(QGraphicsSceneHoverEvent * event) worked like a charm.
The Qt docs on mouseMoveEvent() provide the clue:
"If you do receive this event, you can be certain that this item also received a mouse press event"
http://doc.qt.io/qt-5.5/qgraphicsitem.html#mouseMoveEvent

Qt disable QShortcut to pushbutton when button is disabled

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.

Resources