Qt Qml中的qscrollara:Flickable+;QQuickPaintedItem

Qt Qml中的qscrollara:Flickable+;QQuickPaintedItem,qt,qml,qt-quick,qscrollarea,Qt,Qml,Qt Quick,Qscrollarea,在Qml的帮助下,我正在尝试实现类似于qscrolrea(在widgets世界中)的东西。 我决定探索基于FlickableplusQQuickPaintedItem的项目(在我的案例中命名为Drawer): 抽屉的渲染目标设置为FrameBufferObject。其绘制功能如下所示: void Drawer::paint(QPainter *painter) { // Some function to compute rect which is needed to be redrawn

在Qml的帮助下,我正在尝试实现类似于
qscrolrea
(在widgets世界中)的东西。
我决定探索基于
Flickable
plus
QQuickPaintedItem
的项目(在我的案例中命名为Drawer):

抽屉的渲染目标设置为
FrameBufferObject
。其绘制功能如下所示:

void Drawer::paint(QPainter *painter)
{
   // Some function to compute rect which is needed to be redrawn
   QRect updateRect = computeUpdateRect();

   // How to shift contents of Frame buffer, e.g. to right, and draw only updateRect in this space?
}
想象一下我们如何在
QScrollArea
小部件中滚动,例如向左:视口的所有条目都向右移动,左侧唯一的小矩形被重新绘制。
我想对Flickable+
QQuickPaintedItem
执行同样的操作。但有些事情我不明白:


如何操作
QQuickPaintedItem
中的帧缓冲区对象? 也许有更正确的方法在QML中实现
qscrolrea


顺便问一下,
QQuickPaintedItem
中是否默认启用了双缓冲

对于使用Flickable实现的


提供更多关于任务的信息:我有一个非常大的“图景”。因此,我无法将其全部加载到内存中,但我必须使用类似于“视口”的工具在其中导航。

当您想要将较大的内容封装在较小的区域中并在其中导航时,可以使用滚动区域或flickable。你的情况是。。。事实并非如此。实际上,您并没有使用滚动区域,因为您的图像永远不会大于滚动区域的大小,您只是想伪造它,这其实很容易:

#include <QQuickPaintedItem>
#include <QImage>
#include <QPainter>

class PImage : public QQuickPaintedItem {
    Q_OBJECT
public:
    PImage(QQuickItem * p = 0) : QQuickPaintedItem(p), xpos(0), ypos(0) {}
    void paint(QPainter *painter) {
        if (!source.isNull()) painter->drawImage(QRect(0, 0, width(), height()), source, QRect(xpos, ypos, width(), height()));
        else painter->fillRect(QRect(0, 0, width(), height()), Qt::black);
    }
public slots:
    bool load(QString path) {
        source = QImage(path);
        return !source.isNull();
    }
    void moveBy(int x, int y) {
        int ox, oy;
        // don't go outside the image
        ox = x + xpos + width() <= source.width() ? x + xpos : source.width() - width();
        oy = y + ypos + height() <= source.height() ? y + ypos : source.height() - height();
        if (ox < 0) ox = 0;
        if (oy < 0) oy = 0;
        if (ox != xpos || oy != ypos) {
            xpos = ox;
            ypos = oy;
            update();
        }
    }
private:
    QImage source;
    int xpos, ypos;
};

这只是一个简单的例子,还有很多地方需要改进和完善。还要注意,如果源矩形与目标矩形的大小不同,则可以轻松实现放大或缩小。您可以将其挂接到flickable,以获得“动态滚动”,而不是鼠标区域。

QQuickPaintedItem
QPainter
一起使用。就速度而言,这不是最好的主意,因此我建议您使用
QQuickItem
并直接使用OpenGL。无论如何,如果您使用
QQuickPaintedItem
您可以设置
QQuickPaintedItem::setRenderTarget(QQuickPaintedItem::FramebufferObject)
,因此QPainter使用GL绘制引擎(来自Qt文档)绘制到QopenginelFramebufferobject@folibis感谢您的响应,您知道是否有一种手动操作此帧缓冲区的方法,或者它只能通过QPaint界面访问?我还没有在文档中找到关于它的信息。添加了关于任务的信息:我有一个非常大的“图片”。所以我不能将它全部加载到内存中,但我必须使用类似于viewport的东西来浏览它。那么
qscrolrea
与它有什么关系呢?它不支持部分图像加载。这幅画有多大?图片是什么格式的?它甚至支持部分加载吗?感谢您的回复,我所说的“图片”是指一个可伸缩的画布(大小可能超过10000 x 10000 px),其中的一部分可以动态绘制。一个10k x 10k RGBA图像只需要380 MB的ram。此外,如果它是画布,那么它无论如何都会在ram中。你想做什么还不清楚。如果您只需要绘制一个较大图像的矩形区域,那么只需使用
void qpaint::drawImage(const QRect&rectangle,const QImage&image)
@Sas-不要担心过早优化。只有在确定确实存在性能问题后才能执行此操作。场景图本身可能使用双缓冲。考虑将操作从主线程卸载到工作线程,以保持主线程响应。
#include <QQuickPaintedItem>
#include <QImage>
#include <QPainter>

class PImage : public QQuickPaintedItem {
    Q_OBJECT
public:
    PImage(QQuickItem * p = 0) : QQuickPaintedItem(p), xpos(0), ypos(0) {}
    void paint(QPainter *painter) {
        if (!source.isNull()) painter->drawImage(QRect(0, 0, width(), height()), source, QRect(xpos, ypos, width(), height()));
        else painter->fillRect(QRect(0, 0, width(), height()), Qt::black);
    }
public slots:
    bool load(QString path) {
        source = QImage(path);
        return !source.isNull();
    }
    void moveBy(int x, int y) {
        int ox, oy;
        // don't go outside the image
        ox = x + xpos + width() <= source.width() ? x + xpos : source.width() - width();
        oy = y + ypos + height() <= source.height() ? y + ypos : source.height() - height();
        if (ox < 0) ox = 0;
        if (oy < 0) oy = 0;
        if (ox != xpos || oy != ypos) {
            xpos = ox;
            ypos = oy;
            update();
        }
    }
private:
    QImage source;
    int xpos, ypos;
};
PImage {
    width: 300
    height: 300
    Component.onCompleted: load("d:/img.jpg") // a big image
    MouseArea {
        property int ix
        property int iy
        anchors.fill: parent
        onPressed: {
            ix = mouseX
            iy = mouseY
        }
        onPositionChanged: {
            parent.moveBy(ix - mouseX, iy - mouseY)
            ix = mouseX
            iy = mouseY
        }
    }
}