Aunvre
29th July 2014, 03:10
Hi everyone, this is my first post here, so I apologize if this is the wrong category to be posting in.
I'm trying to design a node graph editor, similar to those seen in Blender, the Unreal Engine, and Unity. As part of this, I am trying to make a widget extended off of QGraphicsView that, when displayed, a large grid is in the background, and this view can be scrolled by holding down a mouse button and dragging it. However, the code I have right now doesn't work quite right, as the grid doesn't update it's position with the drag offsets.
NodeGraphWidget.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QGraphicsView>
#include <QKeyEvent>
#include <QPoint>
class NodeGraphWidget : public QGraphicsView
{
Q_OBJECT
public:
NodeGraphWidget(QWidget *parent = 0);
public slots:
//void zoomIn();
//void zoomOut();
protected:
void keyPressEvent(QKeyEvent *event);
void drawBackground(QPainter *painter, const QRectF &rect);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
float mScale;
int mOffsetX;
int mOffsetY;
bool mMiddleMouseDown;
QPoint mOldMousePos, mNewMousePos;
private:
};
#endif // MAINWINDOW_H
NodeGraphWidget.cpp:
(Note that I purposefully set the offsets to a constant, just to test if the graph would move)
#include "NodeGraphWidget.h"
#include <QBrush>
#include <QDebug>
#include <QEvent>
#include <QGraphicsScene>
#include <QKeyEvent>
NodeGraphWidget::NodeGraphWidget(QWidget *parent)
: QGraphicsView(parent)
{
QGraphicsScene *scene = new QGraphicsScene(this);
scene->setItemIndexMethod(QGraphicsScene::NoIndex);
scene->setSceneRect(0, 0, 400, 400);
setScene(scene);
setViewportUpdateMode(BoundingRectViewportUpdate);
setCacheMode(CacheBackground);
setRenderHint(QPainter::Antialiasing);
setTransformationAnchor(AnchorUnderMouse);
//this->ch
scale(qreal(1.0), qreal(1.0));
//setMinimumSize(400, 400);
setWindowTitle(tr("Test"));
mOffsetX = 0;
mOffsetY = 0;
mScale = 1.f;
}
void NodeGraphWidget::keyPressEvent(QKeyEvent *event)
{
Q_UNUSED(event);
qDebug() << event->key();
switch(event->key())
{
default: setWindowTitle("FUCK");
}
}
void NodeGraphWidget::drawBackground(QPainter *painter, const QRectF &rect)
{
Q_UNUSED(rect);
qDebug() << "redraw bkg, " << mOffsetX << " " << mOffsetY;
QRectF sceneRect = this->sceneRect();
painter->setBrush(QBrush(QColor(64,64,64)));
painter->fillRect(sceneRect, Qt::SolidPattern);
painter->setPen(QColor(80, 80, 80));
const int gridSize = 150;
for(int y = -3; y < (int)(height()*mScale)%gridSize; y++)
{
for(int x = -3; x < (int)(width()*mScale)%gridSize; x++)
{
painter->drawRect((x*gridSize)-(mOffsetX), (y*gridSize)-(mOffsetY), gridSize, gridSize);
}
}
}
void NodeGraphWidget::mousePressEvent(QMouseEvent *event)
{
switch(event->button())
{
case Qt::MiddleButton:
qDebug() << "DOWN";
mMiddleMouseDown = true;
mOldMousePos = event->localPos().toPoint();
break;
}
}
void NodeGraphWidget::mouseMoveEvent(QMouseEvent *event)
{
if(mMiddleMouseDown == true)
{
qDebug() << "DRAG";
mNewMousePos = event->localPos().toPoint();
mOffsetX = 75;// mOldMousePos.x() - mNewMousePos.x();
mOffsetY = 75;// mOldMousePos.y() - mNewMousePos.y();
invalidateScene();
}
}
void NodeGraphWidget::mouseReleaseEvent(QMouseEvent *event)
{
switch(event->button())
{
case Qt::MiddleButton:
qDebug() << "UP";
mMiddleMouseDown = false;
//mOldMousePos = QPoint(0, 0);
//mNewMousePos = QPoint(0, 0);
mOffsetX = 0;
mOffsetY = 0;
break;
}
}
At my qDebug() points, the offset variables are indeed being set, it's just when the view is "redrawn" it isn't being offset. Can anybody offer any help on this? I'm totally stumped.
Which brings me to my next question: is it good practice to have a widget that isn't specified as a scrollable one to be able to do so? I mostly did it so the scrollbars wouldn't show up (and yes, I know that they can be disabled on the scrollable widget classes). It just seemed like a good idea in hindsight. Now that I'm here, however, is this at all good practice? Or should I switch to a scrollable widget to extend off of? Any suggestions would be greatly appreciated, for either of my issues.
Thanks.
I'm trying to design a node graph editor, similar to those seen in Blender, the Unreal Engine, and Unity. As part of this, I am trying to make a widget extended off of QGraphicsView that, when displayed, a large grid is in the background, and this view can be scrolled by holding down a mouse button and dragging it. However, the code I have right now doesn't work quite right, as the grid doesn't update it's position with the drag offsets.
NodeGraphWidget.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QGraphicsView>
#include <QKeyEvent>
#include <QPoint>
class NodeGraphWidget : public QGraphicsView
{
Q_OBJECT
public:
NodeGraphWidget(QWidget *parent = 0);
public slots:
//void zoomIn();
//void zoomOut();
protected:
void keyPressEvent(QKeyEvent *event);
void drawBackground(QPainter *painter, const QRectF &rect);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
float mScale;
int mOffsetX;
int mOffsetY;
bool mMiddleMouseDown;
QPoint mOldMousePos, mNewMousePos;
private:
};
#endif // MAINWINDOW_H
NodeGraphWidget.cpp:
(Note that I purposefully set the offsets to a constant, just to test if the graph would move)
#include "NodeGraphWidget.h"
#include <QBrush>
#include <QDebug>
#include <QEvent>
#include <QGraphicsScene>
#include <QKeyEvent>
NodeGraphWidget::NodeGraphWidget(QWidget *parent)
: QGraphicsView(parent)
{
QGraphicsScene *scene = new QGraphicsScene(this);
scene->setItemIndexMethod(QGraphicsScene::NoIndex);
scene->setSceneRect(0, 0, 400, 400);
setScene(scene);
setViewportUpdateMode(BoundingRectViewportUpdate);
setCacheMode(CacheBackground);
setRenderHint(QPainter::Antialiasing);
setTransformationAnchor(AnchorUnderMouse);
//this->ch
scale(qreal(1.0), qreal(1.0));
//setMinimumSize(400, 400);
setWindowTitle(tr("Test"));
mOffsetX = 0;
mOffsetY = 0;
mScale = 1.f;
}
void NodeGraphWidget::keyPressEvent(QKeyEvent *event)
{
Q_UNUSED(event);
qDebug() << event->key();
switch(event->key())
{
default: setWindowTitle("FUCK");
}
}
void NodeGraphWidget::drawBackground(QPainter *painter, const QRectF &rect)
{
Q_UNUSED(rect);
qDebug() << "redraw bkg, " << mOffsetX << " " << mOffsetY;
QRectF sceneRect = this->sceneRect();
painter->setBrush(QBrush(QColor(64,64,64)));
painter->fillRect(sceneRect, Qt::SolidPattern);
painter->setPen(QColor(80, 80, 80));
const int gridSize = 150;
for(int y = -3; y < (int)(height()*mScale)%gridSize; y++)
{
for(int x = -3; x < (int)(width()*mScale)%gridSize; x++)
{
painter->drawRect((x*gridSize)-(mOffsetX), (y*gridSize)-(mOffsetY), gridSize, gridSize);
}
}
}
void NodeGraphWidget::mousePressEvent(QMouseEvent *event)
{
switch(event->button())
{
case Qt::MiddleButton:
qDebug() << "DOWN";
mMiddleMouseDown = true;
mOldMousePos = event->localPos().toPoint();
break;
}
}
void NodeGraphWidget::mouseMoveEvent(QMouseEvent *event)
{
if(mMiddleMouseDown == true)
{
qDebug() << "DRAG";
mNewMousePos = event->localPos().toPoint();
mOffsetX = 75;// mOldMousePos.x() - mNewMousePos.x();
mOffsetY = 75;// mOldMousePos.y() - mNewMousePos.y();
invalidateScene();
}
}
void NodeGraphWidget::mouseReleaseEvent(QMouseEvent *event)
{
switch(event->button())
{
case Qt::MiddleButton:
qDebug() << "UP";
mMiddleMouseDown = false;
//mOldMousePos = QPoint(0, 0);
//mNewMousePos = QPoint(0, 0);
mOffsetX = 0;
mOffsetY = 0;
break;
}
}
At my qDebug() points, the offset variables are indeed being set, it's just when the view is "redrawn" it isn't being offset. Can anybody offer any help on this? I'm totally stumped.
Which brings me to my next question: is it good practice to have a widget that isn't specified as a scrollable one to be able to do so? I mostly did it so the scrollbars wouldn't show up (and yes, I know that they can be disabled on the scrollable widget classes). It just seemed like a good idea in hindsight. Now that I'm here, however, is this at all good practice? Or should I switch to a scrollable widget to extend off of? Any suggestions would be greatly appreciated, for either of my issues.
Thanks.