我试图在Qml的帮助下实现与QScrollArea
类似的东西(在小部件世界中)。
我决定调查基于Flickable
加QQuickPaintedItem
的项目(在我的案例中名为Drawer):
Flickable {
...
onContentXChanged(): {
drawer.update()
}
Drawer {
id: 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
内的Frame Buffer对象?
也许有更正确的方法在QML中实现QScrollArea
?
顺便说一句,默认情况下QQuickPaintedItem
启用了双缓冲吗?
使用Flickable
实施:
提供有关任务的更多信息:我有一个非常大的“图片”。所以我无法将它整个加载到内存中,但我必须使用像viewport这样的东西来浏览它。
答案 0 :(得分:2)
如果要将较大的内容封装在较小的区域中并在其中导航,则使用滚动区域或可滑动的区域。在你的情况下......不是这样的。您实际上并没有使用滚动区域,因为您的图像永远不会大于滚动区域大小,您只想伪造它,这实际上非常简单:
#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
}
}
}
这只是一个快速的基本示例,有很多空间可以进行润色和改进。另请注意,如果源rect的大小与目标rect不同,则可以轻松实现放大或缩小。您可以将其挂钩到一个可以轻弹的“动态滚动”而不是鼠标区域。