Diagram Scene Example▲
The Diagram Scene example is an application in which you can create a flowchart diagram. It is possible to add flowchart shapes and text and connect the shapes by arrows as shown in the image above. The shapes, arrows, and text can be given different colors, and it is possible to change the font, style, and underline of the text.
The Qt graphics view framework is designed to manage and display custom 2D graphics items. The main classes of the framework are QGraphicsItem, QGraphicsScene and QGraphicsView. The graphics scene manages the items and provides a surface for them. QGraphicsView is a widget that is used to render a scene on the screen. See the Graphics View Framework for a more detailed description of the framework.
In this example we show how to create such custom graphics scenes and items by implementing classes that inherit QGraphicsScene and QGraphicsItem.
In particular we show how to:
-
Create custom graphics items.
-
Handle mouse events and movement of items.
-
Implement a graphics scene that can manage our custom items.
-
Custom painting of items.
-
Create a movable and editable text item.
The example consists of the following classes:
-
MainWindow creates the widgets and display them in a QMainWindow. It also manages the interaction between the widgets and the graphics scene, view and items.
-
DiagramItem inherits QGraphicsPolygonItem and represents a flowchart shape.
-
TextDiagramItem inherits QGraphicsTextItem and represents text items in the diagram. The class adds support for moving the item with the mouse, which is not supported by QGraphicsTextItem.
-
Arrow inherits QGraphicsLineItem and is an arrow that connect two DiagramItems.
-
DiagramScene inherits QGraphicsDiagramScene and provides support for DiagramItem, Arrow and DiagramTextItem (In addition to the support already handled by QGraphicsScene).
MainWindow Class Definition▲
class
MainWindow : public
QMainWindow
{
Q_OBJECT
public
:
MainWindow();
private
slots:
void
backgroundButtonGroupClicked(QAbstractButton *
button);
void
buttonGroupClicked(int
id);
void
deleteItem();
void
pointerGroupClicked(int
id);
void
bringToFront();
void
sendToBack();
void
itemInserted(DiagramItem *
item);
void
textInserted(QGraphicsTextItem *
item);
void
currentFontChanged(const
QFont &
amp;font);
void
fontSizeChanged(const
QString &
amp;size);
void
sceneScaleChanged(const
QString &
amp;scale);
void
textColorChanged();
void
itemColorChanged();
void
lineColorChanged();
void
textButtonTriggered();
void
fillButtonTriggered();
void
lineButtonTriggered();
void
handleFontChange();
void
itemSelected(QGraphicsItem *
item);
void
about();
private
:
void
createToolBox();
void
createActions();
void
createMenus();
void
createToolbars();
QWidget *
createBackgroundCellWidget(const
QString &
amp;text,
const
QString &
amp;image);
QWidget *
createCellWidget(const
QString &
amp;text,
DiagramItem::
DiagramType type);
QMenu *
createColorMenu(const
char
*
slot, QColor defaultColor);
QIcon createColorToolButtonIcon(const
QString &
amp;image, QColor color);
QIcon createColorIcon(QColor color);
DiagramScene *
scene;
QGraphicsView *
view;
QAction *
exitAction;
QAction *
addAction;
QAction *
deleteAction;
QAction *
toFrontAction;
QAction *
sendBackAction;
QAction *
aboutAction;
QMenu *
fileMenu;
QMenu *
itemMenu;
QMenu *
aboutMenu;
QToolBar *
textToolBar;
QToolBar *
editToolBar;
QToolBar *
colorToolBar;
QToolBar *
pointerToolbar;
QComboBox *
sceneScaleCombo;
QComboBox *
itemColorCombo;
QComboBox *
textColorCombo;
QComboBox *
fontSizeCombo;
QFontComboBox *
fontCombo;
QToolBox *
toolBox;
QButtonGroup *
buttonGroup;
QButtonGroup *
pointerTypeGroup;
QButtonGroup *
backgroundButtonGroup;
QToolButton *
fontColorToolButton;
QToolButton *
fillColorToolButton;
QToolButton *
lineColorToolButton;
QAction *
boldAction;
QAction *
underlineAction;
QAction *
italicAction;
QAction *
textAction;
QAction *
fillAction;
QAction *
lineAction;
}
;
The MainWindow class creates and lays out the widgets in a QMainWindow. The class forwards input from the widgets to the DiagramScene. It also updates its widgets when the diagram scene's text item changes, or a diagram item or a diagram text item is inserted into the scene.
The class also deletes items from the scene and handles the z-ordering, which decides the order in which items are drawn when they overlap each other.
MainWindow Class Implementation▲
We start with a look at the constructor:
MainWindow::
MainWindow()
{
createActions();
createToolBox();
createMenus();
scene =
new
DiagramScene(itemMenu, this
);
scene-&
gt;setSceneRect(QRectF(0
, 0
, 5000
, 5000
));
connect(scene, &
amp;DiagramScene::
itemInserted,
this
, &
amp;MainWindow::
itemInserted);
connect(scene, &
amp;DiagramScene::
textInserted,
this
, &
amp;MainWindow::
textInserted);
connect(scene, &
amp;DiagramScene::
itemSelected,
this
, &
amp;MainWindow::
itemSelected);
createToolbars();
QHBoxLayout *
layout =
new
QHBoxLayout;
layout-&
gt;addWidget(toolBox);
view =
new
QGraphicsView(scene);
layout-&
gt;addWidget(view);
QWidget *
widget =
new
QWidget;
widget-&
gt;setLayout(layout);
setCentralWidget(widget);
setWindowTitle(tr("Diagramscene"
));
setUnifiedTitleAndToolBarOnMac(true
);
}
In the constructor we call methods to create the widgets and layouts of the example before we create the diagram scene. The toolbars must be created after the scene as they connect to its signals. We then lay the widgets out in the window.
We connect to the itemInserted() and textInserted() slots of the diagram scenes as we want to uncheck the buttons in the tool box when an item is inserted. When an item is selected in the scene we receive the itemSelected() signal. We use this to update the widgets that display font properties if the item selected is a DiagramTextItem.
The createToolBox() function creates and lays out the widgets of the toolBox QToolBox. We will not examine it with a high level of detail as it does not deal with graphics framework specific functionality. Here is its implementation:
void
MainWindow::
createToolBox()
{
buttonGroup =
new
QButtonGroup(this
);
buttonGroup-&
gt;setExclusive(false
);
connect(buttonGroup, QOverload&
lt;int
&
gt;::
of(&
amp;QButtonGroup::
buttonClicked),
this
, &
amp;MainWindow::
buttonGroupClicked);
QGridLayout *
layout =
new
QGridLayout;
layout-&
gt;addWidget(createCellWidget(tr("Conditional"
), DiagramItem::
Conditional), 0
, 0
);
layout-&
gt;addWidget(createCellWidget(tr("Process"
), DiagramItem::
Step),0
, 1
);
layout-&
gt;addWidget(createCellWidget(tr("Input/Output"
), DiagramItem::
Io), 1
, 0
);
This part of the function sets up the tabbed widget item that contains the flowchart shapes. An exclusive QButtonGroup always keeps one button checked; we want the group to allow all buttons to be unchecked. We still use a button group since we can associate user data, which we use to store the diagram type, with each button. The createCellWidget() function sets up the buttons in the tabbed widget item an