下载

3下载券

加入VIP
  • 专属下载特权
  • 现金文档折扣购买
  • VIP免费专区
  • 千万文档免费下载

上传资料

关闭

关闭

关闭

封号提示

内容

首页 C++ GUI Programming with Qt 4 中文版(第一章至第十章)

C++ GUI Programming with Qt 4 中文版(第一章至第十章).doc

C++ GUI Programming with Qt 4 中…

sdh1108
2018-09-09 0人阅读 举报 0 0 暂无简介

简介:本文档为《C++ GUI Programming with Qt 4 中文版(第一章至第十章)doc》,可适用于IT/计算机领域

CGUIProgrammingwithQt中文版第一章至第十章作者于丁原文链接http:blogcsdnnetiamdblcategoryaspx制作人watchcloud制作日期年月日CGUIProgrammingwithQtByJasminBlanchette,MarkSummerfieldPublisher:PrenticeHallPubDate:June,PrintISBN:PrintISBN:Pages: 学习使用Qt已经将近两年了最开始的时候用Qt后来升级到Qt自认为对Qt的GUI编程部分还是很熟悉的。遗憾的是Qt的参考书少之又少一般就是看文档和CGUIProgrammingwithQt这本书是免费提供的让我对QtTrolltech公司有了更多的了解。我这个人就是这样学习什么都喜欢了解这个东东发展的历史虽然对学习并没有太多帮助。升级到Qt以后API有了很多变化苦盼一本系统的参考书很久CGUIProgrammingwithQt才得以面世终于盼到后却遗憾的发现这本没有提供免费的电子版今天一个偶然的机会得到Yimin网友的帮助得到一份电子版真是很谢谢他他的bloghttp:liyiminnetblog。CGUIProgrammingwithQt就是这样一本参考书从易到难从最经典的helloQt开始到构建复杂的程序。我从现在开始阅读学习同时也把部分心得写出来发到这里也希望对Qt的学习者们有所帮助。这对我来说有点难度懒人那不过一定尽最大努力坚持写完我熟悉的部分。加油!Qt发展小史Qt的创建者HaarardNord(Trolltech公司的CEO)和EirikChambeEng(Trolltech公司的总裁)是一家瑞典公司的同事。那时()他们在做一个项目这个项目需要在UnixMacintoshWindows上运行同一个GUI象我们现在的开发人员一样工作的很累当时可是没有如今这么多的开发工具。一天他们工作之余去公园散步晒太阳喝咖啡。Haarard说:“Weneedanobjectorienteddisplaysystem。”这成为了后来Qt最重要的思想:提供面向对象的跨平台的GUI框架。看到这里小女我不仅感慨:什么时候我们的程序员们可以在工作的时候出来走走只有在轻松愉快的环境中才会生产出出色的成果。在沉闷的办公室里只是机械的堆砌代码而已。所做就做Haarard开始写ata子类在这个子类中保存任意的数据类型。第一个方法不需要继承类但是有些缺点:即使托拽最终不被接受我们也需要把数据类型转换为QByteArray如果我们希望提供的MIME类型能够和大量的应用程序进行交互我们需要把交互的数据保存多份(每一类MIME类型保存一份)。要是交互的数据量很大那么程序的执行速度肯定会慢下来。第二种和第三种方法能够避免或者尽量减少这些问题。我们用一个例子说明这些方法让QTableWidget控件支持托拽。能够进行拖动的数据类型为:textplain,texthtml,textcsv。第一种方法实现如下:voidMyTableWidget::mouseMoveEvent(QMouseEvent*event){   if(event>buttons()Qt::LeftButton){       intdistance=(event>pos()startPos)manhattanLength()       if(distance>=QApplication::startDragDistance())           startDrag()   }   QTableWidget::mouseMoveEvent(event)}voidMyTableWidget::startDrag(){   QStringplainText=selectionAsPlainText()   if(plainTextisEmpty())       return   QMimeData*mimeData=newQMimeData   mimeData>setText(plainText)   mimeData>setHtml(toHtml(plainText))   mimeData>setData("textcsv",toCsv(plainText)to())   QDrag*drag=newQDrag(this)   drag>setMimeData(mimeData)   if(drag>start(Qt::CopyAction|Qt::MoveAction)==Qt::MoveAction)       deleteSelection()}函数mouseMoveEvent()中调用startDrag()开始进行拖动。我们调用函数setText()setHtml()设置MIME类型为textplaintexthtml的数据函数setData()保存textcsv类型的数据setData()把任意的MIME数据类型保存为一个QByteArray类型的数据。函数selectionAsString()的实现与第四章中Spreadsheet::copy()相似。 QStringMyTableWidget::toCsv(constQStringplainText){   QStringresult=plainText   resultreplace("","")   resultreplace(""",""")   resultreplace("t","","")   resultreplace("n",""n"")   resultprepend(""")   resultappend(""")   returnresult}QStringMyTableWidget::toHtml(constQStringplainText){   QStringresult=Qt::escape(plainText)   resultreplace("t","<td>")    resultreplace("n","n<tr><td>")   resultprepend("<table>n<tr><td>")   resultappend("n<table>")   returnresult} 函数toCsv()和toHtml()将tabs和newlines字符转换为vcsv格式的字符(用逗号分割数据)或者HTML字符。例如Red    Green    BlueCyan   Yellow   Magenta转换为(CSV):"Red", "Green", "Blue""Cyan", "Yellow", "Magenta" 或者(HTML)<table><tr><td>Red<td>Green<td>Blue<tr><td>Cyan<td>Yellow<td>Magenta<table>使用函数QString::replace()使转换尽可能简单。函数Qt::escape()用来解释HTML中的特殊字符。voidMyTableWidget::dropEvent(QDropEvent*event){   if(event>mimeData()>hasFormat("textcsv")){       QByteArraycsvData=event>mimeData()>data("textcsv")       QStringcsvText=QString::from(csvData)              event>acceptProposedAction()   }elseif(event>mimeData()>hasFormat("textplain")){       QStringplainText=event>mimeData()>text()              event>acceptProposedAction()   }}虽然我们提供了三种不同的数据格式但在dropEvent()中我们只接受了其中的两种。如果用户从QTableWidget的一个网格中拖动一串HTML字符到一个HTML编译器则把网格中的数据转换为HTML。如果用户拖动一个HTML到QTableWidget控件中我们不想接受它。要让这个例子顺利实现托拽在MyTableWidget构造函数中还要调用setAcceptDrops(true)和setSelectionMode(ContiguousSelection)。现在我们重新实现这个例子这次我们用QMineData作为基类用QMineData的子类实现数据转换避免了QTableWidgetItem和QByteArray之间的转换。下面是子类的定义:classTableMimeData:publicQMimeData{   QOBJECTpublic:   TableMimeData(constQTableWidget*tableWidget,                 constQTableWidgetSelectionRangerange)   constQTableWidget*tableWidget()const{returnmyTableWidget}   QTableWidgetSelectionRangerange()const{returnmyRange}   QStringListformats()constprotected:   QVariantretrieveData(constQStringformat,                         QVariant::TypepreferredType)constprivate:   staticQStringtoHtml(constQStringplainText)   staticQStringtoCsv(constQStringplainText)   QStringtext(introw,intcolumn)const   QStringrangeAsPlainText()const   constQTableWidget*myTableWidget   QTableWidgetSelectionRangemyRange   QStringListmyFormats}在类中我们保存了一个QTableWidgetSelectionRange对象和一个QTableWidget指针用来得到托拽的数据。函数formats()和retriveData()是对QMineData函数的重写。在构造函数中实现对私有变量的初始化。TableMimeData::TableMimeData(constQTableWidget*tableWidget,                            constQTableWidgetSelectionRangerange){   myTableWidget=tableWidget   myRange=range   myFormats<<"textcsv"<<"texthtml"<<"textplain"}QStringListTableMimeData::formats()const{   returnmyFormats}函数formats()返回一个能够支持的MIME类型的列表。类型之间的顺序对程序没有影响但是把“最好”的格式放在第一个是很好的习惯。支持多种格式的程序一般使用第一个能够匹配的格式。QVariantTableMimeData::retrieveData(constQStringformat,                                    QVariant::TypepreferredType)const{   if(format=="textplain"){       returnrangeAsPlainText()   }elseif(format=="textcsv"){       returntoCsv(rangeAsPlainText())   }elseif(format=="texthtml"){       returntoHtml(rangeAsPlainText())   }else{       returnQMimeData::retrieveData(format,preferredType)   }}指定一个MIME类型函数retrieveData()把拖动的数据作为一个QVariant数据返回。参数format的值一般是formats()返回列表中之一。我们并没有做这样的假设应用程序也不会在拖动时检查MIME类型。函数text()html()urls()imageData()colorData()和data()都是由QMimeData提供的。参数preferedType用来给出一个QVariant类型的建议这里我们忽略这个参数由QMimeData处理。voidMyTableWidget::dropEvent(QDropEvent*event){   constTableMimeData*tableData=           qobjectcast<constTableMimeData*>(event>mimeData())   if(tableData){       constQTableWidget*otherTable=tableData>tableWidget()       QTableWidgetSelectionRangeotherRange=tableData>range()              event>acceptProposedAction()   }elseif(event>mimeData()>hasFormat("textcsv")){       QByteArraycsvData=event>mimeData()>data("textcsv")       QStringcsvText=QString::from(csvData)              event>acceptProposedAction()   }elseif(event>mimeData()>hasFormat("textplain")){       QStringplainText=event>mimeData()>text()              event>acceptProposedAction()   }   QTableWidget::mouseMoveEvent(event)}函数dropEvent()和本节前面写的dropEvent()相似。在这个函数中我们首先把QMimeData安全转换为TableMimeData。如果qobjectcast<T>()返回了正确对指针说明托拽发生在同一个应用程序中的MyTableWidget控件我们根据QMimeData的API直接得到表格中拖动数据。如果没有得到正确的指针则按照标准方式处理。处理剪贴板(ClipboardHandling)很多应用程序使用Qt提供的剪贴板。例如:QTextEdit类提供了cut()copy()和paste()槽函数也能相应键盘的快捷键。客户程序只要编写很少的代码甚至不写代码。如果我们正在开发自己的类可以使用函数QApplication::clipboard()得到Qt的剪贴板该函数返回的是一个QClipboard类型对象的指针。使用这个指针很容器对剪贴板进行读写访问调用setText()setImage()setPixmap()把数据写到剪贴板。调用text()image()pixmap()得到剪贴板里的数据。在第章中的Spreadsheet程序中就是一个使用剪贴板的例子。对于有些应用程序来说Qt提供的剪贴板是不够用的。除了文本和图像等类型的数据我们还想让程序支持更多类型的数据让自己的程序和其他应用程序进行交互。这个问题和拖拽很相似解决方法也是一样:继承类QMimeData重新实现几个虚函数。如果我们的程序用一个QMimeData子类支持拖拽那么这个子类可以用在剪贴板中。用函数setMimeData()把数据写到剪贴板函数mimeData()得到剪贴板的数据。在X系统通常会点击三键鼠标的中间键完成对选择数据的粘贴操作。在Qt中用一个单独的“选择”剪贴板。如果一个控件要支持这种剪贴板同时也要支持标准的剪贴板需要在QClipboard函数调用中使用QClipboard::Selection参数下面的函数mouseReleaseEvent()是一个文本编辑器的鼠标相应函数支持鼠标中键粘贴。voidMyTextEditor::mouseReleaseEvent(QMouseEvent*event){QClipboard*clipboard=QApplication::clipboard()if(event>button()==Qt::MidButtonclipboard>supportsSelection()){QStringtext=clipboard>text(QClipboard::Selection)pasteText(text)}}在X中supportsSelection()返回true。在其他平台上返回false。剪贴板中的数据改变时QClipboard会发出QClipboard::dataChanged()信号。第章数据视图类(ItemViewClasses)很多Qt应用程序都允许用户查找查看编辑一个数据集中的一个具体数据。这些数据可能存在在一个文件中或者在数据库中也可能来自于网络。Qt提供的数据视图类能很好的处理这些数据。在Qt早先的版本中数据视图控件中保存了一个数据集中的所有数据。用户在这个控件中对数据进行查找编辑等操作有时候还要把数据写回到数据源中。这种处理方式很容易使用但是当数据量很大时就会影响程序性能也不能将一个数据源用多个不同的控件表示出来。Smalltalk语言在处理大数据集时使用了一个更加灵活的方式:模型视图控制器(modelviewcontrolerMVC)。在MVC方式中模型(model)代表数据集负责数据的获取查看及保存。尽管每种数据集的数据模型都不同但是模型提供的API对视图都是一致的。视图(view)把得到的数据呈现给用户如果数据量比较大时用户能够查看的只是全部数据的一部分即只是视图请求查看得那部分。控制器在用户和视图之间进行协调把用户的动作转换为对数据的查看或者编辑等操作然后视图在把数据的变化通知模型。FigureQt'smodelviewarchitecture Qt提供了一个类似MVC的模型视图(modelview)模式。在Qt中模型(model)和MVC中的模型功能一样。Qt没有使用MVC中的控制器(controller)而是使用了代理(delegate)。代理控制对对数据项的显示和编辑。Qt为每一种视图提供了一个缺省的代理。这个代理对于大多数应用程序已经足够了一般我们不需要太多关注它。使用Qt的模型视图结构我们只要用模型获取需要显示的数据再把这些数据提供给视图就可以。在处理大量数据时这种结构能够处理的更快内存消耗也比较小因为不再一次显示出所有的数据了。同时一个模型能够用一个或者多个视图显示出来用户能够用多种方式和数据进行交换。Qt能够自动对多个视图进行同步将一个视图中的变化同步到其他视图中。使用模型视图结构的另一个好处是如果我们想改变数据集那么只需要改变模型就可以了而不需要改变视图。FigureOnemodelcanservemultipleviews在很多情况下应用程序只需要显示一小部分数据这时可以使用Qt提供的方便的视图类(QListWidgetQTableWidgetQTreeWidget)直接在这些视图中填充数据。这些类和Qt的早前版本提供的类是一样的。把数据保存在数据项(item)中如QTableWidget中包含了多个QTableWidgetItem。在内部这些类使用自定义的模型使视图能够显示这些项目在数据量比较多时复制所有的数据是不明智的。这种情况下我们可以使用Qt提供的视图类(QListView,QTableViewQTreeView)与一个数据模型共同实现。例如如果数据集在一个数据库中我们可以使用QTableView和QSqlTableModel显示这些数据。使用数据视图便捷类(UsingtheItemViewConvenienceClasses)通常使用Qt提供的数据视图便捷类(itemviewconvenienceclass)要比定义一个模型简单的多适合无需分离模型和视图的操作。在第四章中我们使用了QTableWidget和QTableWidgetItem实现了表格的功能。在这一节中我们将介绍这些便捷类的使用。第一个例子是一个只读的QListWidget第二个例子是一个可编辑的QTableWidget第三个例子显示的是一个只读的QTreeWidget。首先我们显示一个简单的对话框用户通过鼠标点击选中列表中的一个流程图符号每一个项目包含一个图标一个文字说明和一个唯一ID。FigureTheFlowchartSymbolPickerapplication 下面是头文件中声明的类:classFlowChartSymbolPicker:publicQDialog{QOBJECTpublic:FlowChartSymbolPicker(constQMap<int,QString>symbolMap,QWidget*parent=)intselectedId()const{returnid}voiddone(intresult)} 当我们构造对话框时要传递一个QMap<int,Qstring>参数这个参数保存了一个项目的ID。调用函数selectedId()能够得到选中的ID如果用户没有选择返回的ID为-。FlowChartSymbolPicker::FlowChartSymbolPicker(constQMap<int,QString>symbolMap,QWidget*parent):QDialog(parent){id=listWidget=newQListWidgetlistWidget>setIconSize(QSize(,))QMapIterator<int,QString>i(symbolMap)while(ihasNext()){inext()QListWidgetItem*item=newQListWidgetItem(ivalue(),listWidget)item>setIcon(iconForSymbol(ivalue()))item>setData(Qt::UserRole,ikey())}} 我们把用户的最后一次选择的ID放在成员变量id中初始化为-。然后创建一个QListWidget一个便捷类。我们遍历流程图符号映射中的所有项目每一个项目用一个QListWidgetItem类对象表示。新建一个QListWidgetItem所需的第一个参数为显示的文本另一个参数为QListWidget作为其他父容器。然后我们设置了这个项目的图标调用setData()函数把每一个流程符号的ID保存在QListWidgetItem中。函数iconForSymbol()返回表示当前流程符号的图标。QListWidgetItem有很多角色(role)每一个角色由一个QVariant类型的数据进行读取和设置。最常用的角色是Qt::DisplayRoleQt::EditRole和Qt::IconRole。这些角色的数值可以通过setter和getter函数获得。如(setText(),setIcon())也有其他一些角色。我们也可以使用Qt::UserRole或者比这个值更大的数值定义用户自己的角色。在这个例子中我们使用Qt::UserRole保存每一项的ID。构造函数中省略的部分主要用于创建按钮布局和设置窗口标题。voidFlowChartSymbolPicker::done(intresult){id=if(result==QDialog::Accepted){QListWidgetItem*item=listWidget>currentItem()if(item)id=item>data(Qt::UserRole)toInt()}QDialog::done(result)} 函数done()是对QDialog::done()的重写。用户点击了对话框上的确定或者取消按钮后调用这个函数。如果用户点击了确定按钮我们调用data()函数得到选中项目的ID。如果需要得到的是项目显示的文本可以用函数item>data(Qt::DisplayRole)toString()或者item>text()更方便。缺省状态下QListWidget是只读的。如果我们希望用户能够编辑这个项目可以调用QAbstractItemView::setEditTriggers()。例如设置为QAbstractItemView::AnyKeyPressed说明用户敲击键盘就可以进行编辑。另外我们也可以提供一个编辑按钮(也许是增加或者删除按钮)把他们的信号和槽函数关联起来在程序中实现编辑。现在我们已经知道怎么使用一个便捷类查看和选择数据。我们将要实现一个可以进行编辑的例子。也是用到了对话框这个例子中要表现的是一对(x,y)坐标用户对这些坐标可以编辑。FigureTheCoordinateSetterapplication 和前一个例子一样我们主要关注和视图有关的代码首先从构造函数开始。CoordinateSetter::CoordinateSetter(QList<QPointF>*coords,QWidget*parent):QDialog(parent){coordinates=coordstableWidget=newQTableWidget(,)tableWidget>setHorizontalHeaderLabels(QStringList()<<tr("X")<<tr("Y"))for(introw=row<coordinates>count()row){QPointFpoint=coordinates>at(row)addRow()tableWidget>item(row,)>setText(QString::number(pointx()))tableWidget>item(row,)>setText(QString::number(pointy()))}}QTableWidget的构造函数中的两个初始化参数是表格的行数和列数。QTableWidget中的每一个小格为一个QTableWidgetItem实例垂直和水平表头也是如此。函数setHorizontalHeaderLabels()用来设置列标题。缺省情况下QTableWidget的每一行标题由序列号开始向下排列这已经能够满足我们的要求了所以没有设置行标题。设置好列标题以后我们开始遍历所有传递来的坐标数据。对每一个(x,y)数据对我们创建两个QTableWidgetItem实例分别表示x坐标和y坐标值。调用函数QTableWidget::setItem()把QTableWidgetItem实例添加到表格中去。在缺省情况下QTableWidget是可以进行编辑的。用户可以编辑任意一个小格子中的内容通过鼠标定位到小格子然后按F或者直接输入就可以。用户进行的任何修改都会自动更新到对应的QTableWidgetItem。如果想不允许任何编辑可以调用函数setEditTriggers(QAbstractItemView::NoEditTriggers)。voidCoordinateSetter::addRow(){introw=tableWidget>rowCount()tableWidget>insertRow(row)QTableWidgetItem*item=newQTableWidgetItemitem>setTextAlignment(Qt::AlignRight|Qt::AlignVCenter)tableWidget>setItem(row,,item)QTableWidgetItem*item=newQTableWidgetItemitem>setTextAlignment(Qt::AlignRight|Qt::AlignVCenter)tableWidget>setItem(row,,item)tableWidget>setCurrentItem(item)}当用户点击AddRow按钮时函数addRow()就会被触发。函数insertRow()往表格中加入一行。如果用户想编辑新加入行的某一个列QTableWidget会自动创建一个QTableWidgetItem实例。voidCoordinateSetter::done(intresult){if(result==QDialog::Accepted){coordinates>clear()for(introw=row<tableWidget>rowCount()row){doublex=tableWidget>item(row,)>text()toDouble()doubley=tableWidget>item(row,)>text()toDouble()coordinates>append(QPointF(x,y))}}QDialog::done(result)}最后当用户点击了OK按钮我们清除对话框中的坐标值根据QTableWidget中的数据形成一个新的坐标集合。下面是最后一个例子我们使用QTreeWidget查看一下一个Qt应用程序的设置文件。缺省情况下QTreeWidget中的项目是只读的FigureTheSettingsViewerapplication 下面是构造函数的一部分。SettingsViewer::SettingsViewer(QWidget*parent):QDialog(parent){organization="Trolltech"application="Designer"treeWidget=newQTreeWidgettreeWidget>setColumnCount()treeWidget>setHeaderLabels(QStringList()<<tr("Key")<<tr("Value"))treeWidget>header()>setResizeMode(,QHeaderView::Stretch)treeWidget>header()>setResizeMode(,QHeaderView::Stretch)setWindowTitle(tr("SettingsViewer"))readSettings()}为了读取到一个应用程序的设置文件必须创建一个QSettings对象并且把组织名称和程序名称作为参数。我们使用了一个缺省名称(”Desinger”by“Trolltech”)然后创建一个QTreeWidget。最后我们调用readSettings()函数。voidSettingsViewer::readSettings(){QSettingssettings(organization,application)treeWidget>clear()addChildSettings(settings,,"")treeWidget>sortByColumn()treeWidget>setFocus()setWindowTitle(tr("SettingsViewerby")arg(application)arg(organization))}程序设置保存在一个有层次关系的属性关键字和对应值当的文件中(windows平台下也可能保存在注册表中)。函数addChildSettings()读取一个属性组的信息需要的参数分别是一个QSettings对象父项目QTreeWidgetItem和当前的属性组名在QSettings中组相当于文件中的目录。函数addChildSettings()递归调用自己遍历一个完整的树结构。在readSettings()函数中开始调用它父项目为代表根节点。voidSettingsViewer::addChildSettings(QSettingssettings,QTreeWidgetItem*parent,constQStringgroup){QTreeWidgetItem*itemsettingsbeginGroup(group)foreach(QStringkey,settingschildKeys()){if(parent){item=newQTreeWidgetItem(parent)}else{item=newQTreeWidgetItem(treeWidget)}item>setText(,key)item>setText(,settingsvalue(key)toString())}foreach(QStringgroup,settingschildGroups()){if(parent){item=newQTreeWidgetItem(parent)}else{item=newQTreeWidgetItem(treeWidget)}item>setText(,group)addChildSettings(settings,item,group)}settingsendGroup()}函数addChildSettings()创建了所有的QTreeWidgetItem。它遍历应用设置层次树当前节点的所有属性为每一个属性创建一个QTableWidgetItem。如果传递的父项目为新创建的QTreeWidgetItem作为QTreeWdiget的子项目(树的根节点)如果父项目不为在父项目下面创建一个子项目。控件QTreeWidget的第一列为属性关键字名称第二列为属性值。然后函数开始遍历当前节点下的属性组为每一个组创建一个QTreeWidgetItem对象第一列为属性的名称。函数递归调用自己得到所有的属性组把每一个组的子项目放到QTreeWidget控件中。在本节所介绍的控件中这些控件的编程方式和Qt的早期版本很像。把所有数据读到控件中使用item代表一个数据如果item是可编辑的就把更新的数据写回到数据源。接下来的几节将改变这种简单的方式充分利用Qt的modelview结构。使用已有的模型类(UsingPredefinedModels)Qt已经提供了一些可以和视图类配合使用的模型:QStringListModel保存一系列字符串QStandardItemModel保存有任意继承关系的数据QDirModel对本地文件系统进行的封装QSqlQueryModel对SQL查询结果进行的封装QSqlTableModel封装一个SQL表QSqlRelationalTableModel封装带有外键的SQL表QSortFilterProxyModel排序或者顾虑一个模型的封装在本节中我们将会讨论QStringListModleQDirModel和QSortFilterProxyModel的使用。SQL有关的模型将在第章介绍。首先我们看一个简单的对话框用户可以增加爱删除编辑一个QStringList每一个字符串代表一个项目领导。FigureTheTeamLeadersapplication下面是其构造函数的一部分:TeamLeadersDialog::TeamLeadersDialog(constQStringListleaders,                                    QWidget*parent)   :QDialog(parent){   model=newQStringListModel(this)   model>setStringList(leaders)   listView=newQListView   listView>setModel(model)   listView>setEditTriggers(QAbstractItemView::AnyKeyPressed                             |QAbstractItemView::DoubleClicked)   }首先我们创建一个QStringListModel然后用传递来得参数leaders作为模型的数据。然后我们创建一个QListView把刚才创建的模型作为这个视图的模型。调用setEditTriggers()允许用户通过敲击键盘或者双击它。缺省情况下QListView没有编辑触发器是只读的。voidTeamLeadersDialog::insert(){   introw=listView>currentIndex()row()   model>insertRows(row,)   QModelIndexindex=model>index(row)   listView>setCurrentIndex(index)   listView>edit(index)}当用户点击了insert按钮槽函数insert()就会被调用。这个函数首先得到列表中当前项目的所在行数模型中每一个数据项都有一个对应的模型索引(modelindex)有一个QModelIndex对象表示。在下一节我们再详细讨论这个类。现在我们需要知道的是一个索引有三个主要组成对象:行列一个指向实际数据的指针。对一个一维列表索引得列数总是为。一旦确定了行数我们就在这个位置插入一新行。插入操作时是在模型上实现的。模型会自动刷新列表视图。然后我们把新插入的行作为当前行。并把当前行设为编辑状态就像用户点击了键盘或者双击了项目一样。voidTeamLeadersDialog::del(){   model>removeRows(listView>currentIndex()row(),)}在构造函数中Delete按钮发出的cliecked()信号和del()函数连接。因为我们只是删除当前行调用函数removeRows()当前索引的行号和要删除的行数作为参数。和插入操作一样模型类负责通知视图的更新。QStringListTeamLeadersDialog::leaders()const{   returnmodel>stringList()}当对话框关闭时函数leaders()能够得到编辑过的字符列表。TeadLeaderDialog可以作为一个通用的字符列表编辑对话框只要改变窗口标题就可以了。另一个经常使用的是显示文件列表或者目录。下一个例子我们使用了QDirModel这个类封装了计算机的文件系统能够显示(或者隐藏)各种文件属性。这个模型类能够根据文件种类进行过滤按照不同的方式进行排序等。FigureTheDirectoryViewerapplication首先看类的构造函数首先了model和view的创建和其他需要的设置。DirectoryViewer::DirectoryViewer(QWidget*parent)   :QDialog(parent){   model=newQDirModel   model>setReadOnly(false)   model>setSorting(QDir::DirsFirst|QDir::IgnoreCase|QDir::Name)   treeView=newQTreeView   treeView>setModel(model)   treeView>header()>setStretchLastSection(true)   treeView>header()>setSortIndicator(,Qt::AscendingOrder)   treeView>header()>setSortIndicatorShown(true)   treeView>header()>setClickable(true)   QModelIndexindex=model>index(QDir::currentPath())   treeView>expand(index)   treeView>scrollTo(index)   treeView>resizeColumnToContents()   }一旦创建了model我们设置它可编辑并且设置排序方式。然后创建一个QTreeView显示model的数据。设置用户能够控制QTreeView的标题列顺序。设置标题列可点击用户能够根据点击的任何一列排序升序或者降序。然后得到当前目录的index调用expand()和scrollTo()使它可见。调用函数resizeColumnToContents()让第一列宽度足够显示所有的文字而不是使用(…)在构造函数的其他部分我们把CreateDirectory按钮和Remove按钮的点击信号和各自的槽函数连接起来。注意我们没有Rename按钮因为不需要用户可以敲击F后键入新的名称model会自动为我们保存。voidDirectoryViewer::createDirectory(){   QModelIndexindex=treeView>currentIndex()   if(!indexisValid())       return   QStringdirName=QInputDialog::getText(this,                             tr("CreateDirectory"),                             tr("Directoryname"))   if(!dirNameisEmpty()){       if(!model>mkdir(index,dirName)isValid())           QMessageBox::information(this,tr("CreateDirectory"),                   tr("Failedtocreatethedirectory"))   }}用户点击CreateDirectory后显示输入对话框在对话框中输入目录名称。我们打算把新目录建在当前目录的下面。QDirModel::mkdir()函数创建一个新目录参数为父目录的index和要创建的目录名称。如果创建成功就返回新创建目录的index。如果失败则返回一个不合法的index。voidDirectoryViewer::remove(){   QModelIndexindex=treeView>currentIndex()   if(!indexisValid())       return   boolok   if(model>fileInfo(index)isDir()){       ok=model>rmdir(index)   }else{       ok=model>remove(index)   }   if(!ok)       QMessageBox::information(this,tr("Remove"),               tr("Failedtoremove")arg(model>fileName(index)))}如果用户点击了Remove按钮我们就删除当前index关联的文件或者目录。vQDir可以实现删除操作QDirModel提供了这个操作的方便函数。本节的最后一个例子讨论QSortFilterProxyModel的使用。与其他Qt提供的model不同这个model封装了一个现有的model对已有的model和view之间传递的数据进行控制。在我们的这个例子中已有的model为一个QStringListModel用一系列QColor::colorNames()对model进行初始化。用户可以在一个QLineEdit控件中键入要过滤从字符串用一个组合框确定这个字符串的解析方式(正则表达式通配符等)FigureTheColorNamesapplication下面是ColorNameDialog对话框的一部分:ColorNamesDialog::ColorNamesDialog(QWidget*parent)   :QDialog(parent){   sourceModel=newQStringListModel(this)   sourceModel>setStringList(QColor::colorNames())   proxyModel=newQSortFilterProxyModel(this)   proxyModel>setSourceModel(sourceModel)   proxyModel>setFilterKeyColumn()   listView=newQListView   listView>setModel(proxyModel)      syntaxComboBox=newQComboBox   syntaxComboBox>addItem(tr("Regularexpression"),QRegExp::RegExp)   syntaxComboBox>addItem(tr("Wildcard"),QRegExp::Wildcard)   syntaxComboBox>addItem(tr("Fixedstring"),QRegExp::FixedString)   } TheQStringListModeliscreatedandpopulatedintheusualwayThisisfollowedbytheconstructionoftheQSortFilterProxyModelWepasstheunderlyingmodelusingsetSourceModel()andtelltheproxytofilterbasedoncolumnoftheoriginalmodelTheQComboBox::addItem()functionacceptsanoptional"data"argumentoftypeQVariantweusethistostoretheQRegExp::PatternSyntaxvaluethatcorrespondstoeachitem'stextvoidColorNamesDialog::reapplyFilter(){   QRegExp::PatternSyntaxsyntax=           QRegExp::PatternSyntax(syntaxComboBox>itemData(                   syntaxComboBox>currentIndex())toInt())   QRegExpregExp(filterLineEdit>text(),Qt::CaseInsensitive,syntax)   proxyModel>setFilterRegExp(regExp)} ThereapplyFilter()slotisinvokedwhenevertheuserchangesthefilterstringorthepatternsyntaxcomboboxWecreateaQRegExpusingthetextinthelineeditThenwesetitspatternsyntaxtotheonestoredinthesyntaxcombobox'scurrentitem'sdataWhenwecallsetFilterRegExp(),thenewfilterbecomesactiveandtheviewisautomaticallyupdated

用户评价(0)

关闭

新课改视野下建构高中语文教学实验成果报告(32KB)

抱歉,积分不足下载失败,请稍后再试!

提示

试读已结束,如需要继续阅读或者下载,敬请购买!

文档小程序码

使用微信“扫一扫”扫码寻找文档

1

打开微信

2

扫描小程序码

3

发布寻找信息

4

等待寻找结果

我知道了
评分:

/269

C++ GUI Programming with Qt 4 中文版(第一章至第十章)

VIP

在线
客服

免费
邮箱

爱问共享资料服务号

扫描关注领取更多福利