I am happily using QTestLib to write tests for my Qt5 widgets based UI. There has seemed to be no shortage of features and convenience functionality until now, when I tried to find a way to simulate mouse wheel events.
I have looked at the official documentation, and an official example but I can't seem to figure out how to go about simulating mouse wheel events.
Does this not exist? Or am I missing something? How should I create dummy mouse wheel events using QTestLib?
It has been 10 years, and I thought it would be a nice way to mark the occasion by formally submitting a feature request on the bug-tracker for Qt:
Behold QTBUG-71449.
For anyone stumbling into this problem 10 years from now on. We wrote an implementation for our testing suite for Qt4.8 (also tested in Qt5.6, as always no guarantees):
void TestUtility::mouseWheelTurn(
QWidget *widget, // The most top level widget; a MainWindow in our case
int delta, // As in QWheelEvent
QPoint pos, // Mouseposition in the moment of scrolling relative to top level widget
Qt::MouseButtons buttons, // As in QWheelEvent
Qt::KeyboardModifiers modifiers, // As in QWheelEvent
Qt::Orientation orientation, // As in QWheelEvent
int delay) // As in other QTest functions
{
QWidget *toWheelChild = widget->childAt(pos);
if(toWheelChild == NULL) return;
pos = widget->mapToGlobal(pos);
pos = toWheelChild->mapFromGlobal(pos);
QTest::mouseMove(toWheelChild, pos);
QTest::qWait(delay);
QWheelEvent *wheelEvent =
new QWheelEvent(pos, delta, buttons, modifiers, orientation);
QApplication::instance()->postEvent(toWheelChild, wheelEvent);
}
Related
In QML you can use Animator type to "animate on the scene graph's rendering thread even when the UI thread is blocked."
How can I achieve the same thing for Qt Widgets?
Basically, I want something like:
1) start loading screen / splash-screen
2) start GUI-blocking operation
3) stop loading screen / splash-screen
It is not possible to move the ui-blocking operation to a separate thread (Widgets are being created). I cannot modify this part.
I tried QQuickWidget and QQuickView containing the splash-screen scene with an Animator inside but it didn't work - they got blocked as well.
EDIT: In the separate thread I read the file containing the UI description. Then I recursively create hundreds of Widgets (including QQuickWidgets, QLabels for images, Web views etc.).
Point of the question was to see if there is a "workaround" for that (e.g. displaying the aforementioned QML scene in some separate window with an own event loop). Unfortunately at this point not much more can be done about the overall design of the above.
Probably the widgets you're creating do too much work. You have to specify exactly how many widgets you're creating, and how. Show some example code. In general, the GUI thread is for cooperative multitasking - if you have something that "blocks", break it down into tiny chunks. For example, suppose that you're processing some XML or json file to build the UI. You could have that task do it one widget at a time, and be invoked each time the event loop is about to block (i.e. use a zero-duration "timer" and invert control).
You should also do the maximum possible amount of work outside of the gui thread. I.e. the UI description should be read and converted to an efficient representation that encapsulates the work to be done in the main thread. This conversion has to be done asynchronously.
The simplest way to accomplish that is to encapsulate each widget's creation in a lambda that refers to some context object. Such a lambda would have the signature [...](BatchContext &ctx). The vector of those lambdas would be kept by the CreationContext object as well:
class BatchContext : public QObject {
Q_OBJECT
public:
using Op = std::function<void(CreationContext &)>;
using QObject::QObject;
// useful for Op to keep track of where things go
void push(QWidget *w) { m_stack.push_back(w); }
QWidget *pop() { return m_stack.isEmpty() ? nullptr : m_stack.takeLast(); }
QWidget *top() const { return m_stack.isEmpty() ? nullptr : m_stack.last(); }
int stackSize() const { return m_stack.size(); }
bool stackEmpty() const { return m_stack.isEmpty(); }
Q_SLOT void startExec() {
if (m_execIndex < ops.size())
m_execTimer.start(0, this);
}
template <typename F>
void addOp(F &&op) { m_ops.push_back(std::forward<F>(op)); }
...
private:
QVector<Op> m_ops;
QVector<QWidget *> m_stack;
QBasicTimer m_execTimer;
int m_execIndex = 0;
void timerEvent(QTimerEvent *ev) override {
if (ev->timerId() == m_execTimer.timerId())
if (!exec())
m_execTimer.stop();
}
/// Does a unit of work, returns true if more work is available
bool exec() {
if (m_execIndex < m_ops.size())
m_ops.at(m_execIndex++)(*this);
return m_execIndex < ops.size();
}
};
After the context is created asynchronously, it can be passed to the main thread where you can then invoke startExec() and the widgets will be created one-at-a-time. The stack is but an example of how you might implement one aspect of widget creation process - the tracking of what widget is the "current parent".
For some reason, I needs to wrap opencv VideoCapture in a class which will be used in Qt Quick.
There are two classes, one is Camera, other is CameraView. CameraView inheritd from QQuickPaintedItem.
Camera class will get image periodically. It achieved by QObject::startTimer(int interval). (e.g. If fps of the webcam is 30, the timer interval is 1000 / 30 - 8, 8 is deviation of time). Once Camera has get image, it notifies CameraView to repaint by calling CameraView::Update().
And in CameraView::paint(QPainter *), CameraView will get an copy of image from Camera class and paints this image by call QPainter::drawImage(...).
I got some problems in process of coding:
I try to replace time event with QThread to get image from camera periodically. When I call CameraView::Update() in QThread, CameraView doesn't repaint. What is the problem?
In my laptop, when I make the CameraView painting the image in fullscreen, I found one python program slow down. Is another way to paint image with lower cost and efficient?
How can I efficiently update QML item based on QQuickPaintedItem C++
class? I delegated some preprocesssing to dedicated thread instead of
a timer on UI thread and it does not update the image in QML UI anymore.
It is a mandatory to trigger UI update from UI thread in Qt including QML. Make that CameraView to expose public slot updateImage.
class CameraView : public QQuickPaintedItem
{
Q_OBJECT
Q_DISABLE_COPY(CameraView)
public:
CameraView(QQuickItem* parent = nullptr);
public slots:
void updateImage(const QImage&);
protected:
QImage m_image;
};
CameraView should implement updateImage and paint like that:
void CameraView::updateImage(const QImage& image)
{
m_imageThumb = image; // does shallow copy of image data
update(); // triggers actual update
}
void CameraView::paint(QPainter* painter)
{
painter->drawImage(this->boundingRect(), m_image);
}
ClassOpenCvOnWorkerThread should start its worker thread and expose signalUiUpdate:
OpenCvOnWorkerThread::OpenCvOnWorkerThread()
{
this->moveToThread(&m_workerThread);
// the below will allow communication between threads
connect(this, SIGNAL(signalUiUpdate(QImage)), m_cameraView, SLOT(updateImage(QImage)));
m_workerThread.start();
}
void OpenCvOnWorkerThread::cvRead()
{
QImage image;
// OpenCV details available in your code
// cv::read
// make QImage from frame
// deliver QImage to another thread
emit signalUiUpdate(image);
}
UPDATE: In my own code for similar QML output from "camera" thread I also take care of handling the UI thread stall when it is unable to process video frames so the signal sender knows when not to post video frames. But that worth another question. Or this whole example can be reimplemented without signal and slot but with condition variable.
I have the following (simplified) code to add QStandardItem's to a QStandardItemModel, attach the model to a QListView, and connect signals of my choice from the model to a function of my choice:
// MyUIContainer derives from QWidget
MyUIContainer::SetItems()
{
// Inside a member function where model/items are added to a QListView...
// This code does not show deletion of existing ItemSelectionModel
QStandardItemModel * model = new QStandardItemModel(ui->listView);
// In the real code, data is set in each QStandardItem
model->setItem( 0, new QStandardItem() );
model->setItem( 1, new QStandardItem() );
model->setItem( 2, new QStandardItem() );
connect(model,
SIGNAL(itemChanged(QStandardItem*)),
this,
SLOT(ReceiveChange(QStandardItem*)));
// I have also tried connecting to this signal - same problem described below
//connect(model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &, const QVector<int>)), this, SLOT(ReceiveChange(const QModelIndex &, const QModelIndex &, const QVector<int>)));
ui->listView->setModel(model);
}
MyUIContainer::ReceiveChange(QStandardItem * item)
{
// Problem! This slot is called *three times*
// whenever the check state of an item changes
}
As the code comment indicates, there is a problem: The itemChanged() \ ReceiveChange() signal \ slot combination is called three times whenever the check state of a checkbox in the QListView changes once.
I understand that I can create my own Model class that is derived from QAbstractItemModel, and (if I understand correctly) handle mouse clicks in the view myself, emitting signals such as, for example, the itemChanged signal with a proper user-defined role so that a change in checkbox state can be handled only once.
However, the latter approach requires me to be careful to handle all possible scenarios of mouse clicks & keyboard events that could result in a changed checkbox state. I was hoping, and assuming, that this logic has been handled inside the Qt library itself, so that I don't have to - so that I can simply receive a signal (or some other message) when the check state of a checkbox changes.
Note that it seems that QListWidget (rather than QListView) also has exactly the same problem.
So, my question is: Without writing my own Model class derived from QAbstractItemModel - with its requirement that I myself write code to handle every possible way that a check state can change - how do I capture a changed check state (via a signal or otherwise) such that I can unambiguously capture every time a check state changes once and only once per check state change?
ADDENDUM
With apologies - as I took great care in ruling everything else out - Riateche's comment made it clear to me that the behavior is not supposed to work in the way this question highlighted. Finally, I have indeed tracked down the problem to the fact that I was calling connect() multiple times.
I’m using Qt 4.8.3 on X11.
I need to know when the user ends with dragging a window around the screen,
this in order to read the final position and eventually start an animation to adjust the window position to an “allowed” one.
I noticed that the QWidget::moveEvent is called for each small movement, but this is very unconvenient because I must perform position checking (and eventually start the animation) only when the user releases the mouse button and the movement is completely finished.
This is the real problem: it seems that there is no way to detect the mouse release event (or to get the mouse buttons status) when the user clicks on the titlebar, since it is controlled by the OS and not by Qt.
I tried also with the QWidget::x11event(XEvent* e)… but the events are collected only inside the window, not the title bar, as well.
Does someone know a way to achieve this?
I suspect that I will have to reimplement the titlebar myself… too bad…
Realizing this is a very old question, it is the first hit that comes up when you try "Qt detecting the end of a window move event". So, I thought I'd add a solution that works well with the current (as of this writing) release of Qt, 5.12.3.
You can set up a small state machine that provides the boundaries for knowing when a top-level window's position has been altered using a QObject::eventFilter(). In Qt 5.12.x, you will receive a QEvent::NonClientAreaMouseButtonPress event when the mouse goes down in the non-client area of your window (e.g., the title bar), a subsequent QEvent::Move event when the window position changes (if at all), and then a final QEvent::NonClientAreaMouseButtonRelease event when the mouse button is released.
Knowing this sequence, and using a persistent Boolean state flag (user_moved_window) to know that the position actually changed, would give you the following code snippet within your QObject::eventFilter() method:
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
QEvent::Type event_type = event->type();
[...]
else if(event_type == QEvent::NonClientAreaMouseButtonPress)
user_moved_window = false;
else if(event_type == QEvent::Move && isVisible())
user_moved_window = true;
else if(event_type == QEvent::NonClientAreaMouseButtonRelease)
{
if(user_moved_window)
{
// do what you need to do to here to respond to
// the end of the reposition event...
user_moved_window = false;
}
}
[...]
return MainWindow::eventFilter(obj, event);
}
You might need to add some additional checks depending on your situation--e.g., to make sure the obj for the event is actually the main window--but this example works well for my production code using Qt 5.12.3.
I have the same problem as yours. The moveEvent is triggered at every point along its move and Qt provides no explicit method to figure out the end of the move.
But now, inspired by the answer of divanov, I found that when we release the mouse after moving the dialog, an event typed 173 would always be triggered. That's QEvent::NonClientAreaMouseMove.
So the code is straightforward.
First install the event filter and announce a member variable: int nLastEvent;.
bool Win::eventFilter(QObject *obj, QEvent *event)
{
if (nLastEvent == QEvent::Move && event->type() == 173)
{
// do what you wanna do here when the mouse is released,
// like attaching the dialog to the main window
}
nLastEvent = event->type();
return QWidget::eventFilter(obj, event);
}
It's simple and efficient enough, isn't it!
Hope it be useful for you, too. :)
Let's consider the following test application:
main.cpp
#include <QApplication>
#include "win.h"
int main(int argc, char** argv)
{
QApplication app(argc, argv);
Win w;
w.show();
return app.exec();
}
win.h:
#include <QWidget>
#include <QEvent>
#include <QMoveEvent>
#include <QDebug>
class Win : public QWidget
{
public:
Win(QWidget *parent = 0) : QWidget(parent) {
this->installEventFilter(this);
}
protected:
bool eventFilter(QObject *obj, QEvent *event) {
if (event->type() == QEvent::Move) {
QMoveEvent *moveEvent = static_cast<QMoveEvent*>(event);
qDebug() << "Move event:" << moveEvent->pos();
} else {
qDebug() << "Event type:" << event->type();
}
return QWidget::eventFilter(obj, event);
}
};
This application just installs event filter on itself and prints to console all received events with special formatting for QMoveEvent to discriminate it in the log.
Typical log:
Event type: 203
Event type: 75
Move event: QPoint(0,0)
Event type: 14
Event type: 17
Event type: 26
Event type: 74
Event type: 77
Move event: QPoint(66,52)
Event type: 12
Event type: 24
Event type: 99
Event type: 77
Event type: 12
Event type: 10
Event type: 11
Move event: QPoint(308,356)
Event type: 19
Event type: 25
Event type: 99
Event type: 18
Event type: 27
Event type: 77
As you see, there are 2 move events, when application was initially created and one, after I finished window movements. I was testing with Qt 4.8.1 and XOrg 7.6.
To check raw X events
Have the test application running.
Get window Id of the test application. To do so execute in command line xwininfo -name WINDOW_NAME, where WINDOW_NAME is the name of the test application's window. Another option is to use xwininfo without parameters, then you have to select the test application window with a mouse pointer.
Run X event monitor xev -id 0x2a00002, where 0x2a00002 is window Id found in a previous step. This will print X events your window receives from X server. ConfigureNotify is X protocol counterpart of QMoveEvent.
I am undertaking a game using a combination of c++ in visual studios 2010 and Qt 4.7 (both windows). The game is a clone of battleship and is console input based. I have created my gui how I want it to look, and on the Qt side in Qt designer, my gui consists of a grid layout 10x10, using labels to hold pixmaps of game cells:
I have painstakingly named each label to represent its position in the 2d array (ie. fleet map => F_00 => F[0,0] => F[i],[j]). I can manually choose what pixmap I would like to display using the properties editor, but I would like something dynamic.
I use an update mapboard class to redraw the game board after a player fires, which keeps storing over a char array. I would like to update my pixmaps for each, using a generic getupdatearray type function. As we traverse the array it will update the pixmap currently associated with individual labels to match their cousins from the array. (say F[5][6] = 'X' for hit, then when the loops got to that position in the array it would update the grid of pixmaps at F_56 to equal hit.png, replacing the empty.png.
I have an idea how to make the loop that would accomplish this, but unsure how i would go about getting the pixmap for each label to be more along the lines of a runtime feature versus the now compile time (static) feature. I have read about QPainter and another Qt class that deals with images, but still having a hard go at it.
Question to any of you, how do I update these pixmaps based on a 2d array?
loop structure - i can figure out
condition statements - i can figure out
qt specific syntax dealing with labels- newbie so no idea atm.
Here's some pseudocode of the kind of thing I am trying to do with map.h:
#include <QtCore>
#include <QtGui>
// WARNING: PSEUDOCODE, DOES NOT COMPILE
// AT A LOSS ON HOW TO SELECT THE CORRECT LABEL
// MAYBE A CHILD CLASS FOR THAT?
class map {
public:
char updateboard(char mapname, char b[][10]){
for(int i=0;i<10;i++){
for(int j=0;j<10;j++){
char C = b[i][j];
if (C == 'M'){//miss
Qlabel mapname_[i][j](<img src='images/missspace.png'/>);
mapname_[i][j].show();
}
else if(C == 'X'){//hit
Qlabel mapname_[i][j](<img src='images/hitspace.png'/>);
mapname_[i][j].show();
}
else if(C == ' '){//undiscovered space
Qlabel mapname_[i][j](<img src='image/emptyspace.png'/>);
mapname_[i][j].show();
}
}
}
}
};
Then in my mainwindow.cpp, I include map.h and say:
// calls class function update board
// takes updated array values and replaces old pixmap with new
map.updateboard(T,b[][10]); // target map update
map.updateboard(F,v[][10]); // fleet map update
Thanks in Advance
UPDATE:
I've gotten to the point where I can swap pixmaps with buttons presses, but I would like to create something more dynamic. I wanted to use a Qstring in which I place the name of the label I want to change using by appending x y values using:
TR_position.append(QString::number(xvalue));
When I try to call it using:
ui->TR_position->setPixmap(QPixmap(":/images/missspace.png"));
...it obviously doesnt work. Is there a way to type case it, or use the contents of the string as the Qlabel name?
You manually entered and named 200 label widgets? Let no one call you lazy. :)
Per your update, you now know how to use QLabel::setPixmap(). What you think you need is getting a QLabel pointer from a name, which would be a combination of two things:
QWidget::findChild to get a QWidget* from a QString
qobject_cast to get a QLabel* from a QWidget
If you go down this path, what you'd wind up with is something like:
QWidget* cellWidget = ui->findChild(TR_position);
QLabel* cellLabel = qobject_cast<QLabel*>(cellWidget);
cellLabel->setPixmap(QPixmap(":/images/missspace.png"));
But BEWARE! There are many things wrong with this approach.
It's brittle: What if there doesn't happen to be any widget with that name (mysterious crash)? Or even worse, what if there are multiple widgets with that name and this code marches along blissfully ignorant of that odd condition that is likely a bug?
It's poor OOP: While there are some decent cases to use dynamic casting (or "downcasting"), it usually indicates a flaw in a design. You know that all QLabels are QWidgets, but not all QWidgets are QLabels...so that qobject_cast call might return NULL. It's just one more point of failure. Sometimes you can't avoid this, but really there is no reason your program needs to be structured in such a way.
It's terribly slow: Searching for a widget by its name is essentially a naive recursive search. If you've set aside a separate widget frame for each grid and only search that, Qt will have to do 100 string compares to find the last element (so 50 in the average case). Imagine clearing the grid with a loop...now you're talking about 100*50 string compares!
All these things are avoidable. Just as it's possible to use loops to set the images on the controls by name, it's possible to use loops to create the widgets in the first place. You basically would leave the area for the game board blank in the design tool, and then dynamically create the controls with code...attach them to the layout with code...and save pointers to them in 2D array. (You wouldn't access them by label name at that point, you'd index them just as you are indexing your board.)
You could create your own class derived from QLabel (such as a GameCell class) which contained the information for your board cell and methods related to it. Then you wouldn't need an array of label widgets in parallel to an array representing your board. You'd simply have one array of objects that took care of both aspects of the implementation.
UPDATE: Since you asked in the comments for specifics, here's a GameCell class:
class GameCell : public QLabel
{
Q_OBJECT
public:
enum State { Undiscovered, Hit, Miss };
GameCell (QWidget *parent = 0) : QLabel (parent),
currentState (Undiscovered)
{
syncBitmap();
}
State getState() const { return currentState; }
void setState(State newState) {
if (currentState != newState) {
currentState = newState;
syncBitmap();
}
}
private:
void syncBitmap() { // you'd use setPixmap instead of setText
switch (currentState) {
case Undiscovered: setText("U"); break;
case Hit: setText("H"); break;
case Miss: setText("M"); break;
}
}
State currentState;
};
This does double duty by behaving like a QWidget as well as maintaining a piece of internal state. Then a GameMap widget can use a QGridLayout of these GameCells:
class GameMap : public QWidget {
Q_OBJECT
public:
static const int Rows = 10;
static const int Columns = 10;
GameMap (QWidget* parent = 0) :
QWidget (parent)
{
layout = new QGridLayout (this);
for (int column = 0; column < Columns; column++) {
for (int row = 0; row < Rows; row++) {
GameCell* cell = new GameCell (this);
cells[column][row] = cell;
layout->addWidget(cell, row, column);
}
}
}
private:
GameCell* cells[Columns][Rows];
QGridLayout* layout;
};
If you wanted to, you could just leave spaces in your layout in the designer you wanted to fill in with the GameMap widget. Or you can push on and do the whole thing programmatically. For the sake of simplicity I'll just put two boards next to each other with a vertical separator on the surface of a dialog:
class Game : public QDialog
{
Q_OBJECT
public:
Game (QWidget *parent = 0)
: QDialog(parent)
{
targetMap = new GameMap (this);
fleetMap = new GameMap (this);
verticalSeparator = new QFrame (this);
verticalSeparator->setFrameShape(QFrame::VLine);
verticalSeparator->setFrameShadow(QFrame::Sunken);
layout = new QHBoxLayout (this);
layout->addWidget(targetMap);
layout->addWidget(verticalSeparator);
layout->addWidget(fleetMap);
setLayout(layout);
setWindowTitle(tr("Battleship"));
}
private:
GameMap* targetMap;
QFrame* verticalSeparator;
GameMap* fleetMap;
QHBoxLayout* layout;
};
I'm not going to write a whole game here or make it look fancy. That's just the gist, showing how to get 200 labels up in a programmatic fashion:
With my code, getting a GameCell from an (x,y) coordinate doesn't require an average of 50 string compares. Due to the formalized and predictable nature of 2D arrays, indexing into cells[x][y] only requires a single multiply operation and a single addition operation. There's no downcasting, and you can simply write:
cells[x][y].setState(GameCell::Miss);
ADDENDUM: Creating a QWidget for each grid cell isn't necessarily the way to go in the first place. Some might consider that "heavyweight". If your game were being played out on a large virtual space of tiles then it could be much too slow. You might find it useful to look into QGraphicsGridLayout, which could be a more appropriate approach in the long run:
http://doc.qt.io/qt-5/qtwidgets-graphicsview-basicgraphicslayouts-example.html
Using QWidgets won't be much of an issue with a 10x10 grid, however, so if you want to just stick with that then you can. If you're going to do it that way, then at least you shouldn't be placing them all by hand!