Is it possible to use a different mouse cursor when dragging a floating QDockWidget? Neither QWidget::setCursor nor QApplication::setOverrideCursor have any effect.
A floating QDockWidget is a window, so you need to ask the OS to change the cursor when it's on the non-client area.
A little buggy example for windows:
#define WINVER 0x0500
#include <windows.h>
#include <windowsx.h>
#include <winuser.h>
bool DockWidget::winEvent(MSG * message, long * result)
{
switch(message->message)
{
case WM_NCMOUSEMOVE:
if(message->wParam == HTCAPTION)
{
qDebug() << "WM_NCMOUSEMOVE";
if(!cursorHasBeenChanged && !cursorHasBeenClosed)
{
cursorHasBeenChanged = true;
QApplication::setOverrideCursor(Qt::OpenHandCursor);
}
}
else
if(cursorHasBeenChanged)
{
cursorHasBeenChanged = false;
QApplication::restoreOverrideCursor();
}
break;
case WM_NCMOUSELEAVE:
qDebug() << "WM_NCMOUSELEAVE";
if(cursorHasBeenChanged && !cursorHasBeenClosed)
{
cursorHasBeenChanged = false;
QApplication::restoreOverrideCursor();
}
break;
case WM_NCLBUTTONDOWN:
if(message->wParam == HTCAPTION)
{
qDebug() << "WM_NCLBUTTONDOWN";
cursorHasBeenClosed = true;
QApplication::setOverrideCursor(Qt::ClosedHandCursor);
}
break;
case WM_NCLBUTTONUP:
qDebug() << "WM_NCLBUTTONUP";
if(cursorHasBeenClosed)
{
cursorHasBeenClosed = false;
QApplication::restoreOverrideCursor();
}
break;
default:
;
}
return QDockWidget::winEvent(message, result);
}
I think the code is self-explanatory, byut don't hesitate to ask if there something you don't understand.
The buggy part, is that I never receive WM_NCLBUTTONUP messages and I don't know why (I get WM_NCMOUSEMOVE instead) neither WM_NCMOUSEHOVER (which is the "enter event" for non-client area).
Related
#include <iostream>
using namespace std;
struct Node{
bool flag;
char letter;
Node* left;
Node* right;
};
typedef Node* Nodeptr;
int stop = 0;
void splitString(string sequence, Nodeptr branch){
//cout << sequence << " ";
//cout << sequence.size() << endl;
if(stop == 20) return;
else stop++;
if(sequence.size() == 1){
branch->flag = true;
branch->letter = sequence[0];
}
else{
int half = sequence.size()/2;
Node* left = new Node;
Node* right = new Node;
branch->flag = false;
branch->left = left;
branch->right = right;
splitString(sequence.substr(0, half), left);
splitString(sequence.substr(half), right);
}
return;
}
void print(Nodeptr root){
if(root->flag)
cout << root->letter;
else{
print(root->left);
print(root->right);
}
return;
}
int main() {
std::cout << "Hello World!\n";
Nodeptr tree = new Node;
splitString("Heaven on ", tree);
print(tree);
//the above two lines run fine
Nodeptr tree2 = new Node;
splitString("Heaven on E", tree2); //this code will run fine
//print(tree2); //this code will give me an EXITED, SEGMENTATION FAULT error
}
Considering that the two lines:
splitString("Heaven on ", tree);
print(tree);
run fine, but these do not:
splitString("Heaven on E", tree2);
//print(tree2); //this code will give me an EXITED, SEGMENTATION FAULT error
I come to think that I have reached the maximum recursion depth. I reviewed my code for the building and traversing the binary tree but I cannot find any problems there. What is the reason for the error? Thanks!
For two reason:
you are using a global, which is a very bad practice, and for example in this case you are not resetting it after the first splitString
you are not managing the case where the string has 0 as size, in the right way
This is a possible implementation of splitString which works (without globals):
void splitString(string sequence, Nodeptr branch){
if(sequence.size() == 1){
branch->flag = true;
branch->letter = sequence[0];
}
else if (sequence.size() > 1){
int half = sequence.size()/2;
Node* left = new Node;
Node* right = new Node;
branch->flag = false;
branch->left = left;
branch->right = right;
splitString(sequence.substr(0, half), left);
splitString(sequence.substr(half), right);
}
else {
branch->flag = true;
branch->letter = '\0';
}
}
There is surely a better way to do this, and i'll encourage you to change the data structor in order to makes it happen (for example don't use the flag to mark the leaves of the tree, just check if there is left is been set or is nullptr)
Is there elegant way to save and reproduce later all the input events (or at least touch ones) since Qt Quick 2 application's start until it closed or crashed/killed?
I can save all the input events of interest using the following approach (not full implementation):
class InputEventLogger
: public QObject
{
Q_OBJECT
public :
explicit InputEventLogger(QObject * const parent = Q_NULLPTR)
: QObject{parent}
{ ; }
protected :
bool eventFilter(QObject * watched, QEvent * event) Q_DECL_OVERRIDE
{
switch (event->type()) {
case QEvent::KeyPress :
case QEvent::KeyRelease : {
qDebug() << event->type();
const auto keyEvent = static_cast< QKeyEvent * >(event);
qDebug() << keyEvent->key() << keyEvent->text();
break;
}
case QEvent::MouseButtonPress :
case QEvent::MouseButtonRelease :
case QEvent::MouseButtonDblClick :
case QEvent::MouseMove : {
qDebug() << event->type();
const auto mouseEvent = static_cast< QMouseEvent * >(event);
qDebug() << mouseEvent->pos();
break;
}
case QEvent::TouchBegin :
case QEvent::TouchUpdate :
case QEvent::TouchEnd :
case QEvent::TouchCancel : {
qDebug() << event->type();
const auto touchEvent = static_cast< QTouchEvent * >(event);
qDebug() << touchEvent->touchPoints();
break;
}
case QEvent::GraphicsSceneMouseMove :
case QEvent::GraphicsSceneMousePress :
case QEvent::GraphicsSceneMouseRelease :
case QEvent::GraphicsSceneMouseDoubleClick : {
qDebug() << event->type();
break;
}
default : {
break;
}
}
return QObject::eventFilter(watched, event);
}
};
qApp->installEventFilter(new InputEventLogger{qApp});
QGraphicsScene accepts QEvent::GraphicsSceneMouse* events (translated from QEvent::MouseButton*/MouseMove). So, I need to translate corresponding events, before I pass them to QApplication::sendEvent().
Along with events I want to save their timestamps to reproduce them in exact manner in greater extent possible.
How to reproduce user input as realistic as possible?
I am following this instructions to get the child events. My aim is to change the value of QSpinBox by dragging the mouse up/down by keeping the Ctrl key pressed (like in GIMP).
However, while this works for the window, QSpinBox ignores the drag and just selects the contents inside.
I have installed the eventfilter into all childs with:
eventFilter(QObject *obj, QEvent *event)
{
switch(event->type())
{
case QEvent::ChildAdded:
{
QChildEvent* ce = static_cast<QChildEvent*>(event);
// Install the filter to each new child object created
ce->child()->installEventFilter(this);
break;
}
case QEvent::ChildRemoved:
{
QChildEvent* ce = static_cast<QChildEvent*>(event);
// Remove the the filter from each new child object removed
ce->child()->removeEventFilter(this);
break;
}
case QEvent::MouseButtonPress:
{
QMouseEvent* me = static_cast<QMouseEvent*>(event);
qDebug() << QString::number(me->pos().x());
qDebug() << QString::number(me->pos().y());
return true;
}
case QEvent::MouseButtonRelease:
{
QMouseEvent* me = static_cast<QMouseEvent*>(event);
qDebug() << QString::number(me->pos().x());
qDebug() << QString::number(me->pos().y());
return true;
}
case QEvent::MouseMove:
{
QMouseEvent* me = static_cast<QMouseEvent*>(event);
qDebug() << QString::number(me->pos().x());
qDebug() << QString::number(me->pos().y());
return true;
}
}
return QWidget::eventFilter(obj, event);
}
and in the constructor using:
setMouseTracking(true);
installEventFilter(this);
How can I fully make QSpinBox ignore selection?
I am working with OpenCV for Qt.
I am working on doing a program which is able to detect several objects. So far I could make a face, eye and nose detector, but when I try to make a full body detection I get either totally wrong detections, no detections at all or the program crashes. For detecting the full body I just use the same code as for the other detections but with the haarcascade_fullbody.xml file. Is it not possible to use the same code? Why does it work for the other features and not for the full body?
I have also tried to implement a car detection using OpenCV's pretrained models from https://github.com/Itseez/opencv_extra/tree/master/testdata/cv/latentsvmdetector/models_VOC2007 but I get parsing errors.
Thanks in advance!
Code from MainWindow:
void MainWindow::on_btnFullBody_clicked()
{
WriteInLog("Full body detection requested");
QString xml = tr("%1/%2").arg(QApplication::applicationDirPath()).arg(FULL_BODY_FILE);
FeatureDetector detector(xml);
std::vector<QRect> rest;
float scaleFactor= 1.1f;
uint neighbours= 2;
bool ret = detector.DetectFeature(&mSelectedImage, rest, scaleFactor, neighbours);
if (!ret)
{
WriteInLog("No full body has been detected");
}
else
{
QVector<QRect> qRect = QVector<QRect>::fromStdVector(rest);
processedImage(qRect);
WriteInLog("Bodys detected: "+QString::number(qRect.size()));
}
}
Code from DetectFeature:
bool FeatureDetector::DetectFeature(QImage* image, std::vector<QRect> &returnList, float scaleFactor, uint neighbours)
{
returnList.clear();
bool ok = false;
qDebug() << "Starting...";
if (!image->isNull()) {
//Changing from QImage to matrix
QImage temp = image->copy();
cv::Mat res(temp.height(),temp.width(),CV_8UC3,(uchar*)temp.bits(),temp.bytesPerLine());
cv::Mat res_gray;
//Changing the image to grey scale an equalizing the result
cvtColor(res, res_gray,CV_BGR2GRAY);
cv::equalizeHist(res_gray,res_gray);
cv::CascadeClassifier detector;
std::vector< cv::Rect > featureVec;
bool retDetector=true; // detector.load("C:/Users/ansurbcn_2/Pictures/cara.jpg");
qDebug()<<mXmlFilePath;
if (!detector.load(mXmlFilePath.toLatin1().constData()))
{
qDebug() << "Error loading detector";
return false;
}
detector.detectMultiScale(res_gray, featureVec);
//detector.detectMultiScale(res_gray, featureVec, scaleFactor, neighbours, 18|9);
if (retDetector) {
qDebug() << "OK Detector";
}
else {
qDebug() << "Failed Detector";
}
for(size_t i=0; i<featureVec.size();i++)
{
cv::Rect oneFeature =featureVec[i];
QRect qrect(oneFeature.x, oneFeature.y, oneFeature.width, oneFeature.height);
returnList.push_back(qrect);
ok = true;
}
}
return ok;
}
I have implemented QGraphicsObject with QTouchEvents and reimplemented the sceneEvent function.
bool LynxItem::sceneEvent(QEvent *event)
{
//qDebug() << "LynxItem::sceneEvent:" << itemId;
switch (event->type()) {
case QEvent::Gesture:
{
qDebug() << "LynxItem::sceneEvent:Gesture" << itemId;
return gestureEvent(static_cast<QGestureEvent*>(event));
break;
}
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
{
qDebug() << "LynxItem::sceneEvent:TouchUpdate" << itemId;
QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
const QTouchEvent::TouchPoint &touchPoint1 = touchPoints.last();
/* This doesn't allow two objects to move at the same time */
//setPos ( touchPoint1.scenePos() - touchPoint1.pos());
/* This does work but the item is always moved from top left */
setPos(touchPoint1.scenePos());
event->accept();
break;
}
default:
return QGraphicsItem::sceneEvent(event);;
}
return true;
}
My problem is that when I touch the item the items top right corner comes to the touch point. I want to offset the point inside where I touched. However when I do that I can only move one item at a time.
Ok, to answer my own question:
setPos ( touchPoint1.scenePos() - touchPoint1.pos());
Is incorrect. On the TouchBegin I should store touchPoint1.pos():
m_TouchOffset = touchPoint1.pos();
Then use that first position instead
setPos ( touchPoint1.scenePos() - m_TouchOffset);