gpt4 book ai didi

c++ - 在 QTableView 上绘制 QGraphicsLineItem

转载 作者:行者123 更新时间:2023-12-02 10:18:12 25 4
gpt4 key购买 nike

我有一个应用程序,我需要在 QTableView 上画线显示帧的范围。我有一个 QGraphicsViewQGraphicsScene其中包含 QTableView如下所示:

enter image description here

标准

  • 行的跨度应保持相对于列的位置,即第一行应始终保持在 3 到 7 之间,即使滚动出 View 也是如此。回滚时应该再次可见
  • 我想像在 QModelIndex 中那样检索行的起始索引和结束索引。
  • 行必须始终保持行宽的中心

  • 我特此创建了一个 MVCE

    主窗口.h
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H

    #include <QMainWindow>

    QT_BEGIN_NAMESPACE
    namespace Ui { class MainWindow; }
    QT_END_NAMESPACE

    class MainWindow : public QMainWindow
    {
    Q_OBJECT

    public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    private:
    Ui::MainWindow *ui;
    };
    #endif // MAINWINDOW_H

    主窗口.cpp
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include "timelineview.h"

    MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    {
    ui->setupUi(this);

    TimelineView* graphicsView = new TimelineView(this);
    setCentralWidget(graphicsView);
    }

    MainWindow::~MainWindow()
    {
    delete ui;
    }

    时间线 View .cpp
    // qt
    #include <QHeaderView>

    // local
    #include "timelineview.h"

    TimelineView::TimelineView(QWidget* parent) :
    QGraphicsView(parent),
    m_scene{new TimelineScene}
    {
    setScene(m_scene);

    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

    m_table = new QTableView;

    // settings for table view
    m_table->setSelectionMode(QAbstractItemView::NoSelection);
    m_table->setEditTriggers(QAbstractItemView::NoEditTriggers);
    m_table->verticalHeader()->hide();
    m_table->horizontalHeader()->setHighlightSections(false);

    m_tableModel = new QStandardItemModel(10, 100, m_table);
    m_table->setModel(m_tableModel);

    m_scene->addWidget(m_table);

    setMouseTracking(true);
    }


    void TimelineView::resizeEvent(QResizeEvent* event)
    {
    m_scene->setSceneRect(0, 0, width(), height());
    m_table->setGeometry(m_scene->sceneRect().toRect());
    fitInView(m_scene->sceneRect(), Qt::KeepAspectRatioByExpanding);
    QGraphicsView::resizeEvent(event);
    }

    时间线 View .h
    #ifndef TIMELINEVIEW_H
    #define TIMELINEVIEW_H

    // qt
    #include <QGraphicsView>
    #include <QTableView>
    #include <QStandardItemModel>

    // local
    #include "timelinescene.h"

    class TimelineView : public QGraphicsView
    {
    public:

    explicit TimelineView(QWidget* parent = nullptr);

    protected:

    virtual void resizeEvent(QResizeEvent* event) override;

    private:

    QTableView* m_table;
    QStandardItemModel* m_tableModel;
    TimelineScene* m_scene;
    };

    #endif // TIMELINEVIEW_H

    时间线场景.cpp
    #include "timelinescene.h"

    TimelineScene::TimelineScene(QObject* parent) :
    QGraphicsScene(parent)
    , m_lineItem{nullptr}
    , m_isPressed{false}
    {

    }



    void TimelineScene::mousePressEvent(QGraphicsSceneMouseEvent* event)
    {
    if(event->button() == Qt::LeftButton)
    {
    m_origPoint = event->scenePos();
    m_isPressed = true;
    }

    QGraphicsScene::mousePressEvent(event);
    }



    void TimelineScene::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
    {
    if(m_isPressed)
    {
    if(m_lineItem == nullptr)
    {
    // create a pen for the line to be drawn
    QPen pen;
    pen.setStyle(Qt::SolidLine);
    pen.setBrush(QColor(255, 102, 0));
    pen.setWidth(8);

    m_lineItem = new QGraphicsLineItem(m_origPoint.x(), m_origPoint.y(), event->scenePos().x(), event->scenePos().y());

    // set the pen
    m_lineItem->setPen(pen);

    // add the item to the scene
    addItem(m_lineItem);
    }

    m_lineItem->setLine(m_origPoint.x(), m_origPoint.y(), event->scenePos().x(), m_origPoint.y());

    update();
    }

    QGraphicsScene::mouseMoveEvent(event);
    }



    void TimelineScene::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
    {
    m_lineItem = nullptr;
    m_isPressed = false;

    QGraphicsScene::mouseReleaseEvent(event);
    }

    时间线场景.h
    #ifndef TIMELINESCENE_H
    #define TIMELINESCENE_H

    // qt
    #include <QGraphicsScene>
    #include <QObject>
    #include <QGraphicsSceneMouseEvent>
    #include <QGraphicsLineItem>
    #include <QPointF>



    class TimelineScene : public QGraphicsScene
    {
    public:

    explicit TimelineScene(QObject* parent = nullptr);

    protected:

    virtual void mousePressEvent(QGraphicsSceneMouseEvent* event) override;
    virtual void mouseMoveEvent(QGraphicsSceneMouseEvent* event) override;
    virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent* event) override;

    private:

    QGraphicsLineItem* m_lineItem;
    QPointF m_origPoint;
    bool m_isPressed;
    };

    #endif // TIMELINESCENE_H

    问题:
  • 我无法获得单元格的索引,即根据 QModelIndex
  • 说明和结束行的点
  • 我什至可以在 QHeaderView 上画线以及QScrollbar .我知道这样做的原因是因为整个 Canvas 是一个场景,我可以在任何地方绘制。但我只想将绘图限制在表格的单元格

  • 我知道如果我能找到一种方法来检索有关底层 QTableView 的信息,我就可以处理所有这些问题。但不确定如何。

    最佳答案

    如前所述,使用委托(delegate)是正确的方法。

    如果由于某种原因不可能,我强烈建议您不要以这种方式将模型 View 与图形场景混合。

    如果绝对不可能使用委托(delegate),我会考虑在 QTableView 上画线。 — 它具有通过像素坐标访问模型索引的 API,它确实知道它的滚动位置,并且它确实具有用于所有必要用户输入的处理程序。所以你所要做的就是存储 QLine 的集合。在派生自 QTableView 的类中并通过 QPainter 绘制适合当前视口(viewport)的线条.
    恐怕即使“覆盖”与 QGraphicsScene现在看起来像是最简单的解决方案,在坚果中,它有很多与用户输入处理/路由相关的问题。这绝对不是 Qt 方式。

    UPD:基于委托(delegate)的样本:

    这个想法很简单:

  • 整行是段的集合——每个单元格都是
    分割;
  • 对于每个单元格,映射线 startend x坐标为
    范围 [0.0;1.0];
  • 将映射坐标存储在模型本身中。

  • 然后您可以按如下方式绘制自定义委托(delegate):
    void LineDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
    QStyledItemDelegate::paint(painter, option, index);

    const QVariant &lineData = index.data(Line::DataRole);
    if (lineData.isValid() && lineData.canConvert<Line>()) {
    const Line &line = lineData.value<Line>();
    const QLineF &lineF = line.toQLine(option.rect);
    painter->save();

    painter->setPen(m_linePen);
    painter->drawLine(lineF);

    painter->restore();
    }
    }

    鼠标处理有点棘手:
    bool LineDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
    const QModelIndex &index)
    {
    switch (event->type()) {
    case QEvent::MouseButtonPress:
    handleMousePress(static_cast<QMouseEvent *>(event), model, option, index);
    break;
    case QEvent::MouseMove:
    handleMouseMove(static_cast<QMouseEvent *>(event), model, option, index);
    break;
    case QEvent::MouseButtonRelease:
    handleMouseRelease(static_cast<QMouseEvent *>(event), model, option, index);
    break;
    default:
    break;
    }

    return QStyledItemDelegate::editorEvent(event, model, option, index);
    }

    void LineDelegate::handleMousePress(QMouseEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
    const QModelIndex &index)
    {
    Q_UNUSED(event);
    Q_UNUSED(model);

    if (index.isValid()) {
    m_startIndex = index;
    m_startPoint = { event->x() - option.rect.x(), option.rect.center().y() };
    }
    }

    void LineDelegate::handleMouseMove(QMouseEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
    const QModelIndex &index)
    {
    const QPoint endPoint = { event->x() - option.rect.x(), option.rect.center().y() };
    if (m_startIndex != index) {
    m_startIndex = index;
    m_startPoint = endPoint;
    }

    const Line &line = Line::fromQLine({ m_startPoint, endPoint }, option.rect);

    model->setData(index, QVariant::fromValue(line), Line::DataRole);
    }

    void LineDelegate::handleMouseRelease(QMouseEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
    const QModelIndex &index)
    {
    Q_UNUSED(event);
    Q_UNUSED(model);
    Q_UNUSED(option);
    Q_UNUSED(index);

    m_startIndex = QModelIndex();
    m_startPoint = { -1, -1 };
    }

    这是它的样子:

    screencast

    上面示例的完整代码可在 github 上获得。

    请注意——这只是一个简短的原型(prototype)。不支持从右到左的鼠标移动,也不仅限于当前行等。但我希望这应该足以让你开始。

    关于c++ - 在 QTableView 上绘制 QGraphicsLineItem,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61216527/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com