QT Demo 之 text

来源:互联网 发布:java文件编译成class 编辑:程序博客网 时间:2024/05/16 08:58

学习了MouseArea,我们继续选择一个基本的组件进行学习,这次我们学习text的Demo。

text的Demo位于F:\Qt\Qt5.3.2\Examples\Qt-5.3\quick\text目录。通过text.qmlproject文件我们了解,该Demo的mainFile是text.qml。

Item {    height: 480    width: 320    LauncherList {        id: ll        anchors.fill: parent        Component.onCompleted: {            addExample("Hello", "An Animated Hello World", Qt.resolvedUrl("fonts/hello.qml"));            addExample("Fonts", "Using various fonts with a Text element", Qt.resolvedUrl("fonts/fonts.qml"));            addExample("Available Fonts", "A list of your available fonts",  Qt.resolvedUrl("fonts/availableFonts.qml"));            addExample("Banner", "Large, scrolling text", Qt.resolvedUrl("fonts/banner.qml"));            addExample("Img tag", "Embedding images into text", Qt.resolvedUrl("imgtag/imgtag.qml"));            addExample("Text Layout", "Flowing text around items", Qt.resolvedUrl("styledtext-layout.qml"));        }    }}
从代码来看,该Example主界面是一个LauncherList,其中包含6个子元素,分别从6个方面演示text的操作。

先看一下程序运行的效果图:

LauncherList简述

LauncherList是一个自定义的容器,具体实现是在qrc:/shared/LauncherList.qml文件中,其自身的注释说明如下:
    //model is a list of {"name":"somename", "url":"file:///some/url/mainfile.qml"}
    //function used to add to model A) to enforce scheme B) to allow Qt.resolveUrl in url assignments

此处我们知道LaunchList是一个可以添加name,description和url的可点击栏即可,后面有机会再详细分析LaunchList。

在使用LauncherList时,添加List元素是在Component.onCompleted:{}响应函数中添加的,针对Component,官方说明如下:
Components are reusable, encapsulated QML types with well-defined interfaces.
Components are often defined by component files - that is, .qml files.

而completed()信号的以及onCompleted响应函数的说明如下:
completed()
Emitted after the object has been instantiated. This can be used to execute script code at startup, once the full QML environment has been established.The corresponding handler is onCompleted.


因此,我们了解到在这里LauncherList.qml整体是作为一个Component的,当LauncherList实例化完成之后,就会触发onCompleted响应函数,来向LauncherList中addExample。
下面我们就开始分析每一个Example。

fonts/hello.qml文件

hello.qml源码结构比较简单,只有一个Item:

Rectangle {    id: screen    width: 320; height: 480    color: "black"    Item {....}}
Item中只有一个Text字段,坐标在父元素的居中位置:

    Item {        id: container        x: screen.width / 2; y: screen.height / 2        Text {....}    }
