Qml 中的 QScrollArea:Flickable + QQuickPaintedItem [英] QScrollArea in Qml: Flickable + QQuickPaintedItem
问题描述
我试图在 Qml 的帮助下实现类似于 QScrollArea
(在小部件世界中)的东西.我决定探索基于 Flickable
和 QQuickPaintedItem
的项目(在我的例子中名为 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屋!