38001

Adding horizontal slider to QTableWidget

Question:

I am trying to design something like a timeline view for my video player. I decided to use QTableWidget as the timeline since it suits my purpose. My widget looks like this:

<a href="https://i.stack.imgur.com/AB06p.jpg" rel="nofollow"><img alt="enter image description here" class="b-lazy" data-src="https://i.stack.imgur.com/AB06p.jpg" data-original="https://i.stack.imgur.com/AB06p.jpg" src="https://etrip.eimg.top/images/2019/05/07/timg.gif" /></a>

I want the green line to run through the widget when i click on play. Here is my MVCE example:

//View.cpp View::View(QWidget* parent) : QGraphicsView(parent) { QGraphicsScene* scene = new QGraphicsScene(this); TableWidget* wgt = new TableWidget; scene->addWidget(wgt); QGraphicsLineItem* item = new QGraphicsLineItem(30, 12, 30, wgt->height() - 9); item->setPen(QPen(QBrush(Qt::green), 3)); item->setFlags(QGraphicsItem::ItemIsMovable); scene->addItem(item); setScene(scene); }

Here is TableWidget

TableWidget::TableWidget(QWidget* parent) : QTableWidget(parent) { setColumnCount(10); setRowCount(10); //Hides the numbers on the left side of the table verticalHeader()->hide(); //Prevents top header from highlighting on selection horizontalHeader()->setHighlightSections(false); //Makes the cells un-editable setEditTriggers(QAbstractItemView::NoEditTriggers); setSelectionMode(QAbstractItemView::MultiSelection); }

<strong>Problem:</strong>

Moving the line item reflects changes to the scene it has been added to i.e. when i drag the line using mouse, the line moves in the scene but not inside the TableWidget.

<strong>What do i want</strong>

I want the green bar to act like a horizontal slider. It should go through the TableWidget horizontally making the widget scroll along with it showing the current position of the frame indicated by the numbers shown on the header.

Something like as shown below (notice the Red line):

<a href="https://i.stack.imgur.com/dOplo.png" rel="nofollow"><img alt="The Red line" class="b-lazy" data-src="https://i.stack.imgur.com/dOplo.png" data-original="https://i.stack.imgur.com/dOplo.png" src="https://etrip.eimg.top/images/2019/05/07/timg.gif" /></a>

I know this might not be the best way to implement a timeline but i would appreciate any other ideas to implement.

Answer1:

A possible solution is to overwrite the itemChange method to restrict movement as shown below:

#include <QApplication> #include <QGraphicsRectItem> #include <QGraphicsView> #include <QTableWidget> #include <QHeaderView> #include <QGraphicsProxyWidget> class SeekBarItem: public QGraphicsRectItem{ public: SeekBarItem(QRectF rect, QGraphicsItem *parent=nullptr) : QGraphicsRectItem(rect, parent) { setFlag(QGraphicsItem::ItemIsMovable, true); setFlag(QGraphicsItem::ItemSendsGeometryChanges, true); setBrush(Qt::red); } protected: QVariant itemChange(GraphicsItemChange change, const QVariant &value){ if(change == QGraphicsItem::ItemPositionChange){ QPointF p = value.toPointF(); qreal max = parentItem()->boundingRect().bottom()- boundingRect().bottom(); qreal min = parentItem()->boundingRect().top()-boundingRect().top(); if(p.y() > max) p.setY(max); else if (p.y() < min) p.setY(min); p.setX(pos().x()); return p; } return QGraphicsRectItem::itemChange(change, value); } }; class TableWidget: public QTableWidget { public: TableWidget(QWidget* parent=nullptr) : QTableWidget(10, 10, parent) { verticalHeader()->hide(); horizontalHeader()->setHighlightSections(false); setEditTriggers(QAbstractItemView::NoEditTriggers); setSelectionMode(QAbstractItemView::MultiSelection); } }; int main(int argc, char *argv[]) { QApplication a(argc, argv); QGraphicsView view; QGraphicsScene *scene = new QGraphicsScene; view.setScene(scene); QGraphicsProxyWidget *proxy = scene->addWidget(new TableWidget); QGraphicsRectItem *it = new QGraphicsRectItem(QRectF(0, 0, 10, proxy->boundingRect().height()), proxy); it->setBrush(Qt::green); SeekBarItem *seekBarItem = new SeekBarItem(QRectF(-5, 0, 20, 50)); seekBarItem->setParentItem(it); view.resize(640, 480); view.show(); return a.exec(); }

<a href="https://i.stack.imgur.com/hpFW3.png" rel="nofollow"><img alt="enter image description here" class="b-lazy" data-src="https://i.stack.imgur.com/hpFW3.png" data-original="https://i.stack.imgur.com/hpFW3.png" src="https://etrip.eimg.top/images/2019/05/07/timg.gif" /></a>

<a href="https://i.stack.imgur.com/pkWBg.png" rel="nofollow"><img alt="enter image description here" class="b-lazy" data-src="https://i.stack.imgur.com/pkWBg.png" data-original="https://i.stack.imgur.com/pkWBg.png" src="https://etrip.eimg.top/images/2019/05/07/timg.gif" /></a>

<a href="https://i.stack.imgur.com/97O66.png" rel="nofollow"><img alt="enter image description here" class="b-lazy" data-src="https://i.stack.imgur.com/97O66.png" data-original="https://i.stack.imgur.com/97O66.png" src="https://etrip.eimg.top/images/2019/05/07/timg.gif" /></a>

<hr />

<strong>Update:</strong>

#include <QApplication> #include <QGraphicsRectItem> #include <QGraphicsView> #include <QTableWidget> #include <QHeaderView> #include <QGraphicsProxyWidget> #include <QScrollBar> class TableWidget: public QTableWidget { public: TableWidget(QWidget* parent=nullptr) : QTableWidget(10, 10, parent) { verticalHeader()->hide(); horizontalHeader()->setHighlightSections(false); setEditTriggers(QAbstractItemView::NoEditTriggers); setSelectionMode(QAbstractItemView::MultiSelection); setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); } }; class SeekBarItem: public QGraphicsRectItem{ public: SeekBarItem(int width, QAbstractItemView *view, QGraphicsScene *scene) : QGraphicsRectItem(nullptr), proxy(new QGraphicsProxyWidget()), m_view(view) { 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(); } protected: QVariant itemChange(GraphicsItemChange change, const QVariant &value){ if(change == QGraphicsItem::ItemPositionChange){ 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; } return QGraphicsRectItem::itemChange(change, value); } private: QGraphicsProxyWidget *proxy; QAbstractItemView *m_view; QScrollBar *scrollbar; }; int main(int argc, char *argv[]) { QApplication a(argc, argv); QGraphicsView view; QGraphicsScene *scene = new QGraphicsScene; view.setScene(scene); TableWidget *table = new TableWidget; SeekBarItem *seekBarItem = new SeekBarItem(15, table, scene); view.resize(640, 480); view.show(); return a.exec(); }

<a href="https://i.stack.imgur.com/NQBDT.png" rel="nofollow"><img alt="enter image description here" class="b-lazy" data-src="https://i.stack.imgur.com/NQBDT.png" data-original="https://i.stack.imgur.com/NQBDT.png" src="https://etrip.eimg.top/images/2019/05/07/timg.gif" /></a>

<a href="https://i.stack.imgur.com/J41fq.png" rel="nofollow"><img alt="enter image description here" class="b-lazy" data-src="https://i.stack.imgur.com/J41fq.png" data-original="https://i.stack.imgur.com/J41fq.png" src="https://etrip.eimg.top/images/2019/05/07/timg.gif" /></a>

<a href="https://i.stack.imgur.com/rR30m.png" rel="nofollow"><img alt="enter image description here" class="b-lazy" data-src="https://i.stack.imgur.com/rR30m.png" data-original="https://i.stack.imgur.com/rR30m.png" src="https://etrip.eimg.top/images/2019/05/07/timg.gif" /></a>

Recommend

  • VueJS: How to scroll v-list-title
  • mapStateToProps doesn't change state
  • Accessing an attribute on a configSection in a web.config?
  • Efficient way of finding Primes
  • Python ncurses: Doesn't show screen until first key-press, even though refresh is first
  • Make gcc the default compiler of make
  • Javers default ignore instead of default include
  • ? x : y, what is the meaning of that?
  • ng-focus and ng-blur do not work on select DOM
  • Are random seeds compatible between systems?
  • How to use 2 instances of Axios with different baseURL in the same app (vue.js)
  • Javascript datetime string to Date object
  • findViewById in non-Activity class
  • transparency issues with repeated stamping of textures on an MTKView
  • Docker. Assign IP from the same range as Host
  • iOS screenshot live camera preview
  • problems using replaceText for special characters: [ ]
  • Find text in file and set it as a variable. Batch file
  • How to store model in `.pb` file with Estimator in TensorFlow?
  • Can Azure AD ADAL (ios) refresh token be revoked from the client?
  • Was default_marker removed from mapbox-gl.js
  • Read attribute/value pairs from XML file using Linq
  • java outlook send mail
  • JSF with Enum 'Validation Error: Value is not valid'
  • Limit number of button clicks
  • Joining across databases with dbplyr
  • Hibernate Idempotent Update
  • Move elements from a listbox to another
  • Get max bookings count in range
  • MVC3 Extension for ValidatorMessage
  • Filtering out choiceless polls in the Django tutorial causes polls in the index to duplicate
  • How do you run a synchronous timer in C#?
  • Allowing audio files in Spring MVC 3.0?
  • JQuery Mobile Ajax Navigation in Single-Page Template
  • Java Collections.shuffle() weird behaviour [closed]
  • VS2010 RDLC C#. How can I set a LocalReport object to a ReportViewer?
  • Comparing variables with strings bash