精华内容
下载资源
问答
  • qml界面设计(转)

    2014-05-07 08:14:36
    QML编程入门 欢迎来到QML的世界!QML是一款齐新的陈述性UI编程语言。在本手册中,我们将用QML建立一个简单的文本编辑顺序。在阅读完本手册后,你将能够用QML和Qt C++开发自己的顺序。 Directory{  id:...

    QML编程入门

    欢迎来到QML的世界!QML是一款齐新的陈述性UI编程语言。在本手册中,我们将用QML建立一个简单的文本编辑顺序。在阅读完本手册后,你将能够用QML和Qt C++开发自己的顺序。

    1. Directory{
    2.   id:directory
    3.   filename: textInput.text
    4.   onDirectoryChanged: fileDialog.notifyRefresh()
    5. }

    通过运行qmlviewer工具,并将QML文件路径作为参数传递给她,你就能够运行QML的实例代码了。我们假设你对Qt的编译环节有最基本的了解,以便运行本手册中的C++代码。

    1. Behavior{
    2.   NumberAnimation{property: "rotation";easing.type: Easing.OutExpo }
    3. }

    定义按钮和菜单

    基础组件 – 按钮

    我们从建立按钮开始文本编辑器的工作。功能上讲,按钮是一个能够接受鼠标事件的区域和一个标签。在用户点击按钮后,按钮才开始工作。

    你的浏览器不支持图片表现

    1. import Qt 4.7
    2. Rectangle {
    3.   id: simpleb京东utton
    4.   color: "grey"
    5.   width: 150; height: 75
    6.  
    7.   Text{
    8.     id: buttonLabel
    9.     anchors.centerIn: parent
    10.     text: "button label"
    11.   }
    12. }

    首先,我们使用“import Qt 4.7”导入预定义的QML元素,以便进一步使用。所有的QML文件中都必须使用该行。需要注意的是,所使用的Qt模块的版本号也必须在该声明中提及。

    这里用到的简单Rectangle的标识(即id属性)为simplebutton。在QML中,元素的属性定义体式格局为“属性名:值”。这里,值grey被赋给Rectangle的color属性。类似的,我们也给定了Rectangle的width和height值。

    Text元素是不成编辑的文本域。我们将其命名为buttonLabel,并通过设置其text属性来定义其表现的内容。通过设置该标签的anchors.centerIn属性值为parent,我们将标签定位于Rectangle的中心位置。锚可以和其他元素的锚相绑定,从而简化了布局。

    我们将这段代码保存为SimpleButton.qml文件,然后运行qmlviewer,并将文件路径作为参数传递,就能看到如下所示的灰色矩形和文本标签。

    Q_PROPERTY宏声明了属性,使其能够通过Qt的元工具系统被读写。例如QString类型的filename属性,可以通过filename()函数进行读取,并通过setFilename()函数进行写操纵。此外,还有一个名为filenameChanged()的信号与其绑定,会在该属性被改变时触发。读写的函数都在头文件中被定义为public函数。

    1. #include <QtDeclarative/QDeclarativeExtensionPlugin>
    2.  
    3. class DialogPlugin : public QDeclarativeExtensionPlugin
    4. {
    5.   Q_OBJECT
    6.  
    7. public:
    8.   void registerTypes(const char *uri);
    9.  
    10. };

    1. Rectangle{
    2.   id:simplebutton
    3.   ...
    4.  
    5.   MouseArea{
    6.     id: buttonMouseArea
    7.  
    8.     anchors.fill: parent // 将鼠标区域设置为该Rectangle所在的区域
    9.     // onClicked处置责罚鼠标点击事件
    10.     onClicked: console.log(buttonLabel.text + " clicked" )
    11.   }
    12. }

    我们在simplebutton内包含了一个MouseArea元素,其描述了能够接受鼠标事件的区域。这里,我们将鼠标的区域设置为整个Rectangle所在的区域。anchors.fill供给了一种用以访问属性anchors所具有的属性fill的方式。QML使用基于锚的布局,以便元素之间相互绑定,从而建立稳定的布局。

    MouseArea元素预定义了多个信号处置责罚方式,会在相应事件被触发时自动调用。例如,onClicked会在鼠标点击事件(默认为左键)发生时被调用。我们能够将需要进行的任务绑定到onClicked上。这里,我们调用console.log()来输出相应信息。值得一提的是,console.log()能够在调试时作为文本输出工具而大显身手。

    这段在SimpleButton.qml中的代码已经充足被用于在屏幕上表现按钮,并在按钮被点击时输出一段文本信息。

    The Directory element is used in the FileMenu.qml file and it notifies the FileDialog element that the directory refreshed its contents. This notification is performed in the signal handler, onDirectoryChanged.

    Button.qml中的代码展示了一个功能完整的按钮。这里展示的代码中则省略了一部分,由于在前面已经介绍过,或是和当前的讨论没有直接关系。

    我们可以通过“property 类型 名称”来自定义新的属性。这里,名为buttonColor的新属性就是一例。其被定义为color类型,并赋值为lightblue。buttonColor被进一步用在条件操纵符中,以决定按钮的填充色。除使用冒号“:”外,属性的赋值也可以用“=”进行。自定义的属性使得外部元素也能够访问内部组件。在QML中,基本类型包括int、string、real等,以及一个variant类型。

    The list properties need to be explored further. This is because list properties use callbacks to access and modify the list contents. The list property is of type QDeclarativeListProperty<File>. Whenever the list is accessed, the accessor function needs to return a QDeclarativeListProperty<File>. The template type, File, needs to be a QObject derivative. Further, to create the QDeclarativeListProperty, the list’s accessor and modifiers need to be passed to the consructor as function pointers. The list, a QList in our case, also needs to be a list of File pointers.

    buttonClick()信号在Button.qml文件中被声明,以“取代”onClicked信号。所有的信号的处置责罚器都被自动建立,其名称为on加上信号名。这里,onButtonClick是buttonClick的处置责罚器。这里,onClicked处置责罚器会调用onButtonClick处置责罚器,以输出一段文本。onButtonClick则使得外部工具能够访问Button的鼠标区域。例如,某些元素可能定义了多个MouseArea,而使用buttonClick信号则能够更好的区分不同MouseArea发出的信号。

    现在,我们已经拥有了充足的知识来使用QML建立元素,并处置责罚基本的鼠标事件。我们也在Rectangle内建立了一个Text标签,自定义了其属性,并实现了对相关信号的处置责罚。在元素内建立元素的概念会在这个文本编辑器中重复出现。

    除非能够执行一定的功能,否则按钮是没用的。在下一节中,我们将建立一个包含了若干个按钮的菜单。

    你的浏览器不支持图片表现

    另一个对属性改变加加动画的方式是声明Behavior元素。转换只在状态变化的过程中有效,并且Behavior能够为属性的变化设置动画。在这个文本编辑器中,该箭头使用了NumberAnimation来为其rotation属性设置动画。

    你的浏览器不支持图片表现

    装饰文本编辑器

    实现绘图接口

    我们的文本编辑器看上去特别很是简单,所以我们需要装饰一下。通过使用QML,我们能够给文本编辑器加加转换和动画效果。考虑到菜单栏就占据了1/3的空间,所以有必要使他仅仅在我们需要时才出现。

    我们可以通过点击菜单名来访问相应的菜单项。菜单的交换也是直观和有动感的。

    1. Q_PROPERTY(QDeclarativeListProperty<File> files READ files CONSTANT )

    1. Row{
    2.   anchors.centerIn: parent
    3.   spacing: parent.width/6
    4.  
    5.   Button{
    6.     id: loadButton
    7.     buttonColor: "lightgrey"
    8.     label: "Load"
    9.   }
    10.  
    11.   Button{
    12.     buttonColor: "grey"
    13.     id: saveButton
    14.     label: "Save"
    15.   }
    16.  
    17.   Button{
    18.     id: exitButton
    19.     label: "Exit"
    20.     buttonColor: "darkgrey"
    21.  
    22.     onButtonClick: Qt.quit()
    23.   }
    24. }

    我们定义了三个Button元素。他们都在Row元素内被定义,Row元素能够自动将其子元素放置在同一行中。Button的定义则位于同一目录下的Button.qml文件中,在前一节中已经讨论和使用过。我们可以在这些新建立的按钮中加加新的属性,从而覆盖在Button.qml中定义的那些属性。点击名为exitButton的按钮能够关闭当前关闭当前窗口。而在Button.qml中定义的onButtonClick也同样会被调用。

    状态就是各种配置的一个简单集合,用State元素表示。一系列的状态能够被一一列出,并绑定到状态属性上。在我们的顺序中,有两个被称为DRAWER_CLOSED和DRAWER_OPEN的状态。配置通过PropertyChanges元素被声明。在DRAWER_OPEN状态上,有四个项能够接受属性的变化。第一个目标,menuBar,会将其y属性改为0。类似的,textArea会在DRAWER_OPEN状态时降低到一个新的位置。而textArea、绘图器及其图标都邑改变属性以实现当前状态。

    Row元素声明在Rectangle的内部,即建立了一个矩形容器来存放按钮行。这个额外的矩形供给了一个间接的体式格局来管理菜单内的按钮行。

    编辑菜单的声明和这里提到的方式类似,用到的按钮包含以下标签:Copy、Paste和Select All。

    你的浏览器不支持图片表现

    1. function ensureVisible(r){
    2.   if (contentX >= r.x)
    3.     contentX = r.x;
    4.   else if (contentX+width <= r.x+r.width)
    5.     contentX = r.x+r.width-width;
    6.   if (contentY >= r.y)
    7.     contentY = r.y;
    8.   else if (contentY+height <= r.y+r.height)
    9.     contentY = r.y+r.height-height;
    10. }

    实现菜单栏

    我们的文本编辑顺序需要能够在菜单栏上表现菜单。菜单栏需要在用户选择需要表现的菜单后表现其中的菜单项。菜单的交换意味着菜单需要比简单在一行中表现更多的布局。QML使用模型和视图布局来处置责罚数据。

    使用数据模型和视图

    QML能够使用不同的视图来揭示数据模型。我们的菜单栏将以列表的形式揭示菜单,并将菜单名在一列中表现。菜单的列表被定义在VisualItemModel中。VisualItemModel元素包含了若干已经拥有视图的项,例如Rectangle元素和导入的其他UI元素。其他如ListModel模型则需要一个delegate来表现其中的数据。

    我们在menuListModel中声明了两个可视化项,FileMenu和EditMenu。我们自定义了这两个菜单,并用ListView来揭示它们。MenuBar.qml文件中包含了相应的QML声明,而编辑菜单则在EditMenu.qml中定义。

    1. VisualItemModel{
    2.   id: menuListModel
    3.   FileMenu{
    4.     width: menuListView.width
    5.     height: menuBar.height
    6.     color: fileColor
    7.   }
    8.   EditMenu{
    9.     color: editColor
    10.     width:  menuListView.width
    11.     height: menuBar.height
    12.   }
    13. }

    ListView元素能够通过delegate来揭示模型的数据。而delegate能够通过声明模型项来在Row元素或格子中揭示数据。这里的menuListModel已经具有了可视化项,因此我们不再需要声明delegate。

    1. QDeclarativeListProperty  ( QObject * object, void * data, AppendFunction append, CountFunction count = 0, AtFunction at = 0,ClearFunction clear = 0 )
    2. QDeclarativeListProperty<File>( this, &m_fileList, &appendFiles, &filesSize, &fileAt,  &clearFilesPtr );

    此外,ListView担当自Flickable,使得其能够相应鼠标的拖拽和其他姿势。上面这段代码的最后一部分设置了Flickable的属性,以便建立所需的效果。特别的,highlightMoveDuration属性改变了按键转换。更高的highlightMoveDuration值意味着更慢的菜单转换。

    labelList矩形的z值为1,意味着它表现在菜单栏之前。z值越高的项表现得越靠前,默认值为0。

    1. Rectangle{
    2.   id: labelList
    3.   ...
    4.   z: 1
    5.   Row{
    6.     anchors.centerIn: parent
    7.     spacing:40
    8.     Button{
    9.       label: "File"
    10.       id: fileButton
    11.       ...
    12.       onButtonClick: menuListView.currentIndex = 0
    13.     }
    14.     Button{
    15.       id: editButton
    16.       label: "Edit"
    17.       ...
    18.       onButtonClick:    menuListView.currentIndex = 1
    19.     }
    20.   }
    21. }

    在FileMenu.qml文件中:

    你的浏览器不支持图片表现

    建立文本编辑器

    声明TextArea

    如果没有可编辑的文本域,我们的顺序就不能被称为文本编辑器了。而QML就恰好供给了一个TextEdit元素来进行多行的文本编辑。TextEdit和Text元素不同,后者不允许用户直接编辑其中的文本。

    1. TextEdit{
    2.   id: textEditor
    3.   anchors.fill:parent
    4.   width:parent.width; height:parent.height
    5.   color:"midnightblue"
    6.   focus: true
    7.  
    8.   wrapMode: TextEdit.Wrap
    9.  
    10.   onCursorRectangleChanged: flickArea.ensureVisible(cursorRectangle)
    11. }

    1. signal notifyRefresh()
    2. onNotifyRefresh: dirView.model = directory.files

    ListView通过索引维护模型项,并能够通过索引访问模型中的每一个可视项。改变currentIndex能够有效的改变ListView中的高亮项。比如这里菜单项的头部就是如此。在同一行中有两个按钮,在点击后都能够当先表现的菜单。点击fileButton能够将当前菜单设置为文件菜单,而FileMenu的索引为0,由于其是在menuListModel中第一个定义的。类似的,点击editButton也能够将当前菜单改变为EditMenu。

    通过使用导入和自定义先前定义的组件,我们能够通过组合这些菜单页来建立菜单栏。

    为文本编辑器组合组件

    我们现在可以用QML建立文本编辑器的布局了。这个文本编辑器有两个组件:先前建立的菜单栏和文本区域。QML允许我们重用组件,因此我们能够通过导入组件和在必要时自定义来简化代码。我们的文本编辑器的窗口包含两个部分:三分之一为菜单栏,剩下三分之二为文本域。菜单栏在其他元素前表现。

    用QML构建用户界面

    我们要建立的顺序是一个简单的文本编辑器,能够加载、保存,并对文本文件进行简单操纵。本手册包括两部分:第一部分将使用QML设想顺序布局和行为,第二部分则用Qt C++实现文件的加载和保存。通过使用Qt的Meta-Object系统,我们能够将C++函数以属性的形式表露给QML元素。通过组合QML和Qt C++,我们能够有效的别离顺序的界面和逻辑。

    1. Rectangle{
    2.   id: screen
    3.   width: 1000; height: 1000
    4.  
    5.   // 屏幕被分为MenuBar和TextArea两部分。MenuBar占据1/3的空间
    6.   property int partition: height/3
    7.  
    8.   MenuBar{
    9.     id:menuBar
    10.     height: partition
    11.     width:parent.width
    12.     z: 1
    13.   }
    14.  
    15.   TextArea{
    16.     id:textArea
    17.     anchors.bottom:parent.bottom
    18.     y: partition
    19.     color: "white"
    20.     height: partition*2
    21.     width:parent.width
    22.   }
    23. }

    状态改变需要辅以更加流畅的转换。状态间的转换通过Transition元素定义,并且能够绑定到该项的transition属性上。这里,我们的文本编辑器在其状态转换到DRAWER_OPEN或者DRAWER_CLOSED时都邑触发一个转换。重要的是,转换需要设置一个from和一个to属性,定义在何时被触发。我们也可以用*使其在任何状态转换发生时被触发。

    1. Directory{
    2.   id: directory
    3.  
    4.   filesCount
    5.   filename
    6.   fileContent
    7.   files
    8.  
    9.   files[0].name
    10. }

    我们需要加加一个绘图接口,在被点击时表现或收回菜单栏。在我们的实现中,我们有一个矩形来响应鼠标点击事件。和顺序一样,这个绘图接口有“打开”和“关闭”两个状态。该绘图项是一个高度不大的矩形。其内部有一个Image元素来表现箭头图标。该绘图接口向整个顺序赋予了一个状态,以响应用户的鼠标点击事件。

    1. Rectangle{
    2.   id:drawer
    3.   height:15
    4.  
    5.   Image{
    6.     id: arrowIcon
    7.     source: "images/arrow.png"
    8.     anchors.horizontalCenter: parent.horizontalCenter
    9.   }
    10.  
    11.   MouseArea{
    12.     id: drawerMouseArea
    13.     anchors.fill:parent
    14.     onClicked:{
    15.       if (screen.state == "DRAWER_CLOSED"){
    16.         screen.state = "DRAWER_OPEN"
    17.       }
    18.       else if (screen.state == "DRAWER_OPEN"){
    19.         screen.state = "DRAWER_CLOSED"
    20.       }
    21.     }
    22.     ...
    23.   }
    24. }

    你的浏览器没法表现图片

    1. states:[
    2.   State {
    3.     name: "DRAWER_OPEN"
    4.     PropertyChanges { target: menuBar; y: 0}
    5.     PropertyChanges { target: textArea; y: partition + drawer.height}
    6.     PropertyChanges { target: drawer; y: partition}
    7.     PropertyChanges { target: arrowIcon; rotation: 180}
    8.   },
    9.   State {
    10.     name: "DRAWER_CLOSED"
    11.     PropertyChanges { target: menuBar; y:-height; }
    12.     PropertyChanges { target: textArea; y: drawer.height; height: screen.height - drawer.height }
    13.     PropertyChanges { target: drawer; y: 0 }
    14.     PropertyChanges { target: arrowIcon; rotation: 0 }
    15.   }
    16. ]

    通过导入可重用的组件,我们的TextEditor的代码显得相当简单。我们能够自定义主顺序,而不用担忧已经被定义好的属性等。通过该途径,顺序布局和UI组件都能够很容易的被建立。

    在转换过程中,我们可以将动画和属性改变相绑定。我们能够用NumberAnimation元素将menuBar从y:0到y:-partition的位置改变加加动画效果。我们声明目标的属性会以一个特定的曲线在一段时间内改变。这个曲线(easing curve)负责控制动画的速度,以及在状态转化间的行为。我们在这里选择的曲线是Easing.OutQuint,能够使移动在快结束时放慢。请参考QML的相关文章获取更多的动画信息。

    1. transitions: [
    2.   Transition {
    3.     to: "*"
    4.     NumberAnimation { target: textArea; properties: "y, height"; duration: 100; easing.type:Easing.OutExpo }
    5.     NumberAnimation { target: menuBar; properties: "y"; duration: 100; easing.type: Easing.OutExpo }
    6.     NumberAnimation { target: drawer; properties: "y"; duration: 100; easing.type: Easing.OutExpo }
    7.   }
    8. ]

    建立菜单页

    到目前为止,我们已经讨论了若何在单个UML文件中建立元素,并设定要执行的动作。现在,我们将讨论若何引入和重用其他文件中定义的QML元素。

    In TextEditor.qml:

    用Qt C++扩展QML

    现在,我们已经拥有了文本编辑器的界面,接下来就要用C++来实现其功能。通过QML和C++的殽杂使用,我们能够用Qt开发顺序的逻辑。我们可以在C++顺序中通过Qt的Declarative类来建立QML上下文,并在Graphics Scene中表现QML元素。此外,我们也能将C++代码编译成插件,以便在qmlviewer中被调用。这里,我们会将开发后的顺序编译成插件。如许,我们就能直接(用qmlviewer)加载QML文件,而不必运行一个可执行文件了。

    回想那些有状态和动画的组件,我们能够改良其外观。在Button.qml中,我们能够定义按钮被点击时的颜色和scale属性,还能通过ColorAnimation来为颜色改变加加动画,也能用NumberAnimation为数字属性的改变加加动画效果。下面的“on 属性名“语法在为单个属性加加动画时特别很是有用。

    在Button.qml中:

    此外,我们能够通过加加例如gradients和透明度等颜色效果来改良QML组件的外观。声明一个Gradient元素能够覆盖元素的颜色属性。你可以在gradient中用GradientStop元素来声明颜色。gradient取值为0.0到1.0之间。

    在MenuBar.qml中:

    1. gradient: Gradient {
    2.   GradientStop { position: 0.0; color: "#8C8F8C" }
    3.   GradientStop { position: 0.17; color: "#6A6D6A" }
    4.   GradientStop { position: 0.98;color: "#3F3F3F" }
    5.   GradientStop { position: 1.0; color: "#0e1B20" }
    6. }

    这里的gradient被用到菜单栏上来表现渐变的深度。第一个颜色被0.0位置定义,最后一个则在1.0处。

    接下来做什么

    我们已经完成了对这个简单的文本编辑器的用户界面的构建。现在,我们可以用普通的Qt和C++来实现顺序的逻辑了。QML能够很好的被用作构建原型的工具,将顺序的逻辑和UI设想相别离。

    你的浏览器不支持表现图片

    1. TEMPLATE = lib
    2. CONFIG += qt plugin
    3. QT += declarative
    4.  
    5. DESTDIR +=  ../plugins
    6. OBJECTS_DIR = tmp
    7. MOC_DIR = tmp
    8.  
    9. TARGET = FileDialog
    10.  
    11. HEADERS +=     directory.h \
    12.         file.h \
    13.         dialogPlugin.h
    14.  
    15. SOURCES +=    directory.cpp \
    16.         file.cpp \
    17.         dialogPlugin.cpp

    将C++类表露给QML

    我们会用Qt和C++实现文件的加载和保存。通过注册,我们可以在QML中使用C++类和函数。然后将C++代码编译称Qt的插件,以便QML文件能够加载。

    在我们的顺序中,我们需要建立以下项:

    1. Directory类已负责处置责罚目录相关的操纵
    2. File类是QObject,揭示目录里的文件列表
    3. 插件类以便将C++类注册到QML上下文
    4. Qt工程文件,以便编译插件
    5. 一个qmldir文件,告诉qmlviewer何处加载插件

    建立Qt plugin

    我们需要在Qt工程文件中加加如下代码以编译插件,包括必要的源文件、头文件,以及Qt模块等。所有的C++代码和工程文件都存放在filedialog目录下。

    通过在onEntered和onExited上加加相应代码,我们能够在鼠标移动进、出按钮时改变其颜色。

    章节:
    定义按钮和菜单
    实现菜单栏
    建立文本编辑器
    装饰文本编辑器
    用Qt C++扩展QML

    特别的,我们加加了Qt的declarative模块,将工程设置为插件类型,并把编译好的插件放到上层目录的plugins目录下。

    向QML注册类

    在dialogPlugin.h文件中:

    The properties can then be used in QML as part of the Directory element’s properties. Note that we do not have to create an identifier id property in our C++ code.

    我们的插件类DialogPlugin担当自QDeclarativeExtensionPlugin,需要实现其registerTypes()函数。而相应的源文件dialogPlugin.cpp如下所示:

    DialogPlugin.cpp:

    1. #include "dialogPlugin.h"
    2. #include "directory.h"
    3. #include "file.h"
    4. #include <QtDeclarative/qdeclarative.h>
    5.  
    6. void DialogPlugin::registerTypes(const char *uri){
    7.  
    8.   qmlRegisterType<Directory>(uri, 1, 0, "Directory");
    9.   qmlRegisterType<File>(uri, 1, 0,"File");
    10. }
    11.  
    12. Q_EXPORT_PLUGIN2(FileDialog, DialogPlugin);

    这里的registerTypes()函数将我们的File和Directory两个类注册到QML上下文中。注册用的函数qmlRegisterType需要相应的类名作为其模板,一个主版本号、副版本号,以及QML中展示的类名作为参数。

    最后,我们需要用Q_EXPORT_PLUGIN2宏来导出插件。注意,我们在头文件的类声明中也加加了Q_OBJECT宏,需要运行qmake来自动建立相应的元工具代码。

    在C++类中建立QML属性

    我们能够使用C++,通过Qt的元工具系统来建立QML元素。我们能够通过信号和槽机制来实现属性,使其能被Qt用到QML上。

    我们需要为文本编辑器供给加载和保存文件的功能。典型的,该功能包含在文件对话框中。幸运的是,我们可以使用QDir、QFile和QTextStream来实现目录的读取和输入输出流。

    1. color: buttonMouseArea.pressed ? Qt.darker(buttonColor, 1.5) : buttonColor
    2. Behavior on color { ColorAnimation{ duration: 55} }
    3.  
    4. scale: buttonMouseArea.pressed ? 1.1 : 1.00
    5. Behavior on scale { NumberAnimation{ duration: 55} }

    1. class Directory : public QObject{
    2.  
    3.   Q_OBJECT
    4.  
    5.   Q_PROPERTY(int filesCount READ filesCount CONSTANT)
    6.   Q_PROPERTY(QString filename READ filename WRITE setFilename NOTIFY filenameChanged)
    7.   Q_PROPERTY(QString fileContent READ fileContent WRITE setFileContent NOTIFY fileContentChanged)
    8.   Q_PROPERTY(QDeclarativeListProperty<File> files READ files CONSTANT )
    9.  
    10.   ...

    该Directory类使用了Qt的元工具系统来注册其为文件操纵而需要的属性,并以插件形式导出到QML中作为Directory元素。这里用Q_PROPERTY宏定义的每一个属性都被导出称一个QML属性。

    菜单能够表现多个菜单项,每一个菜单项都能够执行一个特定的动作。在QML中,我们能用不同的方式建立菜单。首先,我们将建立建立一个包含多个按钮的菜单,点击这些按钮将触发不同的动作。菜单的源代码在FileMenu.qml文件中。

    The FileDialog element will display the contents of a directory by reading its list property called files. The files are used as the model of a GridView element, which displays data items in a grid according to a delegate. The delegate handles the appearance of the model and our file dialog will simply create a grid with text centered in the middle. Clicking on the file name will result in the appearance of a rectangle to highlight the file name. The FileDialog is notified whenever the notifyRefresh signal is emitted, reloading the files in the directory.

    1. ListView{
    2.   id: menuListView
    3.  
    4.   // 锚被定义来反应窗口的锚
    5.   anchors.fill:parent
    6.   anchors.bottom: parent.bottom
    7.   width:parent.width
    8.   height: parent.height
    9.  
    10.   // 该模型包含了数据
    11.   model: menuListModel
    12.  
    13.   // 控制菜单交换时的移动
    14.   snapMode: ListView.SnapOneItem
    15.   orientation: ListView.Horizontal
    16.   boundsBehavior: Flickable.StopAtBounds
    17.   flickDeceleration: 5000
    18.   highlightFollowsCurrentItem: true
    19.   highlightMoveDuration:240
    20.   highlightRangeMode: ListView.StrictlyEnforceRange
    21. }

    在cppPlugins.pro文件中:

    The files list property is a list of all the filtered files in a directory. The Directory class is implemented to filter out invalid text files; only files with a .txt extension are valid. Further, QLists can be used in QML files by declaring them as a QDeclarativeListProperty in C++. The templated object needs to inherit from a QObject, therefore, the File class must also inherit from QObject. In the Directory class, the list of File objects is stored in a QList called m_fileList.

    1. class File : public QObject{
    2.  
    3.   Q_OBJECT
    4.   Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
    5.  
    6.   ...
    7. };

    为了实现按钮的点击功能,我们将用到QML的事件处置责罚。在QML中,事件处置责罚与Qt的信号/槽机制类似:当信号被触发时,与其连接的槽被调用。

    上面用到的语法展示了若何使用“import”关头字。这在使用不在同一目录下的JavaScript或者QML文件来说是必须的。由于Button.qml文件和FileMenu.qml文件位于同一目录,我们并不需要导入Button.qml就能够直接使用它。我们能够通过声明“Button {}”直接建立Button元素,就像使用“Rectangle{}”声明一样。

    你的浏览器不支持图片表现

    Because QML uses Javascript’s syntax and structure, we can iterate through the list of files and retrieve its properties. To retrieve the first file’s name property, we can call files0.name.

    Regular C++ functions are also accessible from QML. The file loading and saving functions are implemented in C++ and declared using the Q_INVOKABLE macro. Alternatively, we can declare the functions as a slot and the functions will be accessible from QML.

    In Directory.h:

    1. Q_INVOKABLE void saveFile();
    2. Q_INVOKABLE void loadFile();

    The Directory class also has to notify other objects whenever the directory contents change. This feature is performed using a signal. As previously mentioned, QML signals have a corresponding handler with their names prepended with on. The signal is called directoryChanged and it is emitted whenever there is a directory refresh. The refresh simply reloads the directory contents and updates the list of valid files in the directory. QML items can then be notified by attaching an action to the onDirectoryChanged signal handler.

    1. import Qt 4.7  // 导入Qt QML模块
    2. import "folderName"  //导入该目录的内容
    3. import "script.js" as Script  // 导入一个名为script.js的JavaScript文件,并将其命名为Script

    The constructor of QDeclarativeListProperty constructor and the Directory implementation:

    在QML中,基本的可视化组件是Rectangle元素。Rectangle元素拥有能够控制元素外观和位置的属性。

    The constructor passes pointers to functions that will append the list, count the list, retrieve the item using an index, and empty the list. Only the append function is mandatory. Note that the function pointers must match the definition of AppendFunction, CountFunction, AtFunction, or ClearFunction.

    1. void appendFiles(QDeclarativeListProperty<File> * property, File * file)
    2. File* fileAt(QDeclarativeListProperty<File> * property, int index)
    3. int filesSize(QDeclarativeListProperty<File> * property)
    4. void clearFilesPtr(QDeclarativeListProperty<File> *property)

    To simplify our file dialog, the Directory class filters out invalid text files, which are files that do not have a .txt extension. If a file name doesn’t have the .txt extension, then it won’t be seen in our file dialog. Also, the implementation makes sure that saved files have a .txt extension in the file name. Directory uses QTextStream to read the file and to output the file contents to a file.

    With our Directory element, we can retrieve the files as a list, know how many text files is in the application directory, get the file’s name and content as a string, and be notified whenever there are changes in the directory contents.

    To build the plugin, run qmake on the cppPlugins.pro project file, then run make to build and transfer the plugin to the plugins directory.

    在QML中导入plugin

    The qmlviewer tool imports files that are in the same directory as the application. We can also create a qmldir file containing the locations of QML files we wish to import. The qmldir file can also store locations of plugins and other resources.

    In qmldir:

    1. Button ./Button.qml
    2. FileDialog ./FileDialog.qml
    3. TextArea ./TextArea.qml
    4. TextEditor ./TextEditor.qml
    5. EditMenu ./EditMenu.qml
    6.  
    7. plugin FileDialog plugins

    The plugin we just created is called FileDialog, as indicated by the TARGET field in the project file. The compiled plugin is in the plugins directory.

    将文件对话框集成到文件菜单中

    Our FileMenu needs to display the FileDialog element, containing a list of the text files in a directory thus allowing the user to select the file by clicking on the list. We also need to assign the save, load, and new buttons to their respective actions. The FileMenu contains an editable text input to allow the user to type a file name using the keyboard.

    1. Rectangle {
    2.   id:Button
    3.   ...
    4.  
    5.   property color buttonColor: "lightblue"
    6.   property color onHoverColor: "gold"
    7.   property color borderColor: "white"
    8.  
    9.   signal buttonClick()
    10.   onButtonClick: {
    11.     console.log(buttonLabel.text + " clicked" )
    12.   }
    13.  
    14.   MouseArea{
    15.     onClicked: buttonClick()
    16.     hoverEnabled: true
    17.     onEntered: parent.border.color = onHoverColor
    18.     onExited:  parent.border.color = borderColor
    19.   }
    20.  
    21.   // 通过条件操纵符来决定按钮的颜色
    22.   color: buttonMouseArea.pressed ? Qt.darker(buttonColor, 1.5) : buttonColor
    23. }

    In FileMenu.qml:

    Keeping with the simplicity of our application, the file dialog will always be visible and will not display invalid text files, which do not have a .txt extension to their filenames.

    In FileDialog.qml:

    编辑器能够设置其中文本的字体颜色属性。这里,TextEdit所在的区域位于一个flickable区域之内。如果文本过长,则能够供给滚动条的功能。函数ensureVisible()会自动检查光标所在位置,并移动文本到相应位置。QML使用JavaScript作为其剧本语言。正如前面提及的那样,JavaScript文件能够导入到QML文件中。

    Similarly, we have the other properties declared according to their uses. The filesCount property indicates the number of files in a directory. The filename property is set to the currently selected file’s name and the loaded/saved file content is stored in fileContent property.

    In FileMenu.qml:

    1. Button{
    2.   id: newButton
    3.   label: "New"
    4.   onButtonClick:{
    5.     textArea.textContent = ""
    6.   }
    7. }
    8. Button{
    9.   id: loadButton
    10.   label: "Load"
    11.   onButtonClick:{
    12.     directory.filename = textInput.text
    13.     directory.loadFile()
    14.     textArea.textContent = directory.fileContent
    15.   }
    16. }
    17. Button{
    18.   id: saveButton
    19.   label: "Save"
    20.   onButtonClick:{
    21.     directory.fileContent = textArea.textContent
    22.     directory.filename = textInput.text
    23.     directory.saveFile()
    24.   }
    25. }
    26. Button{
    27.   id: exitButton
    28.   label: "Exit"
    29.   onButtonClick:{
    30.     Qt.quit()
    31.   }
    32. }

    Our FileMenu can now connect to their respective actions. The saveButton will transfer the text from the TextEdit onto the directory’s fileContent property, then copy its file name from the editable text input. Finally, the button calls the saveFile() function, saving the file. The sloadButton has a similar execution. Also, the New action will empty the contents of the TextEdit.

    Further, the EditMenu buttons are connected to the TextEdit functions to copy, paste, and select all the text in the text editor.

    你的浏览器没法表现图片

    完成的文本编辑器

    你的浏览器不支持图片表现

    这个顺序能被用作简单的文本编辑器,可以接收文本编辑并保存到文件中。它也能从文件中读取文本。

    Categories:


    展开全文
  • QT_QML 界面设计Row和Column布局

    千次阅读 2018-04-26 13:32:22
    text: qsTr("θ1")+qml_transor.emptyStringForReflash font.pointSize: 13 } Label { id: label_poseParam1 //x: 0 //--不需要指定 //y: 4//--不需要指定 width: 40 height: 30 text: qsTr("θ2")+qml_...
    Column与Row的使用方式类似,下面以Column为例子:
    Column{
            x: label_poseParamValue.x + label_poseParamValue.width + 10
            y: label_poseParamValue.y
            //width: 30  //--不需要指定,最终的长度由内部的各个实体的尺寸以及spacing值确定。
            //height:30  //--不需要指定
            spacing:5
    		
    	Label {
                id: label_poseParam1
                //x: 0 //--不需要指定
                //y: 4//--不需要指定
                width: 40
                height: 30
                text: qsTr("θ1")+qml_transor.emptyStringForReflash
                font.pointSize: 13
            }
    	Label {
                id: label_poseParam1
                //x: 0 //--不需要指定
                //y: 4//--不需要指定
                width: 40
                height: 30
                text: qsTr("θ2")+qml_transor.emptyStringForReflash
                font.pointSize: 13
            }
    }


    展开全文
  • 基于QT QML界面设计

    2019-06-11 21:07:14
    基于QT QML界面设计,具有一定的参考价值。
  • 基于QT wgdit和QML模板界面设计,纯属个人爱好编辑,欢迎下载
  • QML设计登陆界面

    2019-05-01 09:56:40
    QML设计登陆界面
                   

    QML设计登陆界面


    本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明.


    环境:

    主机:WIN7

    开发环境:Qt5.2


    说明:

    用QML设计一个应用的登陆界面


    效果图:



    源代码:

    main.qml

    import QtQuick 2.0Rectangle{    id: login_gui    width: 320; height: 480    SystemPalette { id: activePalette }    //背景图片    Image    {        id: background        anchors { top: parent.top; bottom: parent.bottom }        anchors.fill: parent        source: "pics/pic1.png"        fillMode: Image.PreserveAspectCrop    }    //顶烂    Item    {        id: top_bar        width: login_gui.width; height: login_gui.height * 0.05        anchors.top: login_gui.top        Text        {            id: title            anchors { top: parent.top; horizontalCenter: parent.horizontalCenter }            text: "登陆"            font.bold: true            font.pointSize: login_gui.height * 0.05 * 0.7            color: "dark red"        }    }    //空白栏    Item    {        id: space1        width: login_gui.width; height: login_gui.height * 0.1        anchors.top: top_bar.bottom    }    //登陆框    Rectangle    {        id: rect1        width: login_gui.width * 0.8; height: login_gui.height * 0.3        anchors { top: space1.bottom; horizontalCenter: parent.horizontalCenter }        border.color: "#707070"        color: "transparent"        LineInput        {            width: rect1.width * 0.8; height: rect1.height * 0.2            font_size:height * 0.7            anchors {horizontalCenter: rect1.horizontalCenter; top: rect1.top; topMargin: 8}            hint: "请输入用户号"        }        LineInput        {            width: rect1.width * 0.8; height: rect1.height * 0.2            font_size:height * 0.7            anchors {horizontalCenter: rect1.horizontalCenter; bottom: btn_login.top;  bottomMargin: rect1.height * 0.1}            hint: "请输入密码"        }        Button        {            id: btn_login            width: rect1.width * 0.35; height: rect1.height * 0.2            anchors { left: rect1.left; leftMargin: 28; bottom: rect1.bottom; bottomMargin: 8 }            text: "登陆"            //onClicked: SameGame.startNewGame()        }        Button        {            id: btn_quit            width: rect1.width * 0.35; height: rect1.height * 0.2            anchors { right: rect1.right; rightMargin: 28; bottom: rect1.bottom; bottomMargin: 8 }            text: "退出"            //onClicked: SameGame.startNewGame()        }    }}

    Button.qml

    import QtQuick 2.0Rectangle {    id: container    property string text: "Button"    signal clicked    width: buttonLabel.width + 20; height: buttonLabel.height + 5    border { width: 1; color: Qt.darker(activePalette.button) }    antialiasing: true    radius: 8    // color the button with a gradient    gradient: Gradient {        GradientStop {            position: 0.0            color: {                if (mouseArea.pressed)                    return activePalette.dark                else                    return activePalette.light            }        }        GradientStop { position: 1.0; color: activePalette.button }    }    MouseArea {        id: mouseArea        anchors.fill: parent        onClicked: container.clicked();    }    Text {        id: buttonLabel        anchors.centerIn: container        color: activePalette.buttonText        text: container.text    }}

    LineInput.qml

    import QtQuick 2.0FocusScope {    id: wrapper    property alias text: input.text    property alias hint: hint.text    property alias prefix: prefix.text    property int font_size: 18    signal accepted    Rectangle {        anchors.fill: parent        border.color: "#707070"        color: "#c1c1c1"        radius: 4        Text {            id: hint            anchors { fill: parent; leftMargin: 14 }            verticalAlignment: Text.AlignVCenter            text: "Enter word"            font.pixelSize: font_size            color: "#707070"            opacity: input.length ? 0 : 1        }        Text {            id: prefix            anchors { left: parent.left; leftMargin: 14; verticalCenter: parent.verticalCenter }            verticalAlignment: Text.AlignVCenter            font.pixelSize: font_size            color: "#707070"            opacity: !hint.opacity        }        TextInput {            id: input            focus: true            anchors { left: prefix.right; right: parent.right; top: parent.top; bottom: parent.bottom }            verticalAlignment: Text.AlignVCenter            font.pixelSize: font_size            //color: "#707070"            color: "black"            onAccepted: wrapper.accepted()        }    }}



               
    展开全文
  • QML界面设计及界面预览工具

    万次阅读 2017-03-21 15:02:19
    QML界面分成一些更小的元素,这些元素可以组成一个组件,QML语言描述了UI的形状和行为,并且可以使用JavaScript修饰。总的来说QML的结构有点像HTML,其语法和CSS比较近似。 1.QML层次结构 要使用QML进行界面的...
    这里我们简要介绍一下QML的语法。
    

    QML将界面分成一些更小的元素,这些元素可以组成一个组件,QML语言描述了UI的形状和行为,并且可以使用JavaScript修饰。总的来说QML的结构有点像HTML,其语法和CSS比较近似。

    1.QML层次结构

    要使用QML进行界面的布局,首先需要理解QML元素的层次结构。QML的层次结构很简单,是一个树形结构,最外层必须有一个根元素,根元素里面可以嵌套一个或多个子元素,子元素里面还可以包含子元素。如果用图形画出来的话大概是这个样子。

    image

    QML的坐标系采用的屏幕坐标系,原点在屏幕左上角,x轴从左向右增大,y轴从商到下增大,z轴从屏幕向外增大。子元素从父元素上继承了坐标系统,它的x,y总是相对于它的父元素坐标系。这一点一定要记住,非常重要。

    2.基本语法

    我们主要对照下面的代码进行介绍:

     


     1 import QtQuick 2.4
     2 import QtQuick.Window 2.2
     3 import QtQuick.Controls 1.2
     4 
     5 /* 这是一个多行注释,和c语言的一样 */
     6 // 当然这是一个单行注释
     7 
     8 Window {
     9 
    10     id:root;        // Window元素的id,应该保证在这个qml文件中名字唯一
    11     visible: true;
    12     width: 460;     // 直接指定窗口的宽度
    13     height: 288;    // 直接指定窗口的高度
    14 
    15     Image {
    16         id: bg;
    17         width: parent.width;            // 图片的宽度依赖父窗口的宽度
    18         height: parent.height;          // 图片的高度依赖父窗口的高度
    19         source: "qrc:///images/sky.jpg" // 引用一张图片
    20     }
    21 
    22     Image {
    23         id: rocket;
    24         x: (parent.width - width) / 2;  // 图片位置水平居中
    25         y: 40;                          // 图片位置距离父窗口40
    26         source: "qrc:///images/rocket.png";
    27     }
    28 
    29     Text {
    30         // 没有指定id,即这是一个匿名元素
    31         y:rocket.y + rocket.height + 20;                    // 文本顶部距离rocket图片底部20
    32         anchors.horizontalCenter: parent.horizontalCenter   // 设置文字水平居中
    33         text: qsTr("火箭发射!");                          // 设置文本显示的文字
    34         color: "#ff2332";                                   // 设置文本颜色
    35         font.family: "楷体";                                // 设置字体为楷体
    36         font.pixelSize: 30;                                 // 设置文字大小
    37     }
    38 }

     

    运行效果是这个样子。

    image

    布局结构是是这样的:

    image

    代码说明:

    (1)第1~3行的import是引入了一个指定版本的模块。一般都会引入QtQuick2.x这个模块,Window模块代表一个窗体,Control模块有很多的控制组件。这种import语法类似于C语言中的#include,和Java语言中的imort效果基本上一致。

    (2)第5、6两行分别是多行注释和单行注释,和C语言中的规则是一样的。

    (3)每一个QML文件都需要一个根元素,这里的根元素是Window元素,元素的形式是:元素类型 {}

    (4)元素拥有属性,他们按照name:value的格式进行组织;

    (5)语句后面的分号";"是可选的,但是建议加上;

    (6)第7行指定了window的id,在一个qml文件这种id硬保证唯一,否则后出现的id会覆盖前面的id造成不必要的bug。建议根元素的名字直接叫“root”,方便查找和理解,当然也可以取名任何你喜欢的名字。任何QML文档中的元素都可以使用他们的id进行访问;

    (7)第11行设置窗口可见,默认是false;

    (8)第12、13行指定了窗口的宽高为460x288;

    (9)第15行使用了一个Image元素,这个元素是用来展示图片的;

    (10)第17、18行指定图片的高度和宽度为父元素(即WIndow)的宽高,因此图片的宽高会随着父元素变化,使用parent可以访问父元素。

    (11)19行指定了一个图片资源的路径,这里使用了“qrc://”资源,这个资源的路径在image进行配置;qml还支持直接的本地文件路径和网络路径。

    (12)第24、25行指定了第二张图片的位置,在窗口水平居中,距离窗口顶部40像素;

    (13)第29行创建了一个Text元素,这个元素是用来呈现文字的。

    (14)第31行指定文本元素的y坐标为距离火箭图片(rock)底部20个像素;

    (15)第32行使用锚点的方式设置了文字的水平居中;

    (16)第33行设置了文本内容;

    (17)第34行设置文字的颜色,文字的颜色可以使用RGB方式也可以使用W3C规范的SVG方式;

    (18)第35、36行设置了字体和文字的大小。

     

    3.qmlscene 工具

    qt提供了一个查看qml效果的工具qmlscene ,这个工具在$QTDIR/qmlscene.exe,设置好环境变量后就可以直接在cmd矿口里面使用qmlscene 查看qml文件效果。

    image

    在控制台下输入qmlscene后就会弹出一个文件选择窗口,选择需要预览的qml,当然这里我们图片设置的是qrc路径,qmlscene预览效果并不好

    image

    image

    可以看到,两张图片并没有显示出来,并且会提示找不到这两张图片。

    解决办法当然可以将qrc路径修改成本地文件路径

    image

    image

    当然qmlscene也可以直接在后面接qml的位置比如上面图中就使用了

    qmlscene D:/Workspace/qt/rocket/main.qml

    在下一篇随笔中将详细介绍QML语法中的属性,和在QML使用JS脚本的方式。

    代码下载:http://download.csdn.net/detail/csulennon/8673425

    展开全文
  • QWidget调用QML界面,并交互(上)

    万次阅读 2018-06-30 00:05:16
    在QWidget加载QML文件 ,在加载过程中把qml文件添加...点击显示QML按钮显示对应QML界面,QWidget界面可与QML界面进行交互。 cpp代码部分 1.点击按钮显示QML,对应QML界面显示出来 QUrl source(“qrc:/qmlTes...
  • qml 界面开发之控件样式设置

    千次阅读 2018-03-05 22:49:50
     使用qml 怎样设计出合适的界面,胸有成竹是关键,你心里想的明确的,界面的实现便是调代码了,怎样实现心中的样子,设计样式根据什么来设计,查看Qt的源代码,会有很多收获,刚开始接触qml开发有一头雾水,慢慢做...
  • QML与C++交互 登陆界面设计
  • QML与C++交互:登陆界面设计

    万次阅读 多人点赞 2014-05-14 10:12:02
    QML与C++交互:登陆界面设计 本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明. 环境: 主机:WIN7 开发环境:Qt5.2.1 说明: QML设计前台界面,C++后台负责逻辑 效果图: 源代码...
  • QT在QWidget中加载qml界面 本文简要介绍在QWidget中加载qml文件,并通过信号与槽实现双向交互。 新的改变 我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点...

空空如也

空空如也

1 2 3 4 5 ... 12
收藏数 233
精华内容 93
关键字:

qml界面设计