向 QTableWidget 添加水平滑块

Posted

技术标签:

【中文标题】向 QTableWidget 添加水平滑块【英文标题】:Adding horizontal slider to QTableWidget 【发布时间】:2018-07-09 14:36:37 【问题描述】:

我正在尝试为我的视频播放器设计类似时间线视图的东西。我决定使用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,使小部件随之滚动,显示由标题上显示的数字指示的框架的当前位置。

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

我知道这可能不是实现时间线的最佳方式,但我希望有任何其他想法可以实现。

【问题讨论】:

我希望绿线穿过小部件是什么意思?,,你可以更好地解释我,我什么都不懂,你想成为完成了那条线。 我希望它成为我的搜索栏或 QSlider。就像当我播放视频流时,它应该通过使 tablewidget 滚动的小部件运行。此外,我应该可以使用鼠标在视频中来回移动它。 好的,现在我明白了,为什么那条线的高度与 Qtablewidget 相似?我认为您应该在上方有另一个矩形表示前进。 好的。是的,我可以在行首添加一些东西,使它看起来像一个搜索栏。 我不会把这部分作为 QGraphicsScene 的一部分。相反,我会将 QTableView 子类化并将其放在预览旁边的布局中。子类 (TimelineView) 将处理播放头的 I/O 和绘画。移动播放头应该发出一个信号 (playheadChanged),并且预览区域应该连接到这个信号并通过改变它的当前帧来响应。这种设计将简化播放头 imo 的大部分编程。 【参考方案1】:

一种可能的解决方案是覆盖 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();

【讨论】:

制作精美!我知道我的问题的框架很糟糕,但我需要整个东西(头部和条形图)在小部件内水平移动,使小部件与条形一起水平滚动,显示由标题中显示的数字指示的框架位置. @MarKS plop,请编辑您的问题并在您的问题中添加此信息。 编辑了问题。 这真是太棒了!正是我需要的。谢谢@eyllanesc。希望它也能帮助其他人。

以上是关于向 QTableWidget 添加水平滑块的主要内容,如果未能解决你的问题,请参考以下文章

QTableWidget

PySide/PyQt4:向 QTableWidget Horizo​​ntal (column) Header 添加一个复选框

如何向现有 QTableWidget 添加新行?

如何更改水平标题的高度(QTableWidget)

VS Code 的 Jupyter 扩展的最新版本中缺少水平滑块

QTableWidget设置代理 添加QCombox