向 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 添加水平滑块的主要内容,如果未能解决你的问题,请参考以下文章
PySide/PyQt4:向 QTableWidget Horizontal (column) Header 添加一个复选框