QT图表应用程序的创建

对于QT自定义窗口部件,那么绘制一个或者几个项来说,QPainter肯定是最理想的啦,

那么,但是如果需要处理从几个到几万的项时,而且用户能够单击,拖动和选取这些项的时候QPainter就变得不再适用了、那么QT视图类提供了这一解决方案。

   

我们先看下一些宏的定义以及成员函数的实现吧。

Q_DECLARE_TR_FUNCTIONS()

这是一个宏定义,主要用来完成tr()  和 trUtf8()这两个功能。

Foreach(Link *link, myLinks)

Delete link;

Foreach(variable, container);

Foreach也是一个宏,用来完成foreach的循环,查找variable参数中与container参数类型一致的variable,并且通过delete来删除这个节点。

PrepareGeometryChange()在影响项的变化修改之前立即调用。

Node::Node()

{

myTextColor = Qt::darkGreen;

myOutlineColor = Qt::darkBlue;

myBackgroundColor = Qt::white;

setFlags(ItemIsMovable | ItemIsSelectable);

}

Node构造函数用于初始化颜色,ITemIsMovable ITemIsSelectbale用来支持鼠标移动、单击或者拖动项 和 选择项

Link::Link(Node *fromNode, Node *toNode)

{

    myFromNode = fromNode;

    myToNode = toNode;

    myFromNode->addLink(this);

    myToNode->addLink(this);

    setFlags(QGraphicsItem::ItemIsSelectable);

    setZValue(-1);

    setColor(Qt::darkRed);

    trackNodes();

}

这里通过函数指针传递函数,下面就直接使用指针变量来调用函数了。

QRectF Node::outlineRect() const

{

const int Padding = 8;

QFontMetricsF metrics = qApp->font();

QRectF rect = metrics.boundingRect(myText);

rect.adjust(-Padding, -Padding, +Padding, +Padding);

rect.translate(-rect.center());

return rect;

}

QPainterPath path;

path.addRoundRect(rect, roundness(rect.width()),

                      roundness(rect.height()));

增加一个圆角矩形到QPainterPath对象中,roundness返回一个合适的圆角率,圆角率的范围必须是在099之间。

void Node::paint(QPainter *painter,

                 const QStyleOptionGraphicsItem *option,

                 QWidget * /* widget */)

{

    QPen pen(myOutlineColor);

    if (option->state & QStyle::State_Selected) {

        pen.setStyle(Qt::DotLine);

        pen.setWidth(2);

    }

    painter->setPen(pen);

    painter->setBrush(myBackgroundColor);

    QRectF rect = outlineRect();

    painter->drawRoundRect(rect, roundness(rect.width()),

                           roundness(rect.height()));

    painter->setPen(myTextColor);

    painter->drawText(rect, Qt::AlignCenter, myText);

}

Paint函数就是绘制项的地方, QStyleOptionGraphicsItem继承于QStyleOption,state返回QStyle::State默认状态下指明widget没有状态,这里判断项是否被选中,如果被选中,则将笔画的风格设置为点线型,下面是点线型的风格图,并且设置线宽为2个像素, ,然后绘制一个与边缘矩形大小相等的圆角矩形,最后,在圆角矩形的上面绘制文字,使其居于边缘矩形。

QVariant Node::itemChange(GraphicsItemChange change,

                          const QVariant &value)

{

    if (change == ItemPositionHasChanged) {

        foreach (Link *link, myLinks)

            link->trackNodes();

    }

    return QGraphicsItem::itemChange(change, value);

}

一旦用户拖动一个节点,就会调用itemChange()处理器,由ItemPositionChanged作为第一个参数,如果,发生改变,遍历节点的Link集合,通知每一条线更新他们的端点,最后,调用基类的实现以确保基类也得到了通知。

void Node::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)

{

    QString text = QInputDialog::getText(event->widget(),

                           tr("Edit Text"), tr("Enter new text:"),

                           QLineEdit::Normal, myText);

    if (!text.isEmpty())

        setText(text);

}

如果用户双击该节点,就会弹出显示当前文字的对话框,并且允许用户修改它,如果用户点击了Cancle,将会返回一个空字符串,因此,当字符串不为空时修改才会有效。

我们定义了项类的实现,我们就来使用它吧

DiagramWindow::DiagramWindow()

{

    scene = new QGraphicsScene(0, 0, 600, 500);

    view = new QGraphicsView;

    view->setScene(scene);

    view->setDragMode(QGraphicsView::RubberBandDrag);

    view->setRenderHints(QPainter::Antialiasing

                         | QPainter::TextAntialiasing);

    view->setContextMenuPolicy(Qt::ActionsContextMenu);

    setCentralWidget(view);

    minZ = 0;

    maxZ = 0;

    seqNumber = 0;

    createActions();

    createMenus();

    createToolBars();

    connect(scene, SIGNAL(selectionChanged()),

            this, SLOT(updateActions()));

    setWindowTitle(tr("Diagram"));

    updateActions();

}

我们从创建一个图形场景开始,QGraphicsScene提供2D表面图形的管理,和QGraphicsView配合使用,QGraphicsView用来显示QGraphicsScene中的场景。

setScene(scene)设置当前的场景到scene, setDragMode当鼠标按下左键并且拖动时产生相应的动作,QGraphicsView::RubberBandDrag意味着可以圈选它们。

setRenderHints让边沿显得更加平滑。

setContextMenuPolicy指出这个Widget怎么显示菜单。

minZ 和maxZ数字用在sendToBack() 和 bringToFront()函数中,序号用来为用户添加每一个节点提供一个唯一的初始化文字。

接下来我们就看看到底怎么去使用这些定义好的项,当然我们需要创建一个菜单栏,工具栏。createActions();createMenus();createToolBars();这里完成这些工作我们不再讨论,我们看添加新节点:

void DiagramWindow::addNode()

{

    Node *node = new Node;

    node->setText(tr("Node %1").arg(seqNumber + 1));

    setupNode(node);

}

创建一个Node对象来产生一个新的节点,用setupNode来定位和选取它。

void DiagramWindow::setupNode(Node *node)

{

    node->setPos(QPoint(80 + (100 * (seqNumber % 5)),

                        80 + (50 * ((seqNumber / 5) % 7))));

    scene->addItem(node);

    ++seqNumber;

    scene->clearSelection();

    node->setSelected(true);

    bringToFront();

}

Node继承于QGraphicsItem,当然QGraphicsItem类中的成员函数也是可以使用的,用来给node定位,用addItem来增加项和所以子项到场景当中,每次新建Node 都要用clearSelection清除当前的选中状态,否则会出现每次新建的node都处于选中状态,并且用setSelected来选中当前新建的那个Node节点,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值