Zooming and rotating(缩放与旋转)
QGraphicsView 通过 QGraphicsView::setMatrix()支持与 QPainter 同样的仿射变换. 例如缩放与旋转……
下面的例子来说明如何在QGraphicsView子类中实现缩放与旋转槽:
class View : public QGraphicsView
{
Q_OBJECT
...
public slots:
void zoomIn() { scale(1.2, 1.2); }
void zoomOut() { scale(1 / 1.2, 1 / 1.2); }
void rotateLeft() { rotate(-10); }
void rotateRight() { rotate(10); }
...
};
The slots could be connected to QToolButtons with autoRepeat enabled.
QGraphicsView keeps the center of the view aligned when you transform the view.
See also the Elastic Nodes example for code that shows how to implement basic zooming features.
Printing(打印)
Graphics View provides single-line printing through its rendering functions(渲染函数),QGraphicsScene::render() andQGraphicsView::render(). The functions provide the same API: You can have the scene or the view render all or parts of their contents into any paint device by passing aQPainter to either of the rendering functions..下面的示例说明如何利用QPrinter打印整个场景(scene)
QGraphicsScene scene;
scene.addRect(QRectF(0, 0, 100, 200), QPen(Qt::black), QBrush(Qt::green));
QPrinter printer;
if (QPrintDialog(&printer).exec() == QDialog::Accepted) {
QPainter painter(&printer);
painter.setRenderHint(QPainter::Antialiasing);
scene.render(&painter);
}
The difference between the scene and view rendering functions is that one operates in scene coordinates, and the other in view coordinates.QGraphicsScene::render() is often preferred for printing whole segments of a scene untransformed, such as for plotting geometrical data, or for printing a text document.QGraphicsView::render(), on the other hand, is suitable for taking screenshots; its default behavior is to render the exact contents(确切内容) of the viewport using the provided painter.
QGraphicsScene scene;
scene.addRect(QRectF(0, 0, 100, 200), QPen(Qt::black), QBrush(Qt::green));
QPixmap pixmap;
QPainter painter(&pixmap);
painter.setRenderHint(QPainter::Antialiasing);
scene.render(&painter);
painter.end();
pixmap.save("scene.png");
当场景与目标区域大小不一致时,场景会拉伸以适应目标区域。通过传递一个Qt::AspectRatioMode给渲染函数,当场景内容被拉伸时可以选择保持或忽略场景的纵横比
拓展:
enum Qt::AspectRatioMode
This enum type defines what happens to the aspect ratio when scaling an rectangle.
Constant | Value | Description |
---|---|---|
Qt::IgnoreAspectRatio | 0 | The size is scaled freely. The aspect ratio is not preserved. |
Qt::KeepAspectRatio | 1 | The size is scaled to a rectangle as large as possible inside a given rectangle, preserving the aspect ratio. |
Qt::KeepAspectRatioByExpanding | 2 | The size is scaled to a rectangle as small as possible outside a given rectangle, preserving the aspect ratio. |
See also QSize::scale() andQImage::scaled().
Drag and Drop(拖拽)
因为 QGraphicsView 直接继承自QWidget , 它能够提供QWidget 支持的拖拽功能。另外,为了方便,Graphics View framework 为 scene, and for each and every item实现了拖拽功能. As the view receives a drag, it translates the drag and drop events into a QGraphicsSceneDragDropEvent, which is then forwarded to the scene. The scene takes over scheduling of this event, and sends it to the first item under the mouse cursor that accepts drops.
To start a drag from an item, create a QDrag object, passing a pointer to the widget that starts the drag. Items can be observed by many views at the same time, but only one view can start the drag. Drags are in most cases started as a result of pressing or moving the mouse, so in mousePressEvent() or mouseMoveEvent(), you can get the originating widget pointer from the event. For example:
void CustomItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
QMimeData *data = new QMimeData;
data->setColor(Qt::green);
QDrag *drag = new QDrag(event->widget());
drag->setMimeData(data);
drag->start();
}
To intercept drag and drop events for the scene, you reimplement QGraphicsScene::dragEnterEvent() and whichever event handlers your particular scene needs, in aQGraphicsItem subclass. You can read more about drag and drop in Graphics View in the documentation for each ofQGraphicsScene's event handlers.
Items can enable drag and drop support by calling QGraphicsItem::setAcceptDrops(). To handle the incoming drag, reimplement QGraphicsItem::dragEnterEvent(), QGraphicsItem::dragMoveEvent(), QGraphicsItem::dragLeaveEvent(), and QGraphicsItem::dropEvent().
See also the Drag and Drop Robot example for a demonstration of Graphics View's support for drag and drop operations.
Cursors and Tooltips
Like QWidget, QGraphicsItem also supports cursors (QGraphicsItem::setCursor()), and tooltips (QGraphicsItem::setToolTip()). The cursors and tooltips are activated by QGraphicsView as the mouse cursor enters the item's area (detected by callingQGraphicsItem::contains()).
You can also set a default cursor directly on the view by calling QGraphicsView::setCursor().
See also the Drag and Drop Robot example for code that implements tooltips and cursor shape handling.
Animation
Graphics View supports animation at several levels. You can easily assemble animation by using the Animation Framework. For that you'll need your items to inherit fromQGraphicsObject and associateQPropertyAnimation with them.QPropertyAnimation allows to animate anyQObject property.
Another option is to create a custom item that inherits from QObject and QGraphicsItem. The item can the set up its own timers, and control animations with incremental steps inQObject::timerEvent().
A third option, which is mostly available for compatibility with QCanvas in Qt 3, is to advance the scene by calling QGraphicsScene::advance(), which in turn calls QGraphicsItem::advance().
OpenGL Rendering
To enable OpenGL rendering, you simply set a new QGLWidget as the viewport of QGraphicsView by calling QGraphicsView::setViewport(). If you want OpenGL with antialiasing, you need OpenGL sample buffer support (seeQGLFormat::sampleBuffers()).
Example:
QGraphicsView view(&scene);
view.setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
Item Groups
By making an item a child of another, you can achieve the most essential feature of item grouping: the items will move together, and all transformations are propagated from parent to child.
In addition, QGraphicsItemGroup is a special item that combines child event handling with a useful interface for adding and removing items to and from a group. Adding an item to aQGraphicsItemGroup will keep the item's original position and transformation, whereas reparenting items in general will cause the child to reposition itself relative to its new parent. For convenience, you can create QGraphicsItemGroups through the scene by callingQGraphicsScene::createItemGroup().
Widgets and Layouts
Qt 4.4 introduced support for geometry and layout-aware items through QGraphicsWidget. This special base item is similar to QWidget, but unlike QWidget, it doesn't inherit fromQPaintDevice; rather fromQGraphicsItem instead. This allows you to write complete widgets with events, signals & slots, size hints and policies, and you can also manage your widgets geometries in layouts throughQGraphicsLinearLayout andQGraphicsGridLayout.
QGraphicsWidget
Building on top of QGraphicsItem's capabilities and lean footprint,QGraphicsWidget provides the best of both worlds: extra functionality fromQWidget, such as the style, font, palette, layout direction, and its geometry, and resolution independence and transformation support fromQGraphicsItem. Because Graphics View uses real coordinates instead of integers,QGraphicsWidget's geometry functions also operate onQRectF and QPointF. This also applies to frame rects, margins and spacing. With QGraphicsWidget it's not uncommon to specify contents margins of (0.5, 0.5, 0.5, 0.5), for example. You can create both subwidgets and "top-level" windows; in some cases you can now use Graphics View for advanced MDI applications.
Some of QWidget's properties are supported, including window flags and attributes, but not all. You should refer toQGraphicsWidget's class documentation for a complete overview of what is and what is not supported. For example, you can create decorated windows by passing theQt::Window window flag toQGraphicsWidget's constructor, but Graphics View currently doesn't support theQt::Sheet and Qt::Drawer flags that are common on Mac OS X.
The capabilities of QGraphicsWidget are expected to grow depending on community feedback.
QGraphicsLayout
QGraphicsLayout is part of a second-generation layout framework designed specifically forQGraphicsWidget. Its API is very similar to that ofQLayout. You can manage widgets and sublayouts inside eitherQGraphicsLinearLayout andQGraphicsGridLayout. You can also easily write your own layout by subclassingQGraphicsLayout yourself, or add your ownQGraphicsItem items to the layout by writing an adaptor subclass ofQGraphicsLayoutItem.
Embedded Widget Support
Graphics View provides seamless support for embedding any widget into the scene. You can embed simple widgets, such asQLineEdit or QPushButton, complex widgets such as QTabWidget, and even complete main windows. To embed your widget to the scene, simply callQGraphicsScene::addWidget(), or create an instance ofQGraphicsProxyWidget to embed your widget manually.
Through QGraphicsProxyWidget, Graphics View is able to deeply integrate the client widget features including its cursors, tooltips, mouse, tablet and keyboard events, child widgets, animations, pop-ups (e.g., QComboBox orQCompleter), and the widget's input focus and activation.QGraphicsProxyWidget even integrates the embedded widget's tab order so that you can tab in and out of embedded widgets. You can even embed a newQGraphicsView into your scene to provide complex nested scenes.
When transforming an embedded widget, Graphics View makes sure that the widget is transformed resolution independently, allowing the fonts and style to stay crisp when zoomed in. (Note that the effect of resolution independence depends on the style.)
Performance
Floating Point Instructions
In order to accurately and quickly apply transformations and effects to items, Graphics View is built with the assumption that the user's hardware is able to provide reasonable performance for floating point instructions.
Many workstations and desktop computers are equipped with suitable hardware to accelerate this kind of computation, but some embedded devices may only provide libraries to handle mathematical operations or emulate floating point instructions in software.
As a result, certain kinds of effects may be slower than expected on certain devices. It may be possible to compensate for this performance hit by making optimizations in other areas; for example, by usingOpenGL to render a scene. However, any such optimizations may themselves cause a reduction in performance if they also rely on the presence of floating point hardware.