向 QTableWidget 添加水平滑块

Adding horizontal slider to QTableWidget

我正在尝试为我的视频播放器设计时间轴视图之类的东西。我决定使用 QTableWidget 作为时间轴,因为它符合我的目的。我的小部件如下所示:

我希望当我点击播放时绿线 运行 通过小部件。这是我的 MVCE 示例:

//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);
}

这里是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);
}

问题:

移动行项目反映了对其添加到的场景的更改,即当我使用鼠标拖动线时,线在场景中移动但不在 TableWidget 内移动。

我想要什么

我希望绿色条像水平滑块一样工作。它应该水平穿过 TableWidget,使小部件与其一起滚动,显示 header 上显示的数字指示的框架的当前位置。

如下图所示(注意红线):

我知道这可能不是实施时间表的最佳方式,但如果有任何其他实施想法,我将不胜感激。

一个可能的解决方案是重写 itemChange 方法来限制移动,如下所示:

#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();
}


更新:

#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();
}