Text中描述了颜色(白色)、文本内容(Hello world!)、字体大小(32),而且还定义了两个SequentialAnimation分别表示字间距和透明度上的动画效果。

        Text {            id: text            anchors.centerIn: parent            color: "white"            text: "Hello world!"            font.pixelSize: 32//! [letterspacing]            SequentialAnimation on font.letterSpacing {....}//! [letterspacing]            SequentialAnimation on opacity {....}        }

字间距动画效果

            SequentialAnimation on font.letterSpacing {                loops: Animation.Infinite;                NumberAnimation { from: 0; to: 50; easing.type: Easing.InQuad; duration: 3000 }                ScriptAction {                    script: {                        container.y = (screen.height / 4) + (Math.random() * screen.height / 2)                        container.x = (screen.width / 4) + (Math.random() * screen.width / 2)                    }                }            }
从上面这个动画效果,我们可以看到以下几个组成部分:

  1. 动画循环次数:这里是无线循环的显示动画。(如果要停掉动画,可以设置running属性为false,或者调用stop()函数)
  2. 定义一个具体的动画:这里使用的是一个可以根据数字变化的动画效果:从0增加到50(数值的改变作用在font.letterSpacing),设置擦除曲线为InQuad(具体效果未知),动画时长为3s
  3. 定义一个脚本动作:具体的效果是随机改变container的x,y坐标值

整体的动画效果就是:

  • 在3s内不断增大文本的字间距从0到50,然后随机改变一下文本的x,y坐标;
  • 循环进行上述操作。

透明度动画效果

            SequentialAnimation on opacity {                loops: Animation.Infinite;                NumberAnimation { from: 1; to: 0; duration: 2600 }                PauseAnimation { duration: 400 }            }
通过上面对字间距动画的效果分析,我们可以知道本例中的透明度动画效果是:

  • 在2.6s内不断改变文本的透明度从1到0,然后暂停0.4s(以便和上面的3s动画保持步调一致);
  • 循环进行上述操作。

fonts/fonts.qml文件

fonts.qml文件中定义了一个成员变量myText,3个FontLoader和一个Column,Column中有6个Text使用不同的字体显示myText内容。

Rectangle {    property string myText: "The quick brown fox jumps over the lazy dog."    width: 320; height: 480    color: "steelblue"//! [fontloader]    FontLoader { id: fixedFont; name: "Courier" }//! [fontloader]//! [fontloaderlocal]    FontLoader { id: localFont; source: "content/fonts/tarzeau_ocr_a.ttf" }//! [fontloaderlocal]//! [fontloaderremote]    FontLoader { id: webFont; source: "http://www.princexml.com/fonts/steffmann/Starburst.ttf" }//! [fontloaderremote]    Column {....}}

FontLoader简述

The FontLoader type is used to load fonts by name or URL.

一个FontLoader共有3个属性,分别是:
name : string               This property holds the name of the font family.
source : url                The url of the font to load
status : enumeration        This property holds the status of font loading. It can be one of:FontLoader.Null,FontLoader.Ready,FontLoader.Loading,FontLoader.Error

本例中使用了上面的两种方式加载字体,分别加载了"Courier"和"content/fonts/tarzeau_ocr_a.ttf"两种本地字体,以及"http://www.princexml.com/fonts/steffmann/Starburst.ttf"网络字体,针对Starburst.ttf网络字体,因为涉及到网络加载,使用了第三个属性status,如最后一个Text是在字体加载的不同状态下显示不同的文本:

        Text {            text: {                if (webFont.status == FontLoader.Ready) myText                else if (webFont.status == FontLoader.Loading) "Loading..."                else if (webFont.status == FontLoader.Error) "Error loading font"            }        }

字体显示

以下6个Text的字体显示分别如下(省略了部分代码):

字体是Times,大小是20

        Text {            font.family: "Times"            font.pixelSize: 20        }
字体是Times,对齐方式居中,大小是20,文本全部大写
        Text {            horizontalAlignment: Text.AlignHCenter            font { family: "Times"; pixelSize: 20; capitalization: Font.AllUppercase }        }
字体是上面fixedFont指定的Courier字体,对齐方式是右对齐,大小是20,加粗,文本全部小写
        Text {            horizontalAlignment: Text.AlignRight            font { family: fixedFont.name; pixelSize: 20; weight: Font.Bold; capitalization: Font.AllLowercase }        }
字体是上面fixedFont指定的Courier字体,大小是20,斜体,文本小型大写(大小跟小写字母一样,样式是大写)
        Text {            font { family: fixedFont.name; pixelSize: 20; italic: true; capitalization: Font.SmallCaps }        }
字体是上面localFont指定的tarzeau_ocr_a.ttf字体,大小是20,文本每个单词的首字母大写
        Text {            font { family: localFont.name; pixelSize: 20; capitalization: Font.Capitalize }        }
字体是上面webFont指定的Starburst.ttf字体,大小是20
        Text {            font.family: webFont.name; font.pixelSize: 20        }
上面忽略的代码如下,分别定义了text文本内容、字体颜色、文本宽度以及按照单词进行换行:
            text: myText            color: "lightsteelblue"            width: parent.width            wrapMode: Text.WordWrap

fonts/availableFonts.qml文件

availableFonts文件中就是一个ListView,用来显示所有的Font格式

Rectangle {    width: 320; height: 480; color: "steelblue"    ListView {....}}

ListView简述

A ListView displays data from models created from built-in QML types like ListModel and XmlListModel, or custom model classes defined in C++ that inherit from QAbstractItemModel or QAbstractListModel.
A ListView has a model, which defines the data to be displayed, and a delegate, which defines how the data should be displayed. Items in a ListView are laid out horizontally or vertically. List views are inherently flickable because ListView inherits from Flickable.

从上面的描述,我们可以知道ListView用来显示从model中提供的数据,然后按照delegate的方式进行显示。


显示的数据来源于Qt.fontFamilies()

//! [model]        model: Qt.fontFamilies()//! [model]

显示的方式是每行高40,宽和列表等宽,居中显示,颜色白色,大小20

        delegate: Item {            height: 40; width: ListView.view.width            Text {                anchors.centerIn: parent                text: modelData//! [delegate]                font.family: modelData//! [delegate]                font.pixelSize: 20                color: "white"            }        }
注意,这里的字体以及文本内容都是modelData,就是说每种字体都是使用自己的字体格式来显示字体名称。

令人有点疑惑不解的是modelData这个变量是哪里来的,通过查找文档,我们了解到这是一个内置变量,用来表示model中的每一个元素
Models that do not have named roles (such as the QStringList model shown below) will have the data provided via the modelData role. The modelData role is also provided for models that have only one role. In this case the modelData role contains the same data as the named role.
吐槽:帮助文档中没有任何和modelData有关的内容,官网上又是语焉不详的,在这个知识点上,Qt的帮助做的太差了。

fonts/banner.qml文件

和fonts/font.qml相反的是,这一个qml中主要定义了一个Row:

Rectangle {    id: screen    property int pixelSize: screen.height * 1.25    property color textColor: "lightsteelblue"    property string text: "Hello world! "    width: 320; height: 480    color: "steelblue"    Row {....}}
开始的3个成员变量分别定义了字体大小、字体颜色以及文本内容。

下面的Row中,显示了三个Text(内容一样,吐槽),然后定义了一个NumberAnimation动画,不断实现向左侧平移的动画(注意,这里改变的x是针对整个Row元素的,因此如果把窗口拉长,是会看到3个Text一起向左平移的)(平移的长度竟然是一个Text的width,而参与平移的是三个Text,吐槽)

    Row {        y: -screen.height / 4.5        NumberAnimation on x { from: 0; to: -text.width; duration: 6000; loops: Animation.Infinite }        Text { id: text; font.pixelSize: screen.pixelSize; color: screen.textColor; text: screen.text }        Text { font.pixelSize: screen.pixelSize; color: screen.textColor; text: screen.text }        Text { font.pixelSize: screen.pixelSize; color: screen.textColor; text: screen.text }    }

imgtag/imgtag.qml文件

这一节非常好玩,重点演示了图片和文本在一起的各种排版效果,先看文件的整体结构,主要包括是一个Flikable,以及三个键盘事件响应函数

Rectangle {    id: main    width: 320; height: 480    focus: true    color: "#dedede"    property var hAlign: Text.AlignLeft    Flickable {...}    Keys.onUpPressed: main.hAlign = Text.AlignHCenter    Keys.onLeftPressed: main.hAlign = Text.AlignLeft    Keys.onRightPressed: main.hAlign = Text.AlignRight}

Flickable简述

The Flickable item places its children on a surface that can be dragged and flicked, causing the view onto the child items to scroll. This behavior forms the basis of Items that are designed to show large numbers of child items, such as ListView and GridView.
简单立即,Flikable就是在一个较小的窗口下显示一个较大的内容,然后这个内容是可以拖动的。

    Flickable {        anchors.fill: parent        contentWidth: parent.width        contentHeight: col.height + 20        Column {....}    }
这里的Flickable只有一个Column子元素,使用contentWidth和contentHeight描述可以拖动的范围。因为contentWidth等于parent.width,则在左右方向上不可拖动;contentHeight等于子元素col的高度+20,表示可以拖动子元素col离开底面20个像素(此处如果我们改变20为200,经测试可以拖动到更高的位置)。
但是,这里有一个疑问的地方,父元素竟然可以访问子元素的属性,更何况col此时还没有创建(位于下面几行)?我的理解,QML中的所有元素都是全局的,但是有结构上从属关系,从访问的角度上是可以通过id直接访问的;而且这里设置contentHeight也可以放到Column后面,毕竟这个是针对Flickable的一个属性设置。

具体的Column数据如下:
字体加粗,插入图片,图片和文本的排版方式默认底对齐

            TextWithImage {                text: "This is a <b>happy</b> face<img src=\"images/face-smile.png\">"            }
字体加粗,插入图片,设置图片和文本是居中对齐

            TextWithImage {                text: "This is a <b>very<img src=\"images/face-smile-big.png\" align=\"middle\"/>happy</b> face vertically aligned in the middle."            }
插入图片,并设置图片的宽高进行缩放

            TextWithImage {                text: "This is a tiny<img src=\"images/face-smile.png\" width=\"15\" height=\"15\">happy face."            }
插入两个图片,分别是顶对齐和底对齐

            TextWithImage {                text: "This is a<img src=\"images/starfish_2.png\" width=\"50\" height=\"50\" align=\"top\">aligned to the top and a<img src=\"images/heart200.png\" width=\"50\" height=\"50\">aligned to the bottom."            }
插入多个图片,全部是居中对齐,设置不同的宽高进行缩放

            TextWithImage {                text: "Qt logos<img src=\"images/qtlogo.png\" width=\"55\" height=\"60\" align=\"middle\"><img src=\"images/qtlogo.png\" width=\"37\" height=\"40\" align=\"middle\"><img src=\"images/qtlogo.png\" width=\"18\" height=\"20\" align=\"middle\">aligned in the middle with different sizes."            }
插入多个图片,全部是底对齐,设置不同的宽高进行缩放

            TextWithImage {                text: "Some hearts<img src=\"images/heart200.png\" width=\"20\" height=\"20\" align=\"bottom\"><img src=\"images/heart200.png\" width=\"30\" height=\"30\" align=\"bottom\"> <img src=\"images/heart200.png\" width=\"40\" height=\"40\"><img src=\"images/heart200.png\" width=\"50\" height=\"50\" align=\"bottom\">with different sizes."            }
插入网络图片,居中对齐,并设置宽高进行缩放

            TextWithImage {                text: "Resized image<img width=\"48\" height=\"48\" align=\"middle\" src=\"http://qt-project.org/images/qt13a/Qt-logo.png\">from the internet."            }
插入网络图片,居中对齐

            TextWithImage {                text: "Image<img align=\"middle\" src=\"http://qt-project.org/images/qt13a/Qt-logo.png\">from the internet."            }
指定高度(但是文本字体以及图片大小均不变),并进行垂直居中(如果在该TextWithImage外面套一个Rectangle并设置好背景色,那么显示效果就很清晰了),显示文本和图片
            TextWithImage {                height: 120                verticalAlignment: Text.AlignVCenter                text: "This is a <b>happy</b> face<img src=\"images/face-smile.png\"> with an explicit height."            }
上面使用的TextWithImage也是一个自定义的Component,单独定义在TextWithImage.qml文件中:
Text {    width: parent.width    font.pointSize: 14    wrapMode: Text.WordWrap    textFormat: Text.StyledText    horizontalAlignment: main.hAlign}
从代码上可以看出TextWithImage这个Component指定了宽度、字体大小、换行方式、文本格式是使用格式化的方式(即支持HTML标签)以及水平上的对齐方式保持和主窗口一致
注意,此处代码上使用了跨文件的id,对于代码的耦合性上考虑非常不建议。

最后添加了几个按键事件响应函数,即分别通过左上右来改变整个Rectangle的布局格式:左对齐、居中对齐、右对齐。
    Keys.onUpPressed: main.hAlign = Text.AlignHCenter    Keys.onLeftPressed: main.hAlign = Text.AlignLeft    Keys.onRightPressed: main.hAlign = Text.AlignRight
注意,这里的hAlign并不是内置成员变量,但是为什么改变这个属性的值就能修改文本的对齐方式呢?原因就在于,TextWithImage的horizontalAlignment属性使用main.hAlign变量的值,即在imgtag.qml文件中改变hAlign变量的值,然后在TextWithImage.qml文件中使用。啊,多么操蛋的设计。

styledtext-layout.qml文件

该文件演示了如何使用文本排版中的按行进行详细排版的方法,文件的主结构只有一个Text:

Rectangle {    id: main    width: 320; height: 480    focus: true    property real offset: 0    property real margin: 8    Text {....}}
吐槽:offset字段没有使用,留之何用。

Text字段详细定义了页边距为10、换行方式为按单词进行换行、字体是Times New Roman、字体大小是14、文本采用富文本格式、水平对齐方式为自动调整文本间的空格以满足每行两端对齐(类似报纸排版),然后创建了一个非常非常长的text,其中有各种富文本标签,以及自定义了一个onLineLaidOut用来详细的进行行排版。

    Text {        id: myText        anchors.fill: parent        anchors.margins: 10        wrapMode: Text.WordWrap        font.family: "Times New Roman"        font.pixelSize: 14        textFormat: Text.StyledText        horizontalAlignment: Text.AlignJustify        text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer at ante dui <a href=\"http://www.digia.com\">www.digia.com</a>.<br/>Curabitur ante est, pulvinar quis adipiscing a, iaculis id ipsum. Nunc blandit condimentum odio vel egestas.<br><ul type=\"bullet\"><li>Coffee<ol type=\"a\"><li>Espresso<li>Cappuccino<li>Latte</ol><li>Juice<ol type=\"1\"><li>Orange</li><li>Apple</li><li>Pineapple</li><li>Tomato</li></ol></li></ul><p><font color=\"#434343\"><i>Proin consectetur <b>sapien</b> in ipsum lacinia sit amet mattis orci interdum. Quisque vitae accumsan lectus. Ut nisi turpis, sollicitudin ut dignissim id, fermentum ac est. Maecenas nec libero leo. Sed ac leo eget ipsum ultricies viverra sit amet eu orci. Praesent et tortor risus, viverra accumsan sapien. Sed faucibus eleifend lectus, sed euismod urna porta eu. Quisque vitae accumsan lectus. Ut nisi turpis, sollicitudin ut dignissim id, fermentum ac est. Maecenas nec libero leo. Sed ac leo eget ipsum ultricies viverra sit amet eu orci."//! [layout]        onLineLaidOut: {....}//! [layout]    }

文本text内容详细分析包括以下内容:

  1. 纯文本:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer at ante dui
  2. 超链接:<a href=\"http://www.digia.com\">www.digia.com</a>.
  3. 换行:<br/>Curabitur ante est, pulvinar quis adipiscing a, iaculis id ipsum. Nunc blandit condimentum odio vel egestas.<br>
  4. 无符号列表:<ul type=\"bullet\"><li>Coffee<ol type=\"a\"><li>Espresso<li>Cappuccino<li>Latte</ol><li>Juice<ol type=\"1\"><li>Orange</li><li>Apple</li><li>Pineapple</li><li>Tomato</li></ol></li></ul>
  5. 段落:<p>
  6. 字体颜色设置:<font color=\"#434343\">
  7. 斜体:<i>Proin consectetur <b>sapien</b> in ipsum lacinia sit amet mattis orci interdum. Quisque vitae accumsan lectus. Ut nisi turpis, sollicitudin ut dignissim id, fermentum ac est. Maecenas nec libero leo. Sed ac leo eget ipsum ultricies viverra sit amet eu orci. Praesent et tortor risus, viverra accumsan sapien. Sed faucibus eleifend lectus, sed euismod urna porta eu. Quisque vitae accumsan lectus. Ut nisi turpis, sollicitudin ut dignissim id, fermentum ac est. Maecenas nec libero leo. Sed ac leo eget ipsum ultricies viverra sit amet eu orci.

吐槽:文本标签不配对,此处难道是测试Qt对于不标准的格式的兼容性吗??

lineLaidOut信号和onLineLaidOut事件响应函数

This signal is emitted for each line of text that is laid out during the layout process. The specified line object provides more details about the line that is currently being laid out.
This gives the opportunity to position and resize a line as it is being laid out. It can for example be used to create columns or lay out text around objects.
The corresponding handler is onLineLaidOut.
通过官方说明,我们可以了解,lineLaidOut信号是在每行文本准备布局的时候触发,开发人员可以通过自定义onLineLaidOut事件响应函数来进行个性化的按行进行排版。

        onLineLaidOut: {            line.width = width / 2  - (margin)            if (line.y + line.height >= height) {                line.y -= height - margin                line.x = width / 2 + margin            }        }
示例代码中,是将每行的宽度减半再减去一个边距值,即只显示在左半边;但是如果左半边已经超出下面的边界怎么办?通过调整line.x和line.y来排版到空白的右半边,具体的效果图如下:

注意:右半边部分的字体是斜体,颜色和左半边也不一样,所以视觉效果差异很大。

总结

学到的知识点:
  1. Component元素以及onCompleted事件响应函数
  2. 一个Qt动画的基本构成
  3. 了解了SequentialAnimation动画、NumberAnimation动画、PauseAnimation动画以及ScriptAction动作
  4. 如何加载字体(使用name和source,包括本地和网络)
  5. 如何设置文本的样式(字体、大小、颜色、加粗、斜体、对齐、大小写设置)
  6. 学习了怎么使用ListView
  7. 学习了Column和Row的使用方式
  8. 学习了使用property定义成员变量
  9. 学习了怎么使用Flickable
  10. 学习了富文本格式下,如何进行排版(文本和图片交叉、设置图片大小、设置文本和图片的对齐方式)
  11. 学习了Text元素内如何针对每行进行排版
经过大概3天的时间,将Text下的6个Example进行了仔细学习,基本覆盖了Text的方方面面。Example写的比较详细和全面,但是也有很多坑和槽点。
0 0
原创粉丝点击