I have a QGraphicsView
with a scene containing QGraphicsProxyWidget
(QTableView) and a QGraphicsRectItem
on top of QTableView
. Unfortunately, i am not able to upload any images (Imgur error) but here is a post to visualize how it looks.
My QGraphicsRectItem
a vertical line, acts like a seek bar which runs horizontally on the QTableView
. Basically, it looks like a time line with a seek bar commonly found in Audio and Video editing tools.
Issues:
- Moving the horizontal scroll bar makes the seek bar disappear on hitting the boundaries of
QTableView
and it doesn't reappear anymore. - While moving the scrollbar if the seekbar hits the boundaries, scrollbar cannot be moved further.
What did i do:
I have managed to create a MVCE (Not really Minimal)
//SeekBar.h
#include <QGraphicsRectItem>
#include <QAbstractItemView>
#include <QObject>
#include <QScrollBar>
#include <QGraphicsProxyWidget>
#include "tableview.h"
class SeekBar : public QObject, public QGraphicsRectItem
{
Q_OBJECT
public:
SeekBar(int width, QTableView* view, QGraphicsScene* scene);
protected:
QVariant itemChange(GraphicsItemChange change, const QVariant& value);
public slots:
void scrollBarMoved();
private:
QGraphicsProxyWidget* proxy;
QTableView* m_view;
QScrollBar* scrollbar;
bool m_isScrollMoving;
};
//SeekBar.cpp
#include <QBrush>
#include <QGraphicsScene>
#include "seekbar.h"
SeekBar::SeekBar(int width, QTableView* view, QGraphicsScene* scene) :
QGraphicsRectItem(nullptr),
proxy(new QGraphicsProxyWidget()),
m_view(view),
m_isScrollMoving(false)
{
proxy->setWidget(m_view);
scene->addItem(proxy);
setParentItem(proxy);
setFlag(QGraphicsItem::ItemIsMovable, true);
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
setBrush(Qt::red);
setRect(0, 0, width, m_view->height());
scrollbar = m_view->horizontalScrollBar();
connect(m_view->horizontalScrollBar(), &QScrollBar::sliderMoved, this, &SeekBar::scrollBarMoved);
}
QVariant SeekBar::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant& value)
{
if (change == QGraphicsItem::ItemPositionChange && !m_isScrollMoving)
{
QPointF p = value.toPointF();
qreal max = parentItem()->boundingRect().right() - boundingRect().right();
qreal min = parentItem()->boundingRect().left() - boundingRect().left();
if (p.x() > max)
{
p.setX(max);
}
else if (p.x() < min)
{
p.setX(min);
}
p.setY(pos().y());
float percentage = (p.x() - min) * 1.0 / (max - min);
int value = scrollbar->minimum() + percentage * (scrollbar->maximum() - scrollbar->minimum());
scrollbar->setValue(value);
return p;
}
else if (change == QGraphicsItem::ItemPositionChange && m_isScrollMoving)
{
QPointF p = value.toPointF();
qreal max = parentItem()->boundingRect().right() - boundingRect().right();
qreal min = parentItem()->boundingRect().left() - boundingRect().left();
setVisible(true);
if (p.x() > max)
{
hide();
}
else if (p.x() < min)
{
hide();
}
p.setY(pos().y());
return p;
}
return QGraphicsRectItem::itemChange(change, value);
}
void SeekBar::scrollBarMoved()
{
m_isScrollMoving = true;
int col = m_view->columnAt(pos().x());
setPos(m_view->columnViewportPosition(col), 0);
m_isScrollMoving = false;
}
//TableView.h
#include <QTableView>
class TableView : public QTableView
{
public:
TableView(QWidget* parent = nullptr);
};
//TableView.cpp
#include "tableview.h"
#include <QHeaderView>
#include <QStandardItemModel>
#include <QScrollBar>
TableView::TableView(QWidget* parent) : QTableView(parent)
{
QStandardItemModel* model = new QStandardItemModel(10, 10);
setModel(model);
verticalHeader()->hide();
horizontalHeader()->setHighlightSections(false);
setEditTriggers(QAbstractItemView::NoEditTriggers);
setSelectionMode(QAbstractItemView::MultiSelection);
setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
}
//main.cpp
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsProxyWidget>
#include "tableview.h"
#include "seekbar.h"
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
QGraphicsView view;
QGraphicsScene* scene = new QGraphicsScene;
view.setScene(scene);
TableView* table = new TableView;
SeekBar* seekBarItem = new SeekBar(5, table, scene);
view.resize(640, 480);
view.show();
return a.exec();
}
What do i want:
- I want to smoothly scroll the table view whenever i drag the seek bar using mouse but it should stay inside the view's boundaries.
- I want to keep the seek at a fixed position(column) while scrolling using the horizontal bar. But it should NOT have any boundaries i.e. while using scrollbar, the seek should be able to pass through the view or hide but should appear at the fixed position when scrolled back.
Seek at column 5
Horizontal bar scrolled a little bit to the right
Scrolled till the end of the view
Scrolled back to column 5
EDIT1: For instance, if the seek is at column 5, while scrolling using horizontal scroll bar it should stick to column 5 and should pass through the boundaries(or hide it when it hits the boundaries?). Seek should be visible whenever the column 5 is in the view while scrolling.
I would appreciate some ideas.