版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
C++GUIProgrammingwithQtByJasminBlanchette,MarkPublisher:PrenticeHallPubDate:June21,2006PrintISBN-10:0-13-187249-PrintISBN-13:978-0-13-187249s:學(xué)習(xí),使用QtQt3Qt4.1,自認(rèn)為QtGUIQt的參考書少之又少,一般就是看文檔C++GUIProgrammingwithQt3,這本書是免費提供的,讓我對Qt,TrolltechQt4以后,API有了很多變化,苦盼一本系統(tǒng)的參考書,很久,C++GUIProgrammingwithQt4才得以面世,終于盼到后卻遺憾的發(fā)現(xiàn)這本沒有提供免費的電子版,今天,一個偶然的機(jī)會,得到Y(jié)imin網(wǎng)友的幫助,得到一份,真是很謝謝他,他的blog。CGUIProgrammingwithQt4就是這樣一本參考書,從易到難,從最經(jīng)典的oQt開始,到構(gòu)建復(fù)雜的程序。我從現(xiàn)在開始閱讀學(xué)習(xí),同時也把部分心得寫出來,發(fā)到這里,也希望對Qt的學(xué)習(xí)者們有所幫助。這對我來說有點難度,懶人那,不過一定十年來,Qt就是這樣從不知名的一個產(chǎn)品,發(fā)展到現(xiàn)在擁有全世界范圍內(nèi)成千上萬從oQt開差不多所有的程序都從o開始,下面就是這個程序的qt版本#include#includeintmain(intargc,char{QApplicationapp(argc,QLabel*label=newQLabel("oreturn9Qt4中,可以寫成<QApplication>的第三行:是main第五行:創(chuàng)建一個QApplication第六行:QLabel對象,QLabel是一個Qt提供的小控件,顯示一行文本。QLabel。qmake-project,qmake命令創(chuàng)建,是平臺無關(guān)的工程文件。在所在 下,運行make(unix)或者nmake(windows)。QLabel*label=newQLabel("<h2><i>o</i>"<fontQApplicationapp(argc,argv);return這個例子用來說明怎么響應(yīng)信號,和o程序的源代碼相似,原來的Label用一個按鈕#include#includeintmain(intargc,char{QApplicationapp(argc,QPushButton*button=new&app,return11當(dāng)有所動作或者狀態(tài)改變,qt的控件會發(fā)出消息(signal),例如,當(dāng)點擊按鈕時,按鈕會發(fā)送clicked()消息,這個消息可以連接到一個函數(shù)上(這個函數(shù)在這里成為slot)。這樣,當(dāng)一個消息發(fā)送時,slot函數(shù)可以自動執(zhí)行。在這個例子中,我們連接了clicked信號和QApplicationquit函數(shù),語法如第七,八行所示。quit.cpp文件中,保存。qmake-projectqmakemake(unixorlinux)or然后運行程序,點擊Quit控件的幾何排列-LayingOut方法使控件同步。程序要求用戶通過spinbox或者slider輸入。程序中使用了三個控件:QSpinBox,QSliderQWidget。QWidget是這個程序的主窗口。QSpinBoxQSlider被放在QWidgetQWidgetchildren。反過來,QWidgetQSpinBoxQSliderparent。QWidgetparent,因QWidgetQWidget*參數(shù),#include#include#include#includeintmain(intargc,char{QApplicationapp(argc,QWidget*window=newQSpinBox*spinBox=newQSlider*slider=newspinBox,QHBoxLayout*layout=newreturn258,9行建立程序的主窗設(shè)置1013行創(chuàng)建主窗口的children,setValue(int)函數(shù)就會為這個控件設(shè)置一個新值。18spinBox35spinBoxvalueChanged(int)信號,int35slidersetValue(int)slider的值也設(shè)置spinBox35spinBox不會發(fā)送任何信號,不1922spinBoxslider控件。布局管理器能夠根據(jù)需要確定控件的大小和位置。Qt有三個主要的布局管理器:22行,QWidget::setLayout()windowspinBox和sliderQHBoxLayout能合理安排它們。我們不用在程序中考慮控件在屏幕上的大小和位置這些Qtsignal和slot完成。第二章創(chuàng)建框(Creating在這章介紹如何創(chuàng)建Qt的框??蚴浅绦蚝陀脩艚换サ臉蛄?,提供了程序和本章中我們首先會用代碼的方式創(chuàng)建我們的第一個框,然后用QtDesigner工具創(chuàng)建框。QtDesigner是一個可視化的工具,用它可以更快的創(chuàng)建,修改框。派生框類(Subclassing2.1派生框類(Subclassing第一個例子是一個用C++實現(xiàn)的查找框。我們把這個框?qū)崿F(xiàn)為一個類,這樣它就是一個獨立的控件,并有自己的信號(signal)slot函數(shù)類的源代碼分別放在finddialog.hfinddialog.cpp中。首先看finddialog.h#ifndef#define#includeclassclassclassclassclassFindDialog:public{FindDialog(QWidget*parent=voidfindNext(constQString&str,Qt::CaseSensitivityvoidfindPrevious(constQString&str,Qt::CaseSensitivityprivatevoidvoidenableFindButton(constQStringQLabelQLineEditQCheckBoxQCheckBoxQPushButtonQPushButton26273行包含QDialog頭文件,這個類從QDialog繼承,QDialogQWidget第4至7行是用到的Qt中類的前向。通過前向,編譯器就知道這個類已826FindDialog的定義。10行,Q_OBJECTsignalslots,就要聲12FindDialog(QWidget*parent0);Qt控件類的標(biāo)準(zhǔn)格NULL,說明沒有父控件。第13行,signal了這個框發(fā)出的兩個信號,如果選擇向前查找,那么框就發(fā)出findPrevious()信號,否則,發(fā)出findNext()信號。signal也是一個宏,在編譯之前,C++c++代碼。Qt::CaseSensitivity是一個枚舉類Qt::CaseSensitiveQt::CaseInsensitive兩個值。在類的私有部分,有兩個slot函數(shù)。為了實現(xiàn)這兩個函數(shù),需要用到框的下面看一下finddialog.cpp源文件代碼:#include#include: label=newQLabel(tr("FindlineEdit=newcaseCheckBox=newQCheckBox(tr("MatchbackwardCheckBox=newQCheckBox(tr("SearchfindButton=newcloseButton=newthis,SLOT(enableFindButton(constQStringthis,this,QHBoxLayout*topLeftLayout=newQVBoxLayout*leftLayout=newQVBoxLayout*rightLayout=newQHBoxLayout*mainLayout=new38delete這些控件。void{QStringtext=lineEdit-Qt::CaseSensitivitycscaseCheckBox->isChecked()?:if(backwardCheckBox->isChecked())emitfindPrevious(text,}elseemitfindNext(text, 50{54findPrevious()或者findNext()信號。emitQtlineEdit中的文本,enableFindButton()slot函數(shù)就會調(diào)用。如果輸入了文本,那么讓findButton有效,否則就無效。最后,創(chuàng)建main.cpp測試FindDialog框#include#includeintmain(intargc,char{QApplicationapp(argc,FindDialog*dialog=newreturn9運行qmake編譯程序。由于在FindDialog中包含了Q_OBJECT宏,由qmake生makefile會保換特殊的規(guī)則運行moc(Qt的原對象編譯器)。為了確保mocmoc生成的代碼中包含這個頭文件,并加入它自己實現(xiàn)的C++代碼。使用了Q_OBJECTmocqmake,那么makefile里自動moc,就會發(fā)生連接錯誤。不同的編譯器給出的提示信息不同,有的會非?;逎?。GCC給出的錯誤信息如下:finddialog.o:Infunction'FindDialog::tr(charconst*,char/usr/lib/qt/src/corelib/global/qglobal.h:1430:undefinedreferencetoVisualC++中的輸出是這樣finddialog.obj:errorLNK2001:unresolvedexternalsymbol"public:~virtualintthiscallMyClass::qt_metacall(enumQMetaObject::Call,int,void*qmake,更新makefile運行程序,如果看到了快鍵,測試ALT+W,ALT+C,ALT+B,ALT+F相應(yīng)的處理程TABTAB鍵是控件創(chuàng)建的順序。tab順序和快鍵可以讓用戶不用鼠標(biāo)也可以運行程序,通過鍵盤可以快速深入信號和槽(SignalsandSlotsin信號和槽是Qt編程的一個重要部分。這個機(jī)制可以在對象之間彼此并不了解的情況槽和普通的c++成員函數(shù)很像。它們可以是虛函數(shù)(virtual),(private),c++成員函數(shù)一樣被調(diào)用,可以傳遞任何類型的參數(shù)。不connect(sender,SIGNAL(signal),receiver,senderreceiver是QObject對象指針,signalslotconnect(slider,SIGNAL(valueChanged(int)),spinBox,SLOT(setValue(int)));connect(slider,SIGNAL(valueChanged(int)),this,connect(lcd,SIGNAL(overflow()),this,SLOT(handleMathError()));connect(calculator,SIGNAL(divisionByZero()),this,connect(lineEdit,SIGNAL(textChanged(constQString&)),this,SIGNAL(updateRecord(constQString&)));connect(ftp,SIGNAL( mandReply(int,constQString&)),this,SLOT(processReply(int,constQString&)));connect(ftp,SIGNAL( mandReply(int,constQString&)),this,如果參速類型不匹配,或者信號和槽不存在,在debug狀態(tài)時,Qt會在運行期間給出警告。如果信號和槽連接時包含了參數(shù)的名字,Qt將會給出警告。QObject中就實現(xiàn)了,可以實現(xiàn)在任何從QObject繼承的子類中。classEmployee:public{Employee(){mySalary=0;intsalary()const{returnmySalary;}publicslots:voidsetSalary(intnewSalary);voidsalaryChanged(intnewSalary);intvoidEmployee::setSalary(int{if(newSalary!=mySalary){mySalary=newSalary;emit}}注意,只有newSalarymySalarysalary-Changed()信號,這樣避免了死QtC++擴(kuò)展,即把彼此獨立的軟件模塊連接起來,而不需M-Octnrosco()。nosconOc它子類的m-normn”這個機(jī)還提供屬性(在QtDsnr中使用和文本譯()支S(QtScrtorAco)的基礎(chǔ)。C++Qtmeta-object系統(tǒng)需要的動態(tài)meta-information。Qt提供了moc,通過定義Q_OBJECTC++函數(shù)的轉(zhuǎn)變。moc是用純c++C++編譯器中。Qt的moc工具實現(xiàn)Q_OBJECT宏的函數(shù)和所有的信號QObjectconnect()disconnect()使用這些內(nèi)省函數(shù)實現(xiàn)信號和槽的連接。qmake,mocQObject自動處理的,程序員通常不用考慮它們。如果你感到對此好奇,可以查看QMetaObject類文檔和mocc++代碼??焖僭O(shè)計框(RapidDialog通常程序員們都是用c++源代碼編寫QtQtQtDesigner滿足了程序員的這一要求,提供了可視化設(shè)計框的方法。它可以給一個應(yīng)用程序提供全部或者部分框用QtDesigner設(shè)計的框和用c++代碼寫成的對在這一節(jié)中,我們使用QtDesigner創(chuàng)建Go-to-Cell框,無論用編寫代碼的方式還是用QtDesigner,創(chuàng)建框都有如下基本的步驟:3tab順序。在windows平臺Qt的安裝 的bin 下,點擊desinger.exe,或者在unix平臺,在命令行上輸入designer。當(dāng)QtDesigner啟動后,它會列出一個控件模板的列表,QtDesigner的介紹略去不想翻譯了,只要稍有點界面編程基礎(chǔ)的都可以輕gotocellgotocelldialog.ui個下創(chuàng)建一個main.cpp文件,編碼如下:#include<QApplication>#include<QDialog>#include"ui_gotocelldialog.h"intmain(intargc,char*argv[]){QApplicationapp(argc,argv);Ui::GoToCellDialogui;QDialog*dialog=newQDialog;returnapp.exec();}保存后,在 下運行qmake,創(chuàng)建.pro文件,然后運行qmake-project生界面編譯器uic工具把gotocelldialog.ui轉(zhuǎn)換成c++代碼ui_gotocelldialog.h在ui_gotocelldialog.hUi::GoToCellDialog類的定義,這個類和setupUi()class{QLabel*label;QLineEdit*lineEdit;QSpacerItem*spacerItem;QPushButton*okButton;QPushButton*cancelButton;voidsetupUi(QWidget*widget)}一層間接包裝來簡單解決uicUi::前綴。gotocelldialog.h頭文件,寫下如下代碼:#ifndefGOTOCELLDIALOG_H#defineGOTOCELLDIALOG_H#include<QDialog>#includeclassGoToCellDialog:publicQDialog,public{GoToCellDialog(QWidget*parent=0);privateslots:void#include<QtGui>#include"gotocelldialog.h":{lineEdit->setValidator(newQRegExpValidator(regExp,this));connect(okButton,SIGNAL(clicked()),this,SLOT(accept()));connect(cancelButton,SIGNAL(clicked()),this,SLOT(reject()));}void{}字符是一個數(shù)字范圍為0到9QRegExpValidator的構(gòu)造函數(shù)中二個參數(shù)為this,Qt的父子機(jī)制在QObject中實現(xiàn)的。當(dāng)我們創(chuàng)建一個帶有父的對象(如一個子控件,一個就是我們使用new創(chuàng)建的沒有父對象的對象。如果我們在父對象存在時刪除了它的一個子里的子控件,器和布局管理器由Qt自己管理,其他還要程序員刪除)在構(gòu)造函數(shù)的最后兩行,把QDialog的accept()函數(shù)連接到OKCancel按鈕的點擊信號連接到reject()函數(shù)。這兩個槽函數(shù)都關(guān)閉這個框,但是1reject()0。不同的返回值可以判斷用戶點擊了那個按鈕。on_lineEdit_textChanged()Ok按鈕的可用狀態(tài),通過編輯框中的輸入字符,如果字符有效Ok按鈕則有效,否則為不可用狀態(tài)。QLineEdit::hasAcceptableInput()根據(jù)我們在構(gòu)造函數(shù)中設(shè)置的器返回bool值。#include<QApplication>#include"gotocelldialog.h"intmain(intargc,char{QApplicationapp(argc,GoToCellDialog*dialog=newGoToCellDialog;return}編譯這個程序(qmake-projectqmake)然后運行。輸入使用qtDesigner可以不改變源程序的情況下改變框的設(shè)計如果框用C++代碼類型的可以通過代碼編寫,也可以用QtDesigner設(shè)計。可擴(kuò)展框通常外觀簡單,帶有一個可擴(kuò)展按鈕來切換框的簡單外觀和可擴(kuò)展級應(yīng)用部分。在這一節(jié),我們使用QtDesigner設(shè)計一個可擴(kuò)展框。More按鈕使用戶在簡單外觀和擴(kuò)展外觀進(jìn)行切換。1File|New菜單,選擇“DialogwithButtonsRight”2More按鈕,并將它托到右邊的垂直布局管理器中,放到垂直空白的下面。設(shè)置按鈕的文本屬為“&More”checkable屬性為“true”,設(shè)置Okdefault屬性true。6、設(shè)置組合框的title屬性為“&PrimaryKey”,第一個的text屬性為“Column:”,第二個的text屬性為“Order:”。Edit|UndoForm|BreakLayout,重新進(jìn)行排列。當(dāng)然只要看起來不是很難看,也可以是其他的樣子,只要易于理解就是ok。然后設(shè)置控件的tab順序。從上到下點擊下拉框,然后點擊Ok,Cancel,More按鈕。以上是框的設(shè)計。然后用QtDesigner建立控件的信號連接。因為我們創(chuàng)建框時使用了“DialogwithButtonsRight”模板,Ok和Cancel按鈕已經(jīng)連接到了框的accept()和reject()槽函數(shù)。連接可以在Qtdesigner的signal/slot編輯窗口查看。我們需要自己建立的連接是連接More按鈕和secondary-GroupBox。將按鈕的toggled(bool)信號和組合框的setVisible(bool)連接。選擇Edit|Signal/Slots,將編輯狀態(tài)變?yōu)檫B接態(tài),拖動More按鈕到secondary-GroupBox上,彈出信號編輯框。創(chuàng)建一個sort ,保存框文件到sort 的sortdialog.ui,使用多繼承的方式使#ifndefSORTDIALOG_H#defineSORTDIALOG_H#include<QDialog>#include"ui_sortdialog.h"classSortDialog:publicQDialog,public{SortDialog(QWidget*parent=voidsetColumnRange(QCharfirst,QChar#include#include:511voidSortDialog::setColumnRange(QCharfirst,QChar{QCharch=while(ch<=last)bo-bo-bo-ch=ch.unicode()+ 28的屬性為QLayout::setFixedSize,這樣用戶就不能隨便改變框的大小。main.cpp文件:#include<QApplication>#include"sortdialog.h"intmain(intargc,char{QApplicationapp(argc,argv);SortDialog*dialog=newSortDialog;dialog->setColumnRange('C','F');return}編譯運行這個程序,點擊More按鈕,查看框的改變動態(tài)框(Dynamic動態(tài)框(Dynamic動態(tài)框是在程序運行時用QtDesigner的.ui文件創(chuàng)建。不用uic工具把.ui文件變成c++QUiLoader加載.ui文件,例如下面的代碼:QUiLoaderuiLoader;QFileQWidget*sortDialog=uiLoader.load(&file);if(sortDialog){}子控件可以用QObject::findChild<T>()得到QComboBox* bo=sortDialog->findChild<QComboBox*>(" if( bo){}QUiLoader類在一個單獨的庫中,如果在一個應(yīng)用程序中使用了QUiLoader,必須在這個程序的.pro文件中添加下面這樣的代碼: +=使用動態(tài)框不重新編程序就夠改變的布局。們可以來創(chuàng)建細(xì)客戶的程序只有兩內(nèi)建框其他的框都是按不同需創(chuàng)建的(這段翻譯有點,原文下:Dnmcosmketosseochneheyutofafomhut nghecon.ycnsoeusdocrehn-cons,hrehexuemryhsaront-ndfomu-nndlohrfomsrecrdsrur.)Qt提供的控件和框類(Built-inWidgetandDialogQt提供的控件和框類(Built-inWidgetandDialogQt提供了許多控件和框類,可以滿足多種情況的需要。這一節(jié)將對它們進(jìn)行介紹。有些特殊的控件如:QBar,QToolBar和QStatusBar主窗口類控件在第三章介紹,QSplitterQScrollArea在第六章介紹。大部分Qt提供的控件都會在本書中出現(xiàn)。在Qt提供四種方式的按鈕:QPushButton,QToolButton,QCheckBox,和QRadioButton.QPushButtonQToolButton(點擊時顯示按下的狀態(tài),再次點擊后恢復(fù))。QCheckBox可以用來表示開關(guān)選項。QRadioButtonsQtQFrameQToolBoxQLabel。QTabWidget和QToolBox是多頁框,每一頁都是一個子控件,頁數(shù)從0開始類是Q Qt還提供只顯示信息的控件,QLabel是用的最多的,它可以用來顯示文本,顯示帶有html格式的文本,還可以顯示。QTextBrowser顯示,表格,多文本連接等。QtAssistant就是使用Qt提供這樣一些數(shù)據(jù)輸入的控件。QLineEdit只可輸入器允許的字符。QTextEdit是Q ScrollArea的子類,可以輸入多行文本。Windows,MacOSX等不同平臺上的普通框盡可能和平臺控件風(fēng)格一致Qt提供了很多信息顯示框和錯誤提示框。程序的進(jìn)行狀態(tài)可以用QProgressDialogQProgressBar顯示。QInputDialog可以方便的讓用戶輸入一行文本或者第三章創(chuàng)建主窗口(CreatingMainWindows)(CreatingMainWindows)qt創(chuàng)建程序的主窗口。最后,讀者能夠生成一個有著全部菜單,應(yīng)用程序的主窗口是用戶界面的框架。SpreadSheet應(yīng)用程序的主窗口如圖所示。這個程序使用了第二章創(chuàng)建的Find,Go-to-Cell和Sort框。GUI應(yīng)用程序都能夠處理文件的讀寫,數(shù)據(jù)處理等功能。在第四章,我們繼續(xù)SpreadSheet為例子進(jìn)行說明。3.1QMainWindow類(Subclassing3.1繼承QMainWindow一個應(yīng)用程序的主窗口要從QMainWindow繼承。我們在第二章看到的創(chuàng)建框的方法可以用來創(chuàng)建主窗口,QDialogQMainWindow都是繼承自QWidget類。主窗口可用QtDesignerc++代碼實現(xiàn)。如果你喜歡使用可視化的工具,可以參考手冊“CreatingMainWindowsinQt#ifndefMAINWINDOW_H#defineMAIhNWINDOW_H#include<QMainWindow>classQAction;classQLabel;classFindDialog;classSpreadsheet;classMainWindow:public{voidcloseEvent(QCloseEvent*event);privateslots:voidnewFile();voidopen();boolsave();boolsaveAs();voidfind();voidgoToCell();voidsort();voidvoidopenRecentFile();voidupdateStatusBar();voidspreadsheetModified();voidcreateActions();voidcreates();voidcreateContext();voidcreateToolBars();voidcreateStatusBar();voidreadSettings();voidwriteSettings();boolokToContinue();boolloadFile(constQString&fileName);boolsaveFile(constQStringvoidsetCurrentFile(constQString&fileName);voidupdateRecentFileActions();QStringstrippedName(constQString&fullFileName);Spreadsheet*spreadsheet;FindDialog*findDialog;QLabel*locationLabel;QLabel*formulaLabel;QStringListrecentFiles;QStringcurFile;enum{MaxRecentFiles=5QAction*recentFileActions[MaxRecentFiles];QAction*separatorAction;Q*fileQ*editQToolBar*fileToolBar;QToolBar*editToolBar;QAction*newAction;QAction*openAction;QActionMainWindowQMainWindow。因為它有自己的信號和槽,所以Q_OBJECT宏。closeEvent()是QWidgetMainWindow有些菜單項,如File|New,Help|About等被為MainWindow的私有的相應(yīng)函數(shù)。多數(shù)的槽函數(shù)返回值為voidsave()saveAs()bool型。當(dāng)一#include<QtGui>#include"finddialog.h"#include"gotocelldialog.h"#include"mainwindow.h"#include"sortdialog.h"#include"spreadsheet.h"{spreadsheet=newSpreadsheet;findDialog=}在構(gòu)造函數(shù)中,我們開始創(chuàng)建SpreadSheet控件,并把這個控件做為主窗口的中心然后我們調(diào)用createActions(),creates(),createContext-(),createToolBars()createStatusBar()創(chuàng)建主窗口的其他部分。readSettings()findDialog指針為空,當(dāng)MainWindow::find()第一次被調(diào)時,將會創(chuàng)建一FindDialog對象。最后,我們設(shè)置窗口的圖標(biāo)為icon.png。Qt支持多種格式的文件,包括BMP,GIF,JPEG,PNG,PNM,XBM,XPM 。在QWidget::setWindowIcon()中設(shè)置的圖標(biāo)顯示在程序主窗口的左上角。不過,Qt沒有提供一個平臺無關(guān)的程序的桌面圖標(biāo)。相關(guān)平臺的處理方式可參考http:/ 1、把在文件中,程序運行時加載它2XPM文件(這種文件是有效的c++文件3、使用Qt這里我們使用Qt提供的資源管理方案,因為它能夠發(fā)在運行時方便的加載文 images里面。使用這個方案時,需要創(chuàng)建一個資源文件,并在.pro文件中添加這個資源文件的有 =<!DOCTYPERCC><RCC/。例如:/images/icon.png。除外,資源可以是任何格式的文件,這將在第12章創(chuàng)建菜單和工具條(CreatingsandGUI程序都有菜單,上下文菜單,工具條等。用戶通過菜單瀏覽程序提供的所有功Qt使用“行為”(action)這個概念提供菜單和工具條。一個“行為(action)”是一個可以加入任何菜單或者工具條的項目。用Qt創(chuàng)建菜單和工具條需要如下步驟SpreadSheet程序中createActions()voidvoid{newAction=newQAction(tr("&New"),this);newAction->setStatusTip(tr("Createanewspreadsheetfile"));connect(newAction,SIGNAL(triggered()),this,SLOT(newFile()));for(inti=0;i<MaxRecentFiles;{recentFileActions[i]=newQAction(this);connect(recentFileActions[i],SIGNAL(triggered()),this,SLOT(openRece}selectAllAction=newQAction(tr("&All"),selectAllAction->setStatusTip(tr("Selectallthecellsinthe"connect(selectAllAction,SIGNAL(triggered()),spreadsheet,SLOT(selectAllshowGridAction=newQAction(tr("&ShowGrid"),this);showGridAction->setStatusTip(tr("Showorhidethespreadsheet'sconnect(showGridAction,SIGNAL(toggled(bool)),spreadsheet,SLOT(setShaboutQtAction=newQAction(tr("About&Qt"),aboutQtAction->setStatusTip(tr("ShowtheQtlibrary'sAboutconnect(aboutQtAction,SIGNAL(triggered()),qApp,}actionactionNew,有一個加速鍵(N),一個父對象(主actiontriggered()newFile(),這個函數(shù)將在下一節(jié)實現(xiàn)。用戶在選擇了File|New菜單項,點擊了New,或者在鍵盤敲了Ctrl+NrecentFileActions是一個action數(shù)組。里面的action被隱并連接到ShowGrid是一個可選取的行為,菜單的旁邊有一個選擇的記號。在上這一項是個套索形式的工具條。當(dāng)它被按下時,SpreadSheet組件顯示一個網(wǎng)格。ShowGridAuto_Recalculate是獨立的行為。QtQActionGroup也提供多選一 voidvoid{=separatorAction=for(inti=0;i<MaxRecentFiles;--===--=--=}在Qt中,菜單是類 Bar()函數(shù)返回一個Q Bar指 分割條(separator)for循環(huán)添加recentFileActionsexitAction行為。件沒有時,這個separator就隱。相同的方式創(chuàng)建Edit,Option,Help等菜單。上下文菜單實現(xiàn)createContext voidvoid{}voidvoid{fileToolBar=addToolBar(tr("&File"));editToolBar=addToolBar(tr("&Edit"));}創(chuàng)建狀態(tài)條(SettingUptheStatus創(chuàng)建狀態(tài)條(SettingUptheStatusMainWindow的構(gòu)造函數(shù)中,調(diào)用createStatusBar()voidvoid{locationLabel=newQLabel("W999");formulaLabel=newQLabel;connect(spreadsheet,SIGNAL(currentCellChanged(int,int,int,int)),this,SLOT(updateStatusBar()));connect(spreadsheet,SIGNAL(modified()),this,SLOT(spreadsheetModified()));}QLableformulaLabel設(shè)置了一個縮進(jìn),使它顯示的信息離左邊有一定的偏移。當(dāng)QLabel控件加到狀態(tài)條上時,它們的大小改變時,其他多余的空間由formulaLabel占據(jù),這是因為我們在代碼中statusBar()->addWidget(formulaLabel,1)formularLabel的托放因數(shù)為1locationLabel0,這表明它的大小是固定的。QStatusBarQWidget::sizeHint()得到控件的locationLabel的大小,我們設(shè)置它的最小值為它可能顯示的最大的文本voidvoid{}函數(shù)就會被調(diào)用。在createStatusBar()的最后它做為普通函數(shù)調(diào)用初始化狀態(tài)條的顯SpreadsheetcurrentCellChanged()信號。voidvoid{}spreadsheetModified()windowModifiedtrue,用來更新窗口updateStausBar()反映當(dāng)前狀態(tài)的變化。實現(xiàn)文件菜單(Implementingthe 實現(xiàn)文件菜單(Implementingthe voidvoid{if(okToContinue())}}youwanttosaveyourchanges(是否存盤提示)YesNo,函trueCancelfalse。Spreadsheet::clear()函數(shù)清楚所有spreadsheet控件的格子和。setCurrentFile()也是一個私有函數(shù),它更新窗口標(biāo)題,curFile變量,更新最近打開的文件列表,為用戶開始編輯沒有名字的新文檔做好boolbool{if(isWindowModified())intr=QMessageBox::warning(this, hasbeenmodified."DoyouwanttosaveyourQMessageBox::Yes|QMessageBox::Cancel|if(r==QMessageBox::Yes)return}elseif(r==QMessageBox::Cancel)return}}return}Yes為默認(rèn)的按鈕,QMessageBox::EscapeEsc和Cancel按鈕等效QMessageBox::warning(parent,title,message,button0,button1,槽函數(shù)open()File|OpenokToContinue()處理為保存的信息。然后使用QFileDialog::getOpenFileName(),這個函數(shù)彈出一個框,讓用戶選擇Cancel按鈕,則返回一個空字符串。voidvoid{if(okToContinue())QStringfileName=tr("OpenSpreadsheet"),tr("Spreadsheetfilesifif}}顯示在父控件的中上位置,Achilddialogalsosharesitsparent'staskbarentry.(怎么準(zhǔn)第二個參數(shù)是框使用的標(biāo)題。第三個參數(shù)是顯示的初始,”.”表示的是程序的當(dāng)前。spreadsheet程序中除了支持自定義的文件格式外,還支Comma-separatedvaluesLotus1-2-3文件,那么過濾器就要這樣:tr("Spreadsheetfiles"Comma-separatedvaluesfiles(*.csv)\n""Lotus1-2-3files(*.wk1*.wks)")boolboolMainWindow::loadFile(constQString{statusBar()->showMessage(tr("LoadingstatusBar()->showMessage(tr("Loadingcanceled"),2000);returnfalse;}statusBar()->showMessage(tr("Fileloaded"),2000);returntrue;}File|Savesave()函數(shù)相應(yīng)的。如果文件已經(jīng)有了名字,或者是在磁盤上打開saveFile()saveAs()。boolbool{if(curFile.isEmpty()){returnsaveAs();}elsereturn}}boolMainWindow::saveFile(constQString{if(!spreadsheet->writeFile(fileName))statusBar()->showMessage(tr("Savingcanceled"),2000);returnfalse;}statusBar()->showMessage(tr("Filesaved"),2000);returntrue;}bool{QStringfileName=tr("SaveSpreadsheet"),".",tr("Spreadsheetfiles(*.sp)"));if(fileName.isEmpty())returnfalse;return}File|SaveAssaveAs()。QFileDialog::getSaveFileName()提示用戶輸入文件名。如果用戶點擊了Cancelfalse,并將狀態(tài)傳遞給調(diào)用者。如果文件已經(jīng)存在,getSaveFileName()getSaveFileName()的一個QFileDialog::DontConfirmOverwrite。File|Close菜單或者窗口標(biāo)題欄上的關(guān)閉按鈕,QWidget::close()就會被調(diào)用。并發(fā)送close()信號。重新實現(xiàn)QWidget::closeEvent()能夠這個消息,以便確voidvoidMainWindow::closeEvent(QCloseEvent{if(okToContinue()){}else}}}如果需要存盤或者用戶選擇了Cancel,那么就忽視這個,不關(guān)閉窗口。通常果接受了這個,Qt就會隱藏這個窗口。私有函數(shù)writeSettings()保存應(yīng)用程序當(dāng)前的QApplicationquitOnLastWindowClosedfalse。這樣,程序會一直運行,直到我QApplication::quit()。voidvoidMainWindow::setCurrentFile(constQString{curFile=fileName;QStringshownName="Untitled";if(!curFile.isEmpty()){shownName=strippedName(curFile);}setWindowTitle(tr("%1[*]-}QStringMainWindow::strippedName(constQString{returnreturn}windowModified屬性,把“[*]”放在合適的地方,Qt就能夠自動處理。tr("%1[*]-有兩個.arg(),分別用來代替%1,%2。如果文件名為“budget.sp”,且沒有加載翻譯文件,那么顯示的字符串就是“budget.sp[*]-Spreadsheet”。也可以簡寫如下:setWindowTitle(shownName+tr("[*]-但是使用arg()更加靈活且容易實現(xiàn)rencentFiles(最近打開文件列表)removeAll()函數(shù)updateRecentFileActions()File菜單項。java樣式的迭代器刪除不存在的文件,因為有些文件可能在列表中但是已經(jīng)被刪除掉了。recentFilesQStringList11章詳細(xì)介紹容器,迭c++標(biāo)準(zhǔn)模板庫(STL)的關(guān)系。voidvoid{ tori(recentFiles);while(i.hasNext()){if(!QFile::exists(i.next()))}for(intj=0;j<MaxRecentFiles;++j){if(j<recentFiles.count()){QStringtext=tr("&%1.arg(j+recentFileActions[j]->setVisible(true);}else}}}C:\Mys\tab04.sp,那么第一個行為顯示的文本就是“&1tab04.sp”。每一個行為都有一個大data項,QVariant類型的數(shù)據(jù)。QVariant能夠存貯voidvoid{if(okToContinue())QAction*action=qobject_cast<QAction*>(sender());if(action)}}qobject_case<T>()mocQObject類的子類對象的指針,如果這個對象不能轉(zhuǎn)換成類型T,返回一個空指針。和標(biāo)準(zhǔn)c++的QObject指針變?yōu)橐粋€QActionloadFile()QActiondata屬性中保存的文件。QActionstatic_cast<T>或C樣式的類型轉(zhuǎn)換都能正確。使用框(Using使用框(Using在這一節(jié)中,我們介紹Qt中框的調(diào)用:初始化框,顯示框和與用戶交首先我們看一下Find框。我們希望用戶能夠在Find框和Spreadsheet應(yīng)用程序的主窗口之間自由切換,所以Find框應(yīng)該是無模式的。一個無模式的框 voidvoid{if(!findDialog)findDialog=newconnect(findDialog,SIGNAL(findNext(constQStringspreadsheet,SLOT(findNext(constQString&,connect(findDialog,SIGNAL(findPrevious(constQString&,spreadsheet,SLOT(findPrevious(constQString&,}}1、第一次調(diào)用Find23如果Find框還不存在,那么創(chuàng)建框,連接findNext()和沒有調(diào)用這個框,還可以節(jié)約內(nèi)存。show()activateWindow()確保窗口是可見的,激活的。單獨調(diào)用show()是能夠顯示并激活窗口的。但是如果調(diào)用時,F(xiàn)ind框是可見的,show()就不activateWindow()就有必要了。所以后面幾行還可以這樣寫:if(findDialog->isHidden()){}else}接著我們來看Go-to-Cell框是一個模式框。我們需要用戶彈出框,在切換到程序的其他窗口前關(guān)閉它。模式框就是彈出后,在關(guān)閉之前,它程序的其他消息和其他進(jìn)程的干擾,也不能切換到其他窗口。我們以前使用過的文件框和消息提示框都是模式框。void{GoToCellDialogdialog(this);if(dialog.exec()){QStringstr=dialog.lineEdit->text().toUpper();spreadsheet->setCurrentCell(str.mid(1).toInt()-1,str[0].unicode()-使用show()顯示的框是無模式框。用exec()顯示的框是模式框。如果框被接受,QDialog::exec()函數(shù)返回true(QDialog::Accepted),否則返回false(QDialog::Rejected)。在第二章創(chuàng)建Go-to-Cell框時,我們連接了okvoid{GoToCellDialogdialog(this);if(dialog.exec()){QStringstr=dialog.lineEdit->text().toUpper();spreadsheet->setCurrentCell(str.mid(1).toInt()-1,str[0].unicode()-}}}QTableWidget::setCurrentCell()需要兩個參數(shù):一個行序號和一個列序號。在Spreadsheet程序中,網(wǎng)格A1對應(yīng)(0,0),B27對應(yīng)(26,1)QLineEdit::text()中返回的QStringQString::mid()函數(shù)(mid()中指定的位置到字符串的最后)然后用QString::toInt()1。至于列序號,我們得到字符串的第一個字符減去字母"A"的unicode的數(shù)字值。在創(chuàng)建這個框的時候,我們使用了QRegExpValidator確保能夠得到正確的格式。goToCell()GoToCellDialog。如果newdelete實現(xiàn):void{GoToCellDialog*dialog=newGoToCellDialog(this);if(dialog->exec()){QStringstr=dialog->lineEdit->text().toUpper();spreadsheet->setCurrentCell(str.mid(1).toInt()-1,str[0].unicode()-}delete}現(xiàn)在我們看sort框。Sort框是一個模式框,使用戶能夠按列排序選中的區(qū)void{SortDialogQTableWidgetSelectionRangerange=spreadsheet->selectedRange();dialog.setColumnRange('A'+range.leftColumn(),'A'+if(dialog.exec())parecompare.keys[0] compare.keys[1]= bo->currentIndex()-1;compare.keys[2]= bo->currentIndex()-1;compare.ascending[0]= bo->currentIndex()==0);compare.ascending[1]= bo->currentIndex()==0);compare.ascending[2]= bo->currentIndex()==}}sort()goToCell()同樣的模式:第二排序列,按降序排列。例如使用途中的選定區(qū)域,range.leftColumn()0,'A'+0='A',range.rightColumn()2,'A'+2='C'。compare對象第一,第二,第三排序列和它們排序順序(在下一章會pare進(jìn)行定義)。在Spreadsheet::sort()中會使用到這個對象。keys數(shù)組存C2E5C0,ascending數(shù)組是每一列排序的順序。QComboBox::currentIndex()得到當(dāng)前選定項目的序0開始。對于第一,第二排序列。還需要用當(dāng)前值減去"None"項目的值。sort()函數(shù)已經(jīng)可以工作了,但是有點脆弱。它假定了Sort框只能用這種固定的方式實現(xiàn),有下拉框,需要None項目。如果我們重新設(shè)計Sort框,我們還要重寫這段代碼。如果只在一個地方這樣調(diào)用了,一次也就夠了。但是如果在多個地方都使用一個更加強(qiáng)壯的方法是讓SortDialog自己創(chuàng)建 pare對象,這樣可以大大減少了MainWindow::sort()的代碼。void{SortDialogQTableWidgetSelectionRangerange=spreadsheet->selectedRange();dialog.setColumnRange('A'+range.leftColumn(),'A'+if }一個讓程序更加強(qiáng)壯的方法是在初始化SortDialog框的時候傳遞Spreadsheet對象的指針,是框能夠直接操作Spreadsheet。這樣SortDialog只是作為一個控件,使SortDialog更加通用,MainWindow::sort()函數(shù)也更加簡單:void{SortDialogdialog(this);}這個sort()函數(shù)和第一個sort()函數(shù)相比:這里調(diào)用函數(shù)不需要知道框的實現(xiàn)細(xì)節(jié),個用戶子定義的框來顯示程序的有關(guān)信息,但是由于大多About框的樣式都是一樣的,所以Qt給出了一個簡單的解決方案。void{QMessageBox::about(this,tr("AboutSpreadsheet"),tr("<h2>Spreadsheet1.1</h2>""<p>Copyright©2006SoftwareInc.""<p>Spreadsheetisasmallapplicationthat""demonstratesQAction,QMainWindow,Q Bar,""QStatusBar,QTableWidget,QToolBar,andmanyother""Qt}調(diào)用QMessageBox::about()靜態(tài)函數(shù)可以得到下圖這樣的About框。除了QMessageBox和QFileDialog的靜態(tài)函數(shù)。這些函數(shù)創(chuàng)建一個框,進(jìn)行初始化然后調(diào)用exec()顯示出來。當(dāng)然,首先創(chuàng)建QMessageBox或QFileDialog,然后顯式調(diào)用exec()show()也是可以的,并且一樣方便。存貯設(shè)置(Storing存貯設(shè)置(StoringMainWindowreadSettings()得到應(yīng)用程序保存的設(shè)置選項。同樣在closeEvent()writeSettings()保存當(dāng)前應(yīng)用程序的設(shè)置。這是MainWindow需要實現(xiàn)的最后兩個成員函數(shù)。void{QSettingssettings("SoftwareInc.","Spreadsheet");settings.setValue("geometry",geometry());settings.setValue("recentFiles",recentFiles);settings.setValue("showGrid",showGridAction->isChecked());settings.setValue("autoRecalc",autoRecalcAction->isChecked());}在缺省情況下,QSettings根據(jù)平臺特性應(yīng)用程序的設(shè)置。在Windows中使用Unix中把數(shù)據(jù)存貯在文本文件中;在MacOSX平臺上使用CoreFoundationPreferenceAPI。QSettings使用鍵值對存貯設(shè)置。鍵相當(dāng)于一個文件系統(tǒng) 語法確定(例如findDialog/matchCase),或者使用beginGroup()和endGroup()settings.setValue("matchCase",caseCheckBox->isChecked());settings.setValue("searchBackward",backwardCheckBox->isChecked());void{QSettingssettings("SoftwareInc.","Spreadsheet");QRectrect=settings.value("geometry",QRect(200,200,400,recentFiles=settings.value("recentFiles").toStringList();boolshowGrid=settings.value("showGrid",true).toBool();boolautoRecalc=settings.value("autoRecalc",true).toBool();}readSettings()函數(shù)writeSettings()保存的程序設(shè)置。函數(shù)value()中的第二Qt提供了QWidget::setGeometry()函數(shù)做為QWidget::geometry()的補(bǔ)充。但是在X11上由于窗口管理器多樣的原因不能準(zhǔn)確實現(xiàn)。所以我們使用move()和resize()。在http:/ /4.1/geometry.html中有詳細(xì)解釋。MainWindowreadSettings()writeSettings()只是一種可行方法之一。QSettings對象可以在程序運行過程中的任何時間任何位置和修改這些設(shè)到現(xiàn)在為止,我們已經(jīng)完成了MainWindow的實現(xiàn)。在一下的幾個小節(jié)中,要討多文檔(Multiple現(xiàn)在我們開始實現(xiàn)Spreadsheetmain()函數(shù):include<QApplication>includeintmain(intargc,char{QApplicationapp(argc,argv);MainWindowmainWin;return}程序中止的時候,MainWindow自動銷毀。main()函數(shù),Spreadsheet程序提供一個主窗口,一次只能處理一個文檔。如果我們希望在同時處理多個文檔,我們就要同時啟動多個Spreadsheet程序。這對用戶來web瀏覽器可為了處理多文檔,我們需要對SpreadsheetFileFile|CloseFile|ExitCloseExit時一樣。main()函數(shù)變?yōu)檫@樣:intmain(intargc,char{QApplicationapp(argc,MainWindow*mainWin=newMainWindow;return}newMainWindow實例,這樣當(dāng)保存后就可以deleteMainWindow實例。MainWindow::newFile()要改成這樣:voidMainWindow::newFile(){MainWindow*mainWin=newMainWindow;}我們只是簡單的創(chuàng)建一個新的MainWindow實例。奇怪的是我們沒有保存新窗口的指Qt會為我們記錄所有窗口的地址。void{closeAction=newQAction(tr("&Close"),this);closeAction->setStatusTip(tr("Closethiswindow"));connect(closeAction,SIGNAL(triggered()),this,SLOT(close()));exitAction=newQAction(tr("E&xit"),this);exitAction->setStatusTip(tr("Exittheapplication"));connect(exitAction,SIGNAL(triggered()),qApp,}newFile()中{}很明顯,最近打開的文檔應(yīng)該是對程序全局有效的。我們可以recentFiles為靜態(tài)變foreach(QWidget*win,QApplication::topLevelWidgets())if(MainWindow*mainWin=qobject_cast<MainWindow*>(win))}上面的代碼用到了Qtforeach(11章介紹)遍歷所有程序窗口,類型為MainWindowupdateRecentFilesActions()ShowGrid和AutoRecalculate也要這樣處理進(jìn)行同步,確保同一個文件不會調(diào)用兩次。一個主窗口只能處理一個文檔的程序稱為SDI(singleinterface)程序。能處理多個文檔的程序稱之為MDI(Multipleinterface)程序。Qt能夠在所有操作系SDIMDI程序。啟動畫面(Ssh3-8啟動畫面(Ssh啟動畫面很簡單,需要使用的類是QSshScreen。在窗口沒有顯示之前,QSshScreen顯示一個,他還可以在上顯示文字信息提示用戶當(dāng)前程序初始化的進(jìn)度。一般情況下,啟動畫面代碼在main()函數(shù)中,加在調(diào)QApplication::exec()之前。下面的一個程序的main()函數(shù)使用QSshScreen顯示一個啟動畫面,同時顯示加載intmain(intargc,char{QApplicationapp(argc,QSshScreen*ssh=newQSQt::AlignmenttopRight=Qt::AlignRight|ssh->showMessage(QObject::tr("Settingupthemainwindow..."),topRight,Qt::white);MainWindowssh->showMessage(QObject::tr("Loadingmodules..."),topRight,Qt::white);ssh->showMessage(QObject::tr("Establishingconnections..."),topRight,Qt::white);deletessh;return}Spreadsheet程序的用戶界面部分我們已經(jīng)完成了。在下一章中會實現(xiàn)表格的3-83-1倒序排列的文章,還是很有成就感的。blog大軍中是因為有趣和好奇,也想用這種方式激勵譯完三天內(nèi)看懂而已。如果有朋友需要原書可以留郵箱給我,當(dāng)然也可以去和百度上去搜,我也是這樣得到的??纯春偷臒峄?,就知道現(xiàn)在也是一個“搜”時GUIQt的初學(xué)者,可以仔細(xì)看看。在這一章用到了很多Qt的類及其常用Qt的龐大類庫來說只是冰山一Spreadsheet具體功能的代碼去掉,也是可以的。第四章就是講述Spreadsheet的具體功能的實現(xiàn),在這一章里,還會介紹怎樣保存文件,實現(xiàn)剪貼板4-1控件(TheCentralWidget)4-1控件(TheCentral1、使用標(biāo)準(zhǔn)Qt控件:標(biāo)準(zhǔn)的Qt控件如QTableWidget或者QTextEdit可以做為控2序就要把IconEditor做為控件。第五章將會介紹怎么樣在Qt中實現(xiàn)自定義的用戶控4QSplitter(分隔條)。QSplitter可5、使用MDI工作控件。在MDI程序中,控件由QWorkSpace控件占據(jù)。每一個MDIMDIQt控件一在Spreadsheet程序中,一個QTableWidget子類做為它的控件。QTableWidget已經(jīng)提供了大部分我們需要的表格功能,但是它不支持剪貼板,不能理解如"=A1+A2+A3"這樣的。在Spreadsheet類中實現(xiàn)這些功能。4-2QTableWidget繼承(SubclassingQTableWidget)4-2QTableWidget繼承(SubclassingSpreadsheetQTableWidget繼承。QTableWidget是一個表示二維離散數(shù)組本時,QTableWidget自動創(chuàng)建一個QTableWidgetItem對象保存輸入的文本?,F(xiàn)在我們來實現(xiàn)這個類,首先是頭文件spreadsheet.h,首先前向兩個類 #ifndef#ifndef#define#include<QTableWidget>classCell;classSpreadsheet:public{Spreadsheet(QWidget*parent=boolautoRecalculate()const{returnautoRecalc;QStringcurrentLocation()QStringcurrentFormula()QTableWidgetSelectionRangeselectedRange()voidboolreadFile(constQStringboolwriteFile(constQStringvoid parepublicvoidfindNext(constQStringvoidfindPrevious(constQStringvoidprivatevoidenum umber=0x7F51C883,RowCount=999,ColumnCount=Cell*cell(introw,intcolumn)QStringtext(introw,intcolumn)QStringformula(introw,intcolumn)voidsetFormula(introw,intcolumn,constQStringboolbool{booloperator()(constQStringListconstQStringList&row2)const;enum{KeyCount=3};intboolFigure4.1.InheritancetreesforSpreadsheetand文本,對齊等這個QTableWidget網(wǎng)格的屬性在QTableWidgetItem類里。QTableWidgetItemCell從QTableWidgetItem繼承的,將在下一節(jié)介紹。MainWindowSpreadsheet的一些函數(shù)。MainWindow::newFileclear()QTableWidgetsetCurrentCell()setShowGrid()就多次調(diào)用過。私有槽函數(shù)somethingChanged()在Speadsheet類。在類的私有部分,我們了三個常數(shù),四個函數(shù)和一個變量。在頭文件的最后定義了類pare#include<QtGui>#include"cell.h"#include"spreadsheet.h":{autoRecalc=true;setItemPrototype(newCell);connect(this
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 中國裝配式建筑政策推動與建筑業(yè)降本增效路徑分析
- 求??坡?lián)盟協(xié)議書
- 江蘇返聘合同范本
- 汽修會員合同范本
- 汽車清洗合同范本
- 汽車贈予合同范本
- 沈陽市就業(yè)協(xié)議書
- 沙石協(xié)議合同范本
- 沒自行協(xié)商協(xié)議書
- 沭陽安置房協(xié)議書
- 皮影藝術(shù)資源引入初中美術(shù)教學(xué)的應(yīng)用研究
- 貴州省生態(tài)文明教育讀本(高年級) -教案(教學(xué)設(shè)計)
- 《財務(wù)會計-學(xué)習(xí)指導(dǎo)習(xí)題與實訓(xùn)》全書參考答案
- 2021大慶讓胡路萬達(dá)廣場商業(yè)購物中心開業(yè)活動策劃方案預(yù)算-67P
- 2022年福建翔安區(qū)社區(qū)專職工作者招聘考試真題
- 2023年考研考博-考博英語-湖南師范大學(xué)考試歷年真題摘選含答案解析
- 英語電影的藝術(shù)與科學(xué)智慧樹知到答案章節(jié)測試2023年中國海洋大學(xué)
- 2023-2024學(xué)年新疆維吾爾自治區(qū)烏魯木齊市小學(xué)數(shù)學(xué)六年級上冊期末??紲y試題
- GB/T 15814.1-1995煙花爆竹藥劑成分定性測定
- GB/T 11446.7-2013電子級水中痕量陰離子的離子色譜測試方法
- 中國地質(zhì)大學(xué)武漢軟件工程專業(yè)學(xué)位研究生實踐手冊
評論
0/150
提交評論