我们知道像微信那样的带有气球的对话框对于一些聊天的应用来说非常好。在很多即时通讯的应用中可以用到。在今天的文章中,我们将介绍如何使用QML来实现这样的界面。
为了方便,我们可以采用Ubuntu SDK中的“QtQuick App with QML UI (qmake)”这个模版来实现一个模版的应用。为了能够创建一个TextBalloon的控件,我们使用了C++代码:
textballoon.h
#ifndef TEXTBALLOON_H #define TEXTBALLOON_H #include <QtQuick> class TextBalloon : public QQuickPaintedItem { Q_OBJECT Q_PROPERTY(bool rightAligned READ isRightAligned WRITE setRightAligned NOTIFY rightAlignedChanged) public: TextBalloon(QQuickItem *parent = 0); void paint(QPainter *painter); bool isRightAligned(); void setRightAligned(bool rightAligned); private: bool rightAligned; signals: void rightAlignedChanged(); }; #endif
textballoon.cpp
#include "textballoon.h" TextBalloon::TextBalloon(QQuickItem *parent) : QQuickPaintedItem(parent) , rightAligned(false) { } void TextBalloon::paint(QPainter *painter) { QBrush brush(QColor("#007430")); QBrush white(QColor("#FFFFFF")); if (rightAligned) { painter->setBrush(brush); painter->setPen(Qt::NoPen); painter->setRenderHint(QPainter::Antialiasing); painter->drawRoundedRect(10, 0, boundingRect().width() - 19, boundingRect().height(), 10, 10); const QPointF points[3] = { QPointF(boundingRect().width() - 10.0, 10.0), QPointF(boundingRect().width(), 20.0), QPointF(boundingRect().width() - 10.0, 30.0), }; painter->drawConvexPolygon(points, 3); } else { painter->setBrush(white); painter->setPen(Qt::NoPen); painter->setRenderHint(QPainter::Antialiasing); painter->drawRoundedRect(10, 0, boundingRect().width() - 19, boundingRect().height(), 10, 10); const QPointF points[3] = { QPointF(10,10), QPointF(0, 20), QPointF(10, 30), }; painter->drawConvexPolygon(points, 3); } } bool TextBalloon::isRightAligned() { return this->rightAligned; } void TextBalloon::setRightAligned(bool rightAligned) { this->rightAligned = rightAligned; }
在main.cpp中,注册该类:
qmlRegisterType<TextBalloon>("TextBalloon", 1, 0, "TextBalloon");
这样这个TextBalloon就可以在QML中被利用。我们的QML界面非常简单:
import QtQuick 2.0 import Ubuntu.Components 1.1 Item { id: root property int contentWidth: width *.6 ListModel { id: balloonModel } ListView { id: balloonView anchors.bottom: controls.top anchors.bottomMargin: 2 anchors.top: parent.top clip:true delegate: MyDelegate {} model: balloonModel spacing: units.gu(4) width: parent.width } Rectangle { id: controls anchors.bottom: parent.bottom anchors.left: parent.left anchors.margins: 1 anchors.right: parent.right border.width: 2 color: "white" height: parent.height * 0.15 Text { anchors.centerIn: parent text: "Add another balloon" } MouseArea { anchors.fill: parent hoverEnabled: true onClicked: { balloonModel.append({"balloonWidth": Math.floor(Math.random() * 200 + 100), "content": "this is cool" }) balloonView.positionViewAtIndex(balloonView.count -1, ListView.End) } onEntered: { parent.color = "#8ac953" } onExited: { parent.color = "white" } } } Component.onCompleted: { console.log("contentWidth: " + root.contentWidth); balloonModel.append({"balloonWidth": root.contentWidth, "content": "this is a text, this is a perfect world to play with, and I love to play the world" }); balloonModel.append({"balloonWidth": root.contentWidth, "content": "this is a text, this is a perfect world to play with, and I love to play the world" }); } }
上面是一个ListView,下面是一个按钮来动态生成一些ListView中的项。我们的ListView的delegate设计稍微麻烦一点:
import QtQuick 2.0 import TextBalloon 1.0 import Ubuntu.Components 1.1 import QtQuick.Layouts 1.1 Item { id: delegate width: ListView.view.width height: txt.contentHeight + 20 property bool rightAligned: index % 2 == 0 ? false : true RowLayout { spacing: units.gu(2) anchors.right: index % 2 == 0 ? undefined : parent.right Image { id: leftImg width: root.contentWidth*.2 height: width anchors.top:parent.top source: "images/pic1.jpg" visible: delegate.rightAligned ? false : true fillMode: Image.PreserveAspectCrop Layout.maximumWidth:root.contentWidth*.2 Layout.maximumHeight: root.contentWidth*.2 } Text { id: txt anchors.top: parent.top anchors.topMargin: units.gu(1) width: root.contentWidth wrapMode: Text.WordWrap text: content // horizontalAlignment: delegate.rightAligned ? Text.AlignRight : Text.AlignLeft font.pixelSize: units.gu(3) Layout.maximumWidth: root.contentWidth TextBalloon { anchors.fill: parent z: -1 rightAligned: delegate.rightAligned anchors.margins: -units.gu(1.5) } } Image { id: rightImg anchors.top:parent.top width: root.contentWidth*.2 height: width source: "images/pic2.jpg" visible: delegate.rightAligned ? true : false fillMode: Image.PreserveAspectCrop Layout.maximumWidth:root.contentWidth*.2 Layout.maximumHeight: root.contentWidth*.2 } } }
这里我们使用RowLayout,也是非常tricky的一个设计。运行我们的应用:
整个项目的源码在: git clone https://gitcafe.com/ubuntu/weixin_new.git
时间: 2024-10-18 14:00:28