我有一個小例子,使用mousemovement和mousewheel調用的Slots。插槽只用一個線程互相打斷?
現在我遇到了這樣的問題,當我縮放並同時移動時,首先調用onZoom-slot並在完成之前調用onMouseMoved-slot。這會導致第一個槽鎖定互斥體(在另一個線程使用的原始程序中),第二個槽等待它。
如何防止插槽互相中斷(以及他們爲什麼首先執行它,因爲它們在同一個線程中?)。
我讀了一些關於使用Qt :: QueuedConnection但導致訪問衝突異常的內容。
的main.cpp
#include "ppi.h"
#include <QtGui/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
PPI w;
w.show();
return a.exec();
}
ppi.h
#ifndef PPI_H
#define PPI_H
#include <QtGui/QMainWindow>
#include <QGraphicsView>
#include <QDebug>
#include <QWheelEvent>
#include <QgraphicsEllipseItem>
#include <QMouseEvent>
#include <QMutex>
#include <QThread>
#include <QGraphicsSceneMouseEvent>
//#include "ui_ppi.h"
class PPIView : public QGraphicsView
{
Q_OBJECT
public:
PPIView(QWidget * parent = 0)
: QGraphicsView(parent)
{};
~PPIView(){};
private slots:
void wheelEvent(QWheelEvent *event)
{emit zoom(event);};
signals:
void zoom(QWheelEvent *event);
};
class PPIScene : public QGraphicsScene
{
Q_OBJECT
public:
PPIScene(QObject *parent)
: QGraphicsScene(parent)
{};
~PPIScene(){};
private:
void mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{emit mouseMoved(event);};
signals:
void mouseMoved(QGraphicsSceneMouseEvent *event);
};
class PPI : public QMainWindow
{
Q_OBJECT
public:
PPI(QWidget *parent = 0, Qt::WFlags flags = 0)
: QMainWindow(parent, flags)
{
//ui.setupUi(this);
//ppiScene is inherited from QGraphicsScene, overriding mouseMoveEvent so it emits mouseMoved();
ppiScene = new PPIScene(this);
gVPPI = new PPIView(this);
gVPPI->setMinimumSize(1024,1024);
gVPPI->show();
test = new QGraphicsEllipseItem(-10, -10, 20, 20);
ppiScene->addItem(test);
gVPPI->adjustSize();
connect(ppiScene, SIGNAL(mouseMoved(QGraphicsSceneMouseEvent*)), this, SLOT(onMouseMoved(QGraphicsSceneMouseEvent*)));
connect(gVPPI, SIGNAL(zoom(QWheelEvent*)), this, SLOT(onZoom(QWheelEvent*)));
//ui.gVPPI is inherited from QGraphicsView, overriding wheelEvent, so it emits zoom()
gVPPI->setScene(ppiScene);
gVPPI->setMouseTracking(true);
};
~PPI(){};
QMutex mutex;
private:
//Ui::ppiClass ui;
PPIScene* ppiScene;
PPIView *gVPPI;
QGraphicsEllipseItem *test;
protected slots:
void onZoom(QWheelEvent *event)
{
qDebug() << "Zoom lock" << QThread::currentThreadId();
mutex.lock();
qDebug() << "Zoom locked";
if(event->delta() > 0)
gVPPI->scale(1.01, 1.01);
else
gVPPI->scale(1/1.01, 1/1.01);
qDebug() << "Zoom unlock";
mutex.unlock();
qDebug() << "Zoom unlocked";
};
void onMouseMoved(QGraphicsSceneMouseEvent *event)
{
qDebug() << "Move lock" << QThread::currentThreadId();
mutex.lock();
qDebug() << "move locked";
test->setPos(test->pos()+event->scenePos()-event->lastScenePos());
qDebug() << "Move unlock";
mutex.unlock();
qDebug() << "Move unlocked";
};
};
#endif // PPI_H
輸出qDebug()
:
Move lock 0x1514
move locked
Move unlock
Move unlocked
Move lock 0x1514
move locked
Move unlock
Move unlocked
Zoom lock 0x1514
Zoom locked
Move lock 0x1514
這是不可能的,因爲Qt中的所有GUI都在一個線程中工作。你的互斥體在那裏什麼都不做。你可以檢查,現在執行什麼線程。例如(在每個槽中):'Q_ASSERT(QThread :: currentThread()== this-> thread());' –
這就是爲什麼我很困惑。所有插槽都在同一個線程中運行,但在同時移動和滾動時仍然能夠引發彼此的衝突。我也用'QThread :: currentThreadId()'檢查了線程ID,它們在同一個線程中。在我的例子中,互斥體做了一些事情:它導致程序凍結。如果這些插槽不會中斷對方,那就不會發生。我添加qDebug()的輸出 – honiahaka10
我認爲'ui.gVPPI-> scale'會以某種方式觸發鼠標移動。你可以在'scale'後添加一個你設置爲真正的bevor和false的bool成員,並且只有在測試爲false時才執行移動 – Bowdzone