Originally Posted by
kghose
Bump. Any hint would be most appreciated
-K
Well I had the same problem. And it turns out the graphicsview rubber band implementation is not particularly useful, so I made my own. The problem with the default is that it's relative to the view, so when you move the scene view, the selection rectangle moves with it, instead of anchoring to the scene where you clicked the mouse.
So here's what I did:
First of all, setDragMode(QGraphicsView::NoDrag); to turn off the default.
Then in the view:
void GraphWidget::onScrollTimeout() {
if(scrollDirection & Left) {
horizontalScrollBar()->setValue(horizontalScrollBar()->value()-scrollMagnitude);
}
if(scrollDirection & Right) {
horizontalScrollBar()->setValue(horizontalScrollBar()->value()+scrollMagnitude);
}
if(scrollDirection & Up) {
verticalScrollBar()->setValue(verticalScrollBar()->value()-scrollMagnitude);
}
if(scrollDirection & Down) {
verticalScrollBar()->setValue(verticalScrollBar()->value()+scrollMagnitude);
}
if(rubberBand->isVisible()) { // update the rubber band
QPoint mouseDownView
= mapFromScene
(mouseDownPos
);
QPoint diff
= (lastMouseViewPos
-mouseDownView
);
rubberBand->setGeometry(qMin(lastMouseViewPos.x(), mouseDownView.x()), qMin(lastMouseViewPos.y(), mouseDownView.y()), qAbs(diff.x()), qAbs(diff.y()));
}
}
// when shift is pressed, we drag the scene
if(evt->modifiers().testFlag(Qt::ShiftModifier)) {
qDebug() << "setting dragging mode";
}
else {
qDebug() << "press";
scrollTimer.start(30);
if(!scene()->itemAt(mapToScene(evt->pos())) && scene()->selectedItems().isEmpty()) {
mouseDownPos = mapToScene(evt->pos()).toPoint();
startRubberBand = true;
rubberBand
->setGeometry
(QRect(evt
->pos
(), evt
->pos
()));
}
}
}
if(!evt->modifiers().testFlag(Qt::ShiftModifier) && evt->buttons().testFlag(Qt::LeftButton)) {
int distance = 0;
scrollDirection = scrollMagnitude = 0;
// determine the direction of automatic scrolling
if(pos.x() < SCROLL_DISTANCE) {
scrollDirection = Left;
distance = pos.x();
}
else if(width()-pos.x() < SCROLL_DISTANCE) {
scrollDirection = Right;
distance = width()-pos.x();
}
if(pos.y() < SCROLL_DISTANCE) {
scrollDirection |= Up;
distance = pos.y();
}
else if(height()-pos.y() < SCROLL_DISTANCE) {
scrollDirection |= Down;
distance = height()-pos.y();
}
if(scrollDirection) {
scrollMagnitude = qRound((SCROLL_DISTANCE-distance)/8);
}
// handle the rubberband
if(startRubberBand && (mapFromScene(mouseDownPos)-evt->pos()).manhattanLength() > 4) {
rubberBand->show();
startRubberBand = false;
}
if(rubberBand->isVisible()) {
QPoint mouseDownView
= mapFromScene
(mouseDownPos
);
lastMouseViewPos = evt->pos();
QRect rubberRect
(mouseDownView, lastMouseViewPos
);
rubberRect = rubberRect.normalized();
rubberBand->setGeometry(rubberRect);
projectScene
->setSelectionAreaFixed
(QRectF(mapToScene
(rubberRect.
topLeft()), mapToScene
(rubberRect.
bottomRight())));
}
}
}
void GraphWidget
::mouseReleaseEvent(QMouseEvent* evt
) { rubberBand->hide();
startRubberBand = false;
scrollDirection = scrollMagnitude = 0;
scrollTimer.stop();
}
void GraphWidget::onScrollTimeout() {
if(scrollDirection & Left) {
horizontalScrollBar()->setValue(horizontalScrollBar()->value()-scrollMagnitude);
}
if(scrollDirection & Right) {
horizontalScrollBar()->setValue(horizontalScrollBar()->value()+scrollMagnitude);
}
if(scrollDirection & Up) {
verticalScrollBar()->setValue(verticalScrollBar()->value()-scrollMagnitude);
}
if(scrollDirection & Down) {
verticalScrollBar()->setValue(verticalScrollBar()->value()+scrollMagnitude);
}
if(rubberBand->isVisible()) { // update the rubber band
QPoint mouseDownView = mapFromScene(mouseDownPos);
QPoint diff = (lastMouseViewPos-mouseDownView);
rubberBand->setGeometry(qMin(lastMouseViewPos.x(), mouseDownView.x()), qMin(lastMouseViewPos.y(), mouseDownView.y()), qAbs(diff.x()), qAbs(diff.y()));
}
}
void GraphWidget::mousePressEvent(QMouseEvent* evt) {
// when shift is pressed, we drag the scene
if(evt->modifiers().testFlag(Qt::ShiftModifier)) {
setDragMode(QGraphicsView::ScrollHandDrag);
qDebug() << "setting dragging mode";
QGraphicsView::mousePressEvent(evt);
}
else {
qDebug() << "press";
scrollTimer.start(30);
QGraphicsView::mousePressEvent(evt);
if(!scene()->itemAt(mapToScene(evt->pos())) && scene()->selectedItems().isEmpty()) {
mouseDownPos = mapToScene(evt->pos()).toPoint();
startRubberBand = true;
rubberBand->setGeometry(QRect(evt->pos(), evt->pos()));
}
}
}
void GraphWidget::mouseMoveEvent(QMouseEvent* evt) {
if(!evt->modifiers().testFlag(Qt::ShiftModifier) && evt->buttons().testFlag(Qt::LeftButton)) {
QPoint pos = evt->pos();
int distance = 0;
scrollDirection = scrollMagnitude = 0;
// determine the direction of automatic scrolling
if(pos.x() < SCROLL_DISTANCE) {
scrollDirection = Left;
distance = pos.x();
}
else if(width()-pos.x() < SCROLL_DISTANCE) {
scrollDirection = Right;
distance = width()-pos.x();
}
if(pos.y() < SCROLL_DISTANCE) {
scrollDirection |= Up;
distance = pos.y();
}
else if(height()-pos.y() < SCROLL_DISTANCE) {
scrollDirection |= Down;
distance = height()-pos.y();
}
if(scrollDirection) {
scrollMagnitude = qRound((SCROLL_DISTANCE-distance)/8);
}
// handle the rubberband
if(startRubberBand && (mapFromScene(mouseDownPos)-evt->pos()).manhattanLength() > 4) {
rubberBand->show();
startRubberBand = false;
}
if(rubberBand->isVisible()) {
QPoint mouseDownView = mapFromScene(mouseDownPos);
lastMouseViewPos = evt->pos();
QRect rubberRect(mouseDownView, lastMouseViewPos);
rubberRect = rubberRect.normalized();
rubberBand->setGeometry(rubberRect);
projectScene->setSelectionAreaFixed(QRectF(mapToScene(rubberRect.topLeft()), mapToScene(rubberRect.bottomRight())));
}
}
QGraphicsView::mouseMoveEvent(evt);
}
void GraphWidget::mouseReleaseEvent(QMouseEvent* evt) {
rubberBand->hide();
startRubberBand = false;
scrollDirection = scrollMagnitude = 0;
scrollTimer.stop();
QGraphicsView::mouseReleaseEvent(evt);
setDragMode(QGraphicsView::NoDrag);
}
To copy to clipboard, switch view to plain text mode
So when we press the mouse, we store the mouse down pos and unhide the QRubberBand. Then on mouse move we update the QRubberBand's geometry and select the underlying objects. (on Line 77, I call the function "setSelectionAreaFixed". You can use QGraphicsScene::setSelectionArea if you are using Qt >= 4.4. Versions before 4.4 had a bug in that function that made it not work properly)
To get the automatic scrolling of the view, I just start a timer when the drag starts. On mouse movement, if the cursor is close to the edge of the view, I set a variable to indicate the direction of scrolling and the speed, then on the timeout I move the scene.
It's not exactly elegant, but it works. Took me a while to sort everything out (the Qt bug didn't help)
Bookmarks