Qml 中的 QScrollArea:Flickable + QQuickPaintedItem [英] QScrollArea in Qml: Flickable + QQuickPaintedItem

查看:12
本文介绍了Qml 中的 QScrollArea:Flickable + QQuickPaintedItem的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在 Qml 的帮助下实现类似于 QScrollArea(在小部件世界中)的东西.我决定探索基于 FlickableQQuickPaintedItem 的项目(在我的例子中名为 Drawer):

I'm trying to realize something similiar to QScrollArea (in widgets world) with the help of Qml. I decided to probe Flickable plus QQuickPaintedItem based item (named Drawer in my case):

Flickable {
  ...
  onContentXChanged(): {
  drawer.update()
  }

Drawer {
  id: drawer
  ...
}

Drawer 的渲染目标设置为 FrameBufferObject.它的绘制函数如下所示:

Drawer's render target is set to FrameBufferObject. Its paint function looks like this:

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 做同样的事情.但是有些东西我看不懂:

Imagine how we do scrolling in QScrollArea widget, e.g. to left: all entry of viewport is shifted to right and the only small rect in left is redrawn. I want to do the same with Flickable+QQuickPaintedItem. But I can't understand some things:

如何在 QQuickPaintedItem 中操作 Frame Buffer 对象?也许有一些更正确的方法来在 QML 中实现 QScrollArea?

How can I manipulate Frame Buffer object inside QQuickPaintedItem? Maybe there is some more right way to implement QScrollArea in QML?

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

By the way, is double buffering enabled by default in QQuickPaintedItem?

使用 Flickable 实现:提供有关任务的更多信息:我有一个非常大的图片".所以我不能将它全部加载到内存中,但我必须使用视口之类的东西来浏览它.

For implementing with Flickable: To provide more info about task: I have a very big "picture". So I cannot load it whole into memory, but I have to navigate through it with something like viewport.

推荐答案

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

A scroll area or a flickable are used when you want to encapsulate a larger content in a smaller area and navigate around it. And in your case that is... not the case. You are not practically using a scroll area as your image is never larger than the scroll area size, you just want to fake it, which is actually quite easy:

#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;
};

在 QML 方面:

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
        }
    }
}

这只是一个简单的基本示例,还有很多改进和改进的空间.另请注意,如果源矩形与目标矩形大小不同,则可以轻松实现放大或缩小.您可以将其连接到一个 flickable 以获得动态滚动"而不是鼠标区域.

This is just a quick basic example, there is a lot of room to polish and improve. Also note that if the source rect is different size than the target rect, you can easily achieve zooming in or out. You can hook it to a flickable to get the "kinetic scrolling" instead of the mouse area.

这篇关于Qml 中的 QScrollArea:Flickable + QQuickPaintedItem的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