zoukankan      html  css  js  c++  java
  • qml demo分析(rssnews-常见新闻布局)

    一、效果展示

      今儿来分析一篇常见的ui布局,完全使用qml编写,ui交互效果友好,如图1所示,是一个常见的客户端新闻展示效果,左侧是一个列表,右侧是新闻详情。

    图1 新闻效果图

    二、源码分析

      首先先来总体分析下该示例代码的工程目录,如图2所示,总共有6个qml文件。其中BusyIndicator和ScrollBar组件是qml已经存在的组件,NewsDelegate组件是新闻详情页中的一项,CategoryDelegate组件是左侧列表中的一项,RssFeeds组件是左侧新闻列表数据源,rssnews文件是主程序文件。

    图2 工程目录

      结合图1看程序工程目录,是不是觉着一目了然。NewsDelegate组件和CategoryDelegate组件是两个绘制代理,RssFeeds组件提供一个视图数据源,其中还有一个视图的数据源在rssnews.qml文件内部定义。接下来我主要分析下主程序文件rssnews.qml和NewsDelegate绘制代理

    1、主程序文件

      主程序文件代码如下,程序中关键的地方都有注释,相比于之前的文章注释少了许多,大多都是一些常见的属性没有了注释。

      1 import QtQuick 2.2
      2 import QtQuick.XmlListModel 2.0
      3 import QtQuick.Window 2.1
      4 import "./content"
      5 
      6 Rectangle {
      7     id: window
      8 
      9      800
     10     height: 480
     11 
     12     property string currentFeed: rssFeeds.get(0).feed//get方法为ListModel内置方法,返回指定索引item
     13     property bool loading: feedModel.status === XmlListModel.Loading//是否是加载中。。。
     14     property bool isPortrait: Screen.primaryOrientation === Qt.PortraitOrientation
     15 
     16     onLoadingChanged: {
     17         if (feedModel.status == XmlListModel.Ready)
     18             list.positionViewAtBeginning()
     19     }
     20 
     21     RssFeeds { id: rssFeeds }
     22 
     23     XmlListModel {
     24         id: feedModel
     25 
     26         source: "http://" + window.currentFeed
     27         query: "/rss/channel/item[child::media:content]"
     28         namespaceDeclarations: "declare namespace media = 'http://search.yahoo.com/mrss/';"
     29 
     30         XmlRole { name: "title"; query: "title/string()" }
     31         // Remove any links from the description
     32         XmlRole { name: "description"; query: "fn:replace(description/string(), '<a href=.*/a>', '')" }
     33         XmlRole { name: "image"; query: "media:content/@url/string()" }
     34         XmlRole { name: "link"; query: "link/string()" }
     35         XmlRole { name: "pubDate"; query: "pubDate/string()" }
     36     }
     37 
     38     ListView {//左侧新闻列表
     39         id: categories
     40         property int itemWidth: 190
     41 
     42          isPortrait ? parent.width : itemWidth
     43         height: isPortrait ? itemWidth : parent.height
     44         orientation: isPortrait ? ListView.Horizontal : ListView.Vertical
     45         anchors.top: parent.top
     46         model: rssFeeds
     47         delegate: CategoryDelegate { itemSize: categories.itemWidth }
     48         spacing: 3
     49     }
     50 
     51     ScrollBar {
     52         id: listScrollBar
     53 
     54         orientation: isPortrait ? Qt.Horizontal : Qt.Vertical
     55         height: isPortrait ? 8 : categories.height;
     56          isPortrait ? categories.width : 8
     57         scrollArea: categories;//关联滚动的区域 
     58         anchors.right: categories.right//锚点定位
     59     }
     60 
     61     ListView {//右侧新闻详情  由多个项NewsDelegate组成
     62         id: list
     63 
     64         anchors.left: isPortrait ? window.left : categories.right
     65         anchors.right: closeButton.left
     66         anchors.top: isPortrait ? categories.bottom : window.top
     67         anchors.bottom: window.bottom
     68         anchors.leftMargin: 30
     69         anchors.rightMargin: 4
     70         clip: isPortrait
     71         model: feedModel
     72         footer: footerText//页脚  视图最底部的修饰
     73         delegate: NewsDelegate {}
     74     }
     75 
     76     ScrollBar {
     77         scrollArea: list
     78          8
     79         anchors.right: window.right
     80         anchors.top: isPortrait ? categories.bottom : window.top
     81         anchors.bottom: window.bottom
     82     }
     83 
     84     Component {
     85         id: footerText
     86 
     87         Rectangle {
     88              parent.width
     89             height: closeButton.height
     90             color: "lightgray"
     91 
     92             Text {
     93                 text: "RSS Feed from Yahoo News"
     94                 anchors.centerIn: parent
     95                 font.pixelSize: 14
     96             }
     97         }
     98     }
     99 
    100     Image {//关闭按钮  点击退出程序
    101         id: closeButton
    102         source: "content/images/btn_close.png"
    103         scale: 0.8
    104         anchors.top: parent.top
    105         anchors.right: parent.right
    106         anchors.margins: 4
    107         opacity: (isPortrait && categories.moving) ? 0.2 : 1.0
    108         Behavior on opacity {
    109             NumberAnimation { duration: 300; easing.type: Easing.OutSine }
    110         }
    111 
    112         MouseArea {
    113             anchors.fill: parent
    114             onClicked: {
    115                 Qt.quit()
    116             }
    117         }
    118     }
    119 }

      footer属性指定页脚,就像word文件的页脚一样,位于ListView最低端,如图1中第一帧的RSS Feed from Yahoo News字段,其实每个页面都有这个字段,只是都位于ListView内容最低端。

    2、新闻详情页中项

      如图1所示,该NewsDelegate绘制代理是右侧页面中的一条新闻项,右侧页面是一个ListView,内部有许多项组成,每一项都是由该代理绘制。

     1 //新闻详情中的一条
     2 import QtQuick 2.2
     3 
     4 Column {
     5     id: delegate
     6      delegate.ListView.view.width
     7     spacing: 8
     8 
     9     // Returns a string representing how long ago an event occurred
    10     function timeSinceEvent(pubDate) {
    11         var result = pubDate;
    12 
    13         // We need to modify the pubDate read from the RSS feed
    14         // so the JavaScript Date object can interpret it
    15         var d = pubDate.replace(',','').split(' ');
    16         if (d.length != 6)
    17             return result;
    18 
    19         var date = new Date([d[0], d[2], d[1], d[3], d[4], 'GMT' + d[5]].join(' '));
    20 
    21         if (!isNaN(date.getDate())) {
    22             var age = new Date() - date;
    23             var minutes = Math.floor(Number(age) / 60000);
    24             if (minutes < 1440) {
    25                 if (minutes < 2)
    26                     result = qsTr("Just now");
    27                 else if (minutes < 60)
    28                     result = '' + minutes + ' ' + qsTr("minutes ago")
    29                 else if (minutes < 120)
    30                     result = qsTr("1 hour ago");
    31                 else
    32                     result = '' + Math.floor(minutes/60) + ' ' + qsTr("hours ago");
    33             }
    34             else {
    35                 result = date.toDateString();
    36             }
    37         }
    38         return result;
    39     }
    40 
    41     Item { height: 8;  delegate.width }
    42 
    43     Row {
    44          parent.width
    45         spacing: 8
    46 
    47         Column {
    48             Item {//占位
    49                  4
    50                 height: titleText.font.pixelSize / 4
    51             }
    52 
    53             Image {
    54                 id: titleImage
    55                 source: image//image对应模型中的字段
    56             }
    57         }
    58 
    59         Text {
    60             id: titleText
    61 
    62             text: title//image对应模型中的字段
    63              delegate.width - titleImage.width
    64             wrapMode: Text.WordWrap
    65             font.pixelSize: 26
    66             font.bold: true
    67         }
    68     }
    69 
    70     Text {//距离新闻发布时间+带有link字样的超链接
    71          delegate.width
    72         font.pixelSize: 12
    73         textFormat: Text.RichText
    74         font.italic: true
    75         text: timeSinceEvent(pubDate) + " (<a href="" + link + "">Link</a>)"
    76         onLinkActivated: {
    77             Qt.openUrlExternally(link)//link对应模型中的字段
    78         }
    79     }
    80 
    81     Text {
    82         id: descriptionText
    83 
    84         text: description//对应模型中的字段
    85          parent.width
    86         wrapMode: Text.WordWrap//换行模式 字不能拆分
    87         font.pixelSize: 14//字号
    88         textFormat: Text.StyledText//支持一些基本的文本样式标记
    89         horizontalAlignment: Qt.AlignLeft//水平靠左
    90     }
    91 }

    三、小节

      看了有一些qml示例代码,也一直主要在分析qml代码,本小节插播一段个人总结吧,也算是小小感慨下。

      不同于以往的QWidget窗口程序,qml写界面非常简洁,从以往的示例中就能感觉的到,在友好交互方面qml比QWidget做的好,比如List下拉到头时的弹簧效果、完美的加载中展示和远程图片加载等等。qml是声明性语言,即不在像C++那样需要编译后才能运行,在代码编写时只需要关注ui,可以根据需要自己封装组件,把需要外界使用的属性使用导出的方式暴露给外界,每一个组件属性都有OnPropertyChanged槽,当属性发生变化时该槽随即执行。

      可能是由于一直从事C++相关的工作,没有声明性语言的基础,在阅读qml代码时总是感觉有一种代码散乱无处整理的感觉,现在小小的示例代码亦是如此,等到正真做起项目来不知道会是怎样一番场景。比如说绘制代理在访问一些属性时,直接访问的是模型中的字段,如果字段名称写错,这种错误只能到运行时异常后才能慢慢排查,类似于这样的代码其实有很多,突然之间就跳出一句无厘头的代码,这在C++中根本不可能出现。。。呵呵呵。。。

  • 相关阅读:
    python 合并 Excel 单元格
    python 设置 Excel 表格的行高和列宽
    Python 用 openpyxl 模块统计 Excel 表格中的数据,以字典形式写入 py 文件
    python 打印字母阶梯和金字塔
    python 用 openpyxl 读取 Excel 表格中指定的行或列
    Python 的 filter() 函数
    Python 的 map() 函数
    python 之 range() 函数
    python 的 reduce() 函数
    python 之 lambda 函数
  • 原文地址:https://www.cnblogs.com/swarmbees/p/6550448.html
Copyright © 2011-2022 走看看