我想以编程方式向左/向右滚动一个场景,但我不确定如何正确地做到这一点。请注意,我不想要(可见)滚动条。
我使用标准QGraphicsView
+ QGraphicsScene
+ QGraphicsItem
设置。我已将其缩小到最小,在场景中只有一个QGraphicsItem
(一个QGraphicsRectItem
)。
通过设置我的视图,我设法实现了程序化滚动:
// view setup
view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
然后,在代码的另一部分:
// programmatic scrolling
QScrollBar* const sb = view->horizontalScrollBar();
sb->setRange(0, 1000); // some values for experimenting
sb->setValue(sb->value() + 100 or -100); // some increment for experimenting
这很有效,但是......滚动浏览隐形滚动条感觉不对。
我尝试了这种更简单的方法:
// programmatic scrolling - doesn't quite work
view->viewport()->scroll(100 or -100, 0); // some increment for experimenting
此代码会滚动,但当矩形离开视图的左边缘时,我会反转滚动方向(在调用100
时,增量从-100
更改为scroll()
}),矩形的未覆盖部分不重新绘制。原因是在这种情况下不调用QGraphicsRectItem::paint()
(使用滚动条方法时调用它)。
那么,有没有办法让viewport()->scroll()
工作?或者其他一些简单的方法来实现程序化滚动?或者人工滚动条方法是否可行?
答案 0 :(得分:0)
尝试使用QGraphicsView::translate()
或QGraphicsView::setTransform()
更改视图转换。
但请记住,您无法将视口移动到场景“外部”,因此请确保您的场景矩形足够大。
答案 1 :(得分:0)
如果我的问题正确,那么有一个dojo类库,其中包含PanWebView这样的类,它允许QWebView使用鼠标平滑滚动而不需要任何滚动条。 Take a look at sources。它支持平移,可以适用于移动应用程序,但也许它也可以为您提供帮助。
PanWebView类看起来像这样
#include <QWebView>
#include <QWebFrame>
#include <QMouseEvent>
#include <QApplication>
class PanWebView : public QWebView
{
Q_OBJECT
private:
bool pressed;
bool scrolling;
QPoint position;
QPoint offset;
QList<QEvent*> ignored;
public:
PanWebView(QWidget *parent = 0): QWebView(parent), pressed(false), scrolling(false) {
QWebFrame *frame = page()->mainFrame();
frame->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
frame->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
}
protected:
void mousePressEvent(QMouseEvent *mouseEvent) {
if (ignored.removeAll(mouseEvent))
return QWebView::mousePressEvent(mouseEvent);
if (!pressed && !scrolling && mouseEvent->modifiers() == Qt::NoModifier)
if (mouseEvent->buttons() == Qt::LeftButton) {
pressed = true;
scrolling = false;
position = mouseEvent->pos();
QWebFrame *frame = page()->mainFrame();
int x = frame->evaluateJavaScript("window.scrollX").toInt();
int y = frame->evaluateJavaScript("window.scrollY").toInt();
offset = QPoint(x, y);
QApplication::setOverrideCursor(Qt::OpenHandCursor);
return;
}
return QWebView::mousePressEvent(mouseEvent);
}
void mouseReleaseEvent(QMouseEvent *mouseEvent) {
if (ignored.removeAll(mouseEvent))
return QWebView::mouseReleaseEvent(mouseEvent);
if (scrolling) {
pressed = false;
scrolling = false;
QApplication::restoreOverrideCursor();
return;
}
if (pressed) {
pressed = false;
scrolling = false;
QMouseEvent *event1 = new QMouseEvent(QEvent::MouseButtonPress,
position, Qt::LeftButton,
Qt::LeftButton, Qt::NoModifier);
QMouseEvent *event2 = new QMouseEvent(*mouseEvent);
ignored << event1;
ignored << event2;
QApplication::postEvent(this, event1);
QApplication::postEvent(this, event2);
QApplication::restoreOverrideCursor();
return;
}
return QWebView::mouseReleaseEvent(mouseEvent);
}
void mouseMoveEvent(QMouseEvent *mouseEvent) {
if (scrolling) {
QPoint delta = mouseEvent->pos() - position;
QPoint p = offset - delta;
QWebFrame *frame = page()->mainFrame();
frame- >evaluateJavaScript(QString("window.scrollTo(%1,%2);").arg(p.x()).arg(p.y()));
return;
}
if (pressed) {
pressed = false;
scrolling = true;
return;
}
return QWebView::mouseMoveEvent(mouseEvent);
}
};
用法:
PanWebView web;
web.setUrl(QUrl("http://news.google.com"));
web.setWindowTitle("Web View - use mouse to drag and pan around");
web.show();
答案 2 :(得分:0)
移动视图假定它比场景小。如果它们的大小相同,则不会移动。
QGraphicsView
可以设置为场景坐标中任意位置的centerOn。使用计时器调用centerOn
一次移动视图一次。
这是一个有效的例子: -
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QTimer>
class MyView : public QGraphicsView
{
private:
public:
MyView(QGraphicsScene* pScene)
: QGraphicsView(pScene, NULL)
{}
void AnimateBy(int x)
{
float updateFrequency = (1000/30.0); // ~30 frames per second
QPointF currScenePos = sceneRect().center();
int curX = currScenePos.x();
int endPos = curX + x;
int distanceToAnimate = (endPos - curX);
// speed = dist / time
float updatePosInterval = (float)distanceToAnimate / updateFrequency;
printf("updatePosInterval: %f \n", updatePosInterval);
static float newXPos = sceneRect().center().x();
QTimer* pTimer = new QTimer;
QObject::connect(pTimer, &QTimer::timeout, [=](){
newXPos += updatePosInterval;
centerOn(newXPos, sceneRect().center().y());
// check for end position or time, then....
if(newXPos >= endPos)
{
pTimer->stop();
pTimer->deleteLater();
}
});
pTimer->start(updateFrequency);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsScene scene(0, 0, 10000, 20000);
MyView* view = new MyView(&scene);
QGraphicsRectItem* pRect = new QGraphicsRectItem(0, 0, 100, 100);
pRect->setPos(scene.width()/2, scene.height()/2);
scene.addItem(pRect);
// timer to wait for the window to appear, before starting to move
QTimer* pTimer = new QTimer;
pTimer->setSingleShot(true);
QObject::connect(pTimer, &QTimer::timeout,[=](){
view->centerOn(pRect); // centre on the rectangle
view->AnimateBy(100);
pTimer->deleteLater();
});
pTimer->start(1000);
view->show();
return a.exec();
}
因此,我们通过使用centerOn
的调用逐帧移动视图来创建动画。
为简单起见,代码只处理在一个轴上移动。要在2轴中移动,请使用2D矢量数学计算间隔位置。