CMLDMR
CMLDMR

Reputation: 344

How QTableView or QListView is scrolling with hand drag?

in QGraphicview,

if we set it with : ui->graphicsView->setDragMode(QGraphicsView::ScrollHandDrag);

this code make graphicsview can scroll items with mouse pressed and drag.

How can we make QListView or QTableView as the QGraphicsView?

Upvotes: 1

Views: 1389

Answers (2)

Top-Master
Top-Master

Reputation: 8826

like Resurrection did mention

You will need to subclass these widgets and reimplement QWidget::mousePressEvent, QWidget::mousMoveEvent and QWidget::mouseReleaseEvent

but below code is more preferred by us:

class MyListView : public QListView
{
    typedef QListView super;
public:
    explicit MyListView(QWidget *parent = 0);

protected:
    // QWidget interface
    void mousePressEvent(QMouseEvent *) Q_DECL_OVERRIDE;
    void mouseReleaseEvent(QMouseEvent *) Q_DECL_OVERRIDE;
    void mouseMoveEvent(QMouseEvent *) Q_DECL_OVERRIDE;

private:
    enum DragState {
        DragStopped,
        DragStarted,
        Dragged
    };
    quint8 m_dragState;
    int m_dragStartPos;
};

MyListView::MyListView(QWidget *parent)
    : super(parent)
    , m_dragState(DragStopped)
    , m_dragStartPos(-1)
{
}

void MyListView::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton) {
        m_dragState = DragStarted;
        m_dragStartPos = event->pos().y();
    } else
        super::mousePressEvent(event);
}

void MyListView::mouseReleaseEvent(QMouseEvent *event)
{
    if(m_dragState) {
        m_dragState = DragStopped;
        m_dragStartPos = -1;
        return;
    }
    super::mouseReleaseEvent(event);
}

void MyListView::mouseMoveEvent(QMouseEvent *event)
{
    if(m_dragState != DragStopped) {
        const int itemSize = sizeHintForRow(0) / 2;
        const int distance = qAbs(m_dragStartPos - event->pos().y());
        if(distance > 10)
            m_dragState = Dragged;
        if(distance > itemSize) {
            QScrollBar *scrollBar = this->verticalScrollBar();
            int stepCount = (distance/itemSize);
            if(m_dragStartPos < event->pos().y())
                stepCount = -stepCount; //scrolling up
            scrollBar->setValue(scrollBar->value() + (stepCount * scrollBar->singleStep()));
            m_dragStartPos = event->y();
        }
        return;
    }
    super::mouseMoveEvent(event);
}

Upvotes: 1

Resurrection
Resurrection

Reputation: 4106

You will need to subclass these widgets and reimplement QWidget::mousePressEvent, QWidget::mousMoveEvent and QWidget::mouseReleaseEvent. However you will have to be careful because you may be interfering with actions that are mapped to these by default implementations (e.g. selecting) so it would need to be tweaked a bit. For example (assumed subclass of QListView):

void MyListView::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::RightButton) //lets map scrolling to right button
        m_ScrollStart = event->pos(); //QPoint member, indicates the start of the scroll
    else
        QListView::mousePressEvent(event);
}

and then

void MyListView::mouseMoveEvent(QMouseEvent *event)
{
    if(!m_ScrollStart.isNull()) //if the scroll was started
    {
        bool direction = (m_ScrollStart.y() < event->pos().y()); //determine direction, true is up (start is below current), false is down (start is above current)
        int singleStep = (direction ? 10 : -10); //fill in the desired value
        verticalScrollBar()->setValue(verticalScrollBar()->value() + singleStep); 
        //scroll by the certain amount in determined direction,
        //you decide how much will be a single step... test and see what you like 
    }

    QListView::mouseMoveEvent(event);
}

and finally

void MyListView::mouseReleaseEvent(QMouseEvent *event)
{
    m_ScrollStart = QPoint(); //resets the scroll drag
    QListView::mouseReleaseEvent(event);
}

Upvotes: 2

Related Questions