I am trying to programmatically send key board presses. This works for the tab key and others, but for the space it does not.
Code looks like this for Tab and Space:
QKeyEvent *event = new QKeyEvent(QKeyEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier);
QCoreApplication::postEvent(this->viewer, event);
QKeyEvent *event = new QKeyEvent(QKeyEvent::KeyPress, Qt::Key_Space, Qt::NoModifier);
QCoreApplication::postEvent(this->viewer, event);
When I do the tab press programmatically it changes between buttons, but when I programmatically press space it does not press the button (it get greyed as it was pressed, but the screen does not change as it should). When i do press space on my keyboard the button gets pressed and the screen changes.
Any idea why the behavior is not the same?
The solution here was to send KeyRelease event after sending KeyPress event. As shown here:
QKeyEvent *event = new QKeyEvent(QKeyEvent::KeyPress, Qt::Key_Space, Qt::NoModifier);
QCoreApplication::postEvent(this->viewer, event);
QKeyEvent *event = new QKeyEvent(QKeyEvent::KeyRelease, Qt::Key_Space, Qt::NoModifier);
QCoreApplication::postEvent(this->viewer, event);
Related
I am building a Qt Application for a raspberry pi, which is connected to a rotary encoder. When the user presses the rotary encoder button, the application registers the hardware interrupt from the button and emits a signal which the application can intercept.
The challenge is that the application has multiple windows that can be displayed, and I would like to simply have a function which translates the button press signal into a global key press that can be registered by any active window in the application, without having to add extra logic to determine which window is active to send the key press directly to it. Is there a way to simulate a system-wide key press so that whatever window is in focus will get it?
So far, I have the following snippet of code, though it requires a reference to a specific QObject to direct the keypress to:
QKeyEvent *event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Enter);
QCoreApplication::postEvent (receiver, event);
where receiver is the object to direct the keypress too. Any ideas?
To broadcast a key event to all top-level widgets (i.e. windows):
for(auto w : qApp->allWidgets())
{
if(w->isTopLevel())
{
qApp->postEvent(w, new QKeyEvent(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier));
}
}
To directly send the event to the active window (the foremost one):
qApp->postEvent(qApp->activeWindow(), new QKeyEvent(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier));
I have a QAction in QMenu. When QAction is triggered() I would like to know which button did it.
connect(YourAction, SIGNAL(triggered()), this, SLOT(actionclicked()));
void MainWindow::actionclicked(QMouseEvent *e)
{
if (e->buttons() == Qt::RightButton)
}
I can't do something like this because triggered() does not have such argument.
As #mvidelgauz noticed, QAction is abstracted from input devices which may triggered the action. Nevertheless, if the action is used in your GUI, it has one or more associated widgets: tool buttons in a toolbar, entries in menu bar and so on. These widgets act like any other widgets, so they receive events which may be filtered with the use of installEventFilter and eventFilter. These two methods are inherited from QObject, so they are present in almost any Qt class. For example, let's create an application with QMainWindow and QAction called actionTest. Then let's turn the main window itself into an action filter for actionTest's associated widgets by overriding main window's eventFilter method:
bool eventFilter(QObject *obj, QEvent *ev) {
//Catch only mouse press events.
if(ev->type() == QEvent::MouseButtonPress) {
// Cast general event to mouse event.
QMouseEvent *mev = static_cast<QMouseEvent*>(ev);
// Show which button was clicked.
if(mev->button() == Qt::LeftButton) {
qDebug() << "Left button!";
}
if(mev->button() == Qt::RightButton) {
qDebug() << "Right button!";
}
}
// In this example we just showed the clicked button. Pass the event
// for further processing to make QAction slots work.
return QMainWindow::eventFilter(obj, ev);
}
Then we need to install event filter object for all watched objects, which are widgets in our case. Let's do it in main window constructor:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
for(auto wgtPtr : ui->actionTest->associatedWidgets()) {
wgtPtr->installEventFilter(this);
}
}
Finally, add a slot for triggered() signal handling:
void on_actionTest_triggered() {
qDebug() << "Action triggered!";
}
Now if you click the action menu entry with left mouse button, it will print
Left button!
Action triggered!
while for right mouse button the result will be
Right button!
Action triggered!
Note that widget event filtering is always performed before triggered() signal emission.
The above code is just an example, and MainWindow class is not the best place to host eventFilter method. In real code you may either:
Create dedicated QObject subclass(es) for QAction widgets event filtering.
Subclass QAction and override it's eventFilter method. In this case you may just save the result of QMouseEvent::button() in the QAction subclass object and later use it in triggered() signal handler. There is a minor inconvenience that Qt creator (at least up to v3.2.1) does not allow you to "promote" QActions in it's form designer, so you'll need to add actions to menus manually in window constructor.
Subclass QMenu, QToolBar, etc.., and make them action filters? I don't know how can it be better than two former variants.
See also documentation about Qt event system.
Let's clarify case 2. Assume the class inherited from QAction is called MyAction. In order to make it work you need to install MyAction objects as filters for themselves (their widgets, to be more specific). You need to do it after widgets were created, so installing filter in MyAction constructor may be premature and lead to crashes. Better place for filter installation is a constructor of a class which owns MyAction object. Typically it's a widget or window class. So just add
for(auto wgtPtr : ui->myActionObject->associatedWidgets()) {
wgtPtr->installEventFilter(ui->myActionObject);
}
to your window constructor after ui->setupUi(this) call. This code is like in the above example, but we use ui->myActionObject instead of this object as filter.
triggered() cannot have this argument by design because it by itself is not necessarily result of a mouse event:
This signal is emitted when an action is activated by the user; for example, when the user clicks a menu option, toolbar button, or presses an action's shortcut key combination, or when trigger() was called
You need to connect to mouse events if you need QMouseEvent as parameter. In fact Qt itself emits triggered() when (but not only as I highlighted in doc quote) framework receives mouse event from menu. So it looks like you'll need to do a similar thing in your code and add your own logic.
P.S. This discussion might be interesting for you
When a QPushButton is clicked, I want it to remain pressed down until clicked again.
void MainWindow::itemClicked(){
QPushButton *clickedItem = qobject_cast<QPushButton *>(sender());
qDebug() << clickedItem->isDown();
if(!clickedItem->isDown())
clickedItem->setDown(true);
else
clickedItem->setDown(false);
}
This doesn't seem to work. It will cause the button to be pressed down indefinitely.
clickedItem->isDown() is always false.
isDown always returns false because you are checking it in a slot connected to the clicked signal. The clicked signal is emited when you press down the push button and release it. So every time the button is pressed and released the clicked signal is emited.
setCheckable() would work for you. It will make the button toggle. So when youu click, it'll stay in down state until you click it again.
It should work out of the box using QAbstractButton::setCheckable(bool).
When set to true it should act the way you want it to act.
In my program, I want to replicate the user pressing a key on the keyboard and mouse clicks.
Think about it like an auto-typer where the program types something in a word document over and over at various delays.
Any ideas on how to do this?
Thanks for your time.
I would suggest QTest namespace key and mouse simulation functions, e.g.
QTest::keyClick()
QTest::mouseClick()
You'll find documentation here
For simulating key presses you can use the QKeyEvent class which describes a key event and post that using QCoreApplication::postEvent.
QKeyEvent *event = new QKeyEvent ( QEvent::KeyPress, Qt::Key_Enter);
qApp->postEvent (receiver, event)
You can set the global position of the mouse by
QCursor::setPos(100,100);
Simulating the mouse events are like:
QMouseEvent * event = new QMouseEvent ((QEvent::MouseButtonPress), QPoint(500,500),
Qt::LeftButton,
Qt::LeftButton,
Qt::NoModifier );
qApp->postEvent((QObject*)this,(QEvent *)event);
Look at my answer in the next topic. Answer has a link to OS depended implementation of Keyboard / Mouse event generation. It can be helpful for you.
When you get get a mouse signal from a model into your slot, the argument passed is a QModelIndex.
QModelIndex does not tell you what button is pressed. So, we can resort to QApplication::mouseButtons. But QApplication::mouseButtons is the current button press, not when model experienced the click.
My thought experiment is saying that, after the right-button is pressed, the underlying view sends the signal to my widget, but just before my widget's slot received the signal, a spurious left-click occurred. So calling QApplication::mouseButtons on receipt of QModelIndex would wrongly associate the row being click with the left mouse button rather than the right button. How possible is this scenario?
When you look at Qt and even QML, it takes a lot of code acrobatics to achieve proper mouse button info on receipt of a QModelIndex. Is it a policy that nokia is striving to promote mouse button agnosticism?
I don't think this is a very possible scenario but it may happen.
A "simple" way to be sure about which button was clicked is to subclass QTableView (or the view you are using and reimplement the mouseReleaseEvent.
void mouseReleaseEvent(QMouseEvent * event)
{
// store the button that was clicked
mButton = event->button();
// Now call the parent's event
QTableView::mouseReleaseEvent(event);
}
By default the mouseReleaseEvent emits the clicked signal if an item of the view is pressed
If a user presses the mouse inside your widget and then drags the
mouse to another location before releasing the mouse button, your
widget receives the release event. The function will emit the
clicked() signal if an item was being pressed.
The trick is to catch the clicked signal in your derived class and emit a new signal which except the model index will contain the button as well.
// Define your new signal in the header
signals:
void clicked(QModelIndex, Qt::MouseButton);
// and a slot that will emit it
private slots:
void clickedSlot(QModelIndex);
// In the constructor of your derived class connect the default clicked with a slot
connect(this, SIGNAL(clicked(QModelIndex), this, SLOT(clickedSlot(QModelIndex)));
// Now the slot just emits the new clicked signal with the button that was pressed
void clickedSlot(QModelIndex i)
{
emit clicked(i, mButton);
}
You can do something similar with the mousePressEvent if you need the pressed signal as well.