【问题标题】:Qt add many QGraphicsPixmapItem to a QGraphicsSceneQt 将许多 QGraphicsPixmapItem 添加到 QGraphicsScene
【发布时间】:2020-02-04 14:21:33
【问题描述】:

我正在尝试像大多数照片编辑器程序 (Photoshop) 一样创建一个图层系统,我基本上是使用 QGraphicsPixmapItem::setPixmap(QPixmap *image); 绘制单个 QGraphicsPixmapItem。在 QGraphicsScene 上。我怎么能这样做,但我可以添加许多 QPixmap 并随意删除它们。我尝试创建 QPixmaps 列表和 QGraphicsPixmapItems 之一,但如果我删除或重新排列 QPixmaps 的顺序会变得混乱有没有更好的方法来做到这一点?

QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(draw())); //calls the function below to redraw sc
timer->start(30);

这会每 30 毫秒更新一次 GraphicsScene,因此我在 pixmap *image 上所做的任何绘图都会被绘制,但现在我想获取一个 QPixmap 列表,并在每次调用 draw() 时将它们添加到场景中,但问题是我需要一个QGraphicsPixmapItems 列表,如果我删除图层或移动它们的顺序,我希望关联的 QGraphicsPixmapItem 也被删除/移动。我想我可以做到这一点,但它似乎很复杂,所以有什么建议吗?

void PaintArea::draw()
{
    m_item->setPixmap(*image); //Do this but call layerManager.getListOfLayers() and add each to the scene
}

【问题讨论】:

  • 您是否尝试过使用QGraphicsItemGroupHere's its documentation if you want to take a look.如果我理解正确你的问题,你只需要将它们分组,并影响整个组的层。
  • 无法在 5 分钟内编辑最后一条评论,所以在这里。使用QGraphicsScene::destroyItemGroup 删除组。在整个项目组上使用QGraphicsItem::setPos 将其集体移动。 (记住 QGraphicsItemGroup 继承 QGraphicsItem)

标签: c++ qt qgraphicsscene qgraphicsitem qpixmap


【解决方案1】:

以下小示例应用程序展示了您可以如何进行操作。基本上,有两个模型和两个视图。模型是 QGraphicsScene 和标准 QStandardItemModel,而视图是 QListView 和 QGraphicsView。

主要任务是通过使用信号和槽使两个模型保持同步。

可以使用添加按钮和上下文菜单修改模型。对于这个小应用程序,只能添加、删除和更改像素图的图片。添加其他操作(例如通过拖放移动项目)以及使用可检查操作和其他自定义用户角色隐藏/可见它们非常简单。

#include <QApplication>
#include <QFileDialog>
#include <QGraphicsPixmapItem>
#include <QGraphicsView>
#include <QHBoxLayout>
#include <QListView>
#include <QMenu>
#include <QPushButton>
#include <QStandardItemModel>

int main(int argc, char* argv[]) {
    QApplication app(argc, argv);
    auto frame = new QFrame;
    frame->setLayout(new QHBoxLayout);
    auto listView = new QListView;
    frame->layout()->addWidget(listView);
    auto graphicsView = new QGraphicsView;
    frame->layout()->addWidget(graphicsView);
    auto graphicsScene = new QGraphicsScene;
    graphicsView->setScene(graphicsScene);
    auto myModel = new QStandardItemModel;
    auto btnAdd = new QPushButton("Add");
    frame->layout()->addWidget(btnAdd);
    QObject::connect(btnAdd, &QPushButton::clicked, [&]() {
        auto item = new QStandardItem("Pixmap");
        item->setData(QString("./data/test.png"), Qt::ItemDataRole::UserRole + 1);
        myModel->appendRow(item);
    });
    listView->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu);

    QObject::connect(listView, &QListView::customContextMenuRequested, [&](const QPoint& pos) {
        auto index = listView->indexAt(pos);
        QMenu menu;

        auto remove = menu.addAction("Remove", [&]() {
            myModel->removeRow(index.row(), index.parent());
            });
        if (!index.isValid()) remove->setEnabled(false);

        auto changeImage = menu.addAction("Change...", [&]() {
            auto file=QFileDialog::getOpenFileName(frame, "Select PNG file", "./data/", "(*.png)");
            if (file.isEmpty()) return;
            myModel->setData(index,  file, Qt::ItemDataRole::UserRole + 1);
        });
        if (!index.isValid()) changeImage->setEnabled(false);

        menu.exec(listView->mapToGlobal(pos));
    });

    QObject::connect(myModel, &QStandardItemModel::dataChanged, [&](const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles = QVector<int>()) {
        if (auto item = myModel->itemFromIndex(topLeft)) {
            if (auto pixItem = dynamic_cast<QGraphicsPixmapItem*>(graphicsScene->items()[topLeft.row()])) {
                pixItem->setPixmap(QPixmap(item->data(Qt::ItemDataRole::UserRole + 1).toString()));
            }
        }
    });
    QObject::connect(myModel, &QStandardItemModel::rowsInserted, [&](const QModelIndex& parent, int first, int last) {
        for (auto iter = first; iter <= last; iter++) {
            auto index=myModel->index(iter, 0, parent);
            auto pixmap=myModel->data(index, Qt::ItemDataRole::UserRole + 1).toString();;
            auto item=graphicsScene->addPixmap(QPixmap(pixmap));
        }
    });

    QObject::connect(myModel, &QStandardItemModel::rowsRemoved, [&](const QModelIndex& parent, int first, int last) {
        auto items = graphicsScene->items();
        for (auto iter = first; iter <= last; iter++) {
            graphicsScene->removeItem(items[iter]);
        }
    });

    listView->setModel(myModel);
    frame->show();
    return app.exec();
}

【讨论】:

    【解决方案2】:

    头文件:

    ...
    QGraphicsScene *scene; QGraphicsItemGroup *itemGroup; 
    ...
    

    .cpp 文件:

    void PaintArea::draw()
    {
        m_item->setPixmap(*image); m_item->setGroup(itemGroup); // Layers-related code
    }
    
    void PaintArea::deleteGroup(QGraphicsItemGroup *group)
    {
        scene->destroyItemGroup(group); // Layers-related code
    }
    

    【讨论】:

    • 啊,好的,谢谢你,我不知道我会在每次抽奖时摧毁这个组吗?
    • @jameskerr 抱歉延迟回复。不,当您想同时删除/删除所有组时,您会销毁组。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-24
    • 1970-01-01
    相关资源
    最近更新 更多