開(kāi)發(fā)及實(shí)例章多線程_第1頁(yè)
開(kāi)發(fā)及實(shí)例章多線程_第2頁(yè)
開(kāi)發(fā)及實(shí)例章多線程_第3頁(yè)
開(kāi)發(fā)及實(shí)例章多線程_第4頁(yè)
開(kāi)發(fā)及實(shí)例章多線程_第5頁(yè)
已閱讀5頁(yè),還剩41頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第12章Qt5多線程12.1多線程及簡(jiǎn)單實(shí)例12.2多線程控制12.3多線程應(yīng)用第12章Qt5多線程多線程具有以下幾點(diǎn)優(yōu)勢(shì)。(1)提高應(yīng)用程序的響應(yīng)速度。這對(duì)于開(kāi)發(fā)圖形界面的程序尤為重要,當(dāng)一個(gè)操作耗時(shí)很長(zhǎng)時(shí),整個(gè)系統(tǒng)都會(huì)等待這個(gè)操作,程序就不能響應(yīng)鍵盤(pán)、鼠標(biāo)、菜單等的操作,而使用多線程技術(shù)可將耗時(shí)長(zhǎng)的操作置于一個(gè)新的線程,從而避免以上的問(wèn)題。(2)使多CPU系統(tǒng)更加有效。當(dāng)線程數(shù)不大于CPU數(shù)目時(shí),操作系統(tǒng)可以調(diào)度不同的線程運(yùn)行于不同的CPU上。(3)改善程序結(jié)構(gòu)。一個(gè)既長(zhǎng)又復(fù)雜的進(jìn)程可以考慮分為多個(gè)線程,成為獨(dú)立或半獨(dú)立的運(yùn)行部分,這樣有利于代碼的理解和維護(hù)。第12章Qt5多線程多線程程序有以下幾個(gè)特點(diǎn)。(1)多線程程序的行為無(wú)法預(yù)期,當(dāng)多次執(zhí)行上述程序時(shí),每一次的運(yùn)行結(jié)果都可能不同。(2)多線程的執(zhí)行順序無(wú)法保證,它與操作系統(tǒng)的調(diào)度策略和線程優(yōu)先級(jí)等因素有關(guān)。(3)多線程的切換可能發(fā)生在任何時(shí)刻、任何地點(diǎn)。(4)多線程對(duì)代碼的敏感度高,因此對(duì)代碼的細(xì)微修改都可能產(chǎn)生意想不到的結(jié)果。12.1

多線程及簡(jiǎn)單實(shí)例【例】(難度一般)(CH1201)如圖12.1所示,單擊“開(kāi)始”按鈕將啟動(dòng)數(shù)個(gè)工作線程(工作線程數(shù)目由MAXSIZE宏決定),各個(gè)線程循環(huán)打印數(shù)字0~9,直到單擊“停止”按鈕終止所有線程為止。實(shí)現(xiàn)步驟如下。(1)在頭文件“threaddlg.h”中聲明用于界面顯示所需的控件,其具體代碼如下:#include<QDialog>#include<QPushButton>classThreadDlg:publicQDialog{Q_OBJECTpublic:ThreadDlg(QWidget*parent=0);~ThreadDlg();private:QPushButton*startBtn;QPushButton*stopBtn;QPushButton*quitBtn;};12.1

多線程及簡(jiǎn)單實(shí)例(2)在源文件“threaddlg.cpp”的構(gòu)造函數(shù)中,完成各個(gè)控件的初始化工作,其具體代碼如下:#include"threaddlg.h"#include<QHBoxLayout>ThreadDlg::ThreadDlg(QWidget*parent):QDialog(parent){setWindowTitle(tr("線程"));startBtn=newQPushButton(tr("開(kāi)始"));stopBtn=newQPushButton(tr("停止"));quitBtn=newQPushButton(tr("退出"));QHBoxLayout*mainLayout=newQHBoxLayout(this);mainLayout->addWidget(startBtn);mainLayout->addWidget(stopBtn);mainLayout->addWidget(quitBtn);}12.1

多線程及簡(jiǎn)單實(shí)例(3)此時(shí)運(yùn)行程序,界面顯示如圖12.1所示。以上完成了界面的設(shè)計(jì),下面的內(nèi)容是具體的功能實(shí)現(xiàn)。(1)在頭文件“workthread.h”中,工作線程WorkThread類繼承自QThread類。重新實(shí)現(xiàn)run()函數(shù)。其具體代碼如下:#include<QThread>classWorkThread:publicQThread{Q_OBJECTpublic:WorkThread();protected:voidrun();};12.1

多線程及簡(jiǎn)單實(shí)例(2)在源文件“workthread.cpp”中添加具體實(shí)現(xiàn)代碼如下:#include"workthread.h"#include<QtDebug>WorkThread::WorkThread(){}run()函數(shù)實(shí)際上是一個(gè)死循環(huán),它不停地打印數(shù)字0~9。為了顯示效果明顯,程序?qū)⒚恳粋€(gè)數(shù)字重復(fù)打印8次。voidWorkThread::run(){while(true){for(intn=0;n<10;n++)qDebug()<<n<<n<<n<<n<<n<<n<<n<<n;}}12.1

多線程及簡(jiǎn)單實(shí)例(3)在頭文件“threaddlg.h”中添加以下內(nèi)容:#include"workthread.h"#defineMAXSIZE1 //MAXSIZE宏定義了線程的數(shù)目publicslots:voidslotStart(); //槽函數(shù)用于啟動(dòng)線程voidslotStop(); //槽函數(shù)用于終止線程private:WorkThread*workThread[MAXSIZE]; //(a)12.1

多線程及簡(jiǎn)單實(shí)例(4)在源文件“threaddlg.cpp”中添加以下內(nèi)容。其中,在構(gòu)造函數(shù)中添加如下代碼:connect(startBtn,SIGNAL(clicked()),this,SLOT(slotStart()));connect(stopBtn,SIGNAL(clicked()),this,SLOT(slotStop()));connect(quitBtn,SIGNAL(clicked()),this,SLOT(close()));槽函數(shù)slotStart(),當(dāng)用戶單擊“開(kāi)始”按鈕時(shí),此函數(shù)將被調(diào)用。這里使用兩個(gè)循環(huán),目的是為了使新建的線程盡可能同時(shí)開(kāi)始執(zhí)行,其具體實(shí)現(xiàn)代碼如下:voidThreadDlg::slotStart(){for(inti=0;i<MAXSIZE;i++){workThread[i]=newWorkThread(); //(a)}for(inti=0;i<MAXSIZE;i++){workThread[i]->start(); //(b)}startBtn->setEnabled(false);stopBtn->setEnabled(true);}12.1

多線程及簡(jiǎn)單實(shí)例槽函數(shù)slotStop(),當(dāng)用戶單擊“停止”按鈕時(shí),此函數(shù)將被調(diào)用。其具體實(shí)現(xiàn)代碼如下:voidThreadDlg::slotStop(){for(inti=0;i<MAXSIZE;i++){workThread[i]->terminate();workThread[i]->wait();}startBtn->setEnabled(true);stopBtn->setEnabled(false);}12.1

多線程及簡(jiǎn)單實(shí)例(5)運(yùn)行結(jié)果如圖12.2所示。

MAXSIZE=5MAXSIZE=112.2

多線程控制實(shí)現(xiàn)線程的互斥與同步常使用的類有QMutex、QMutexLocker、QReadWriteLocker、QReadLocker、QWriteLocker、QSemaphore和QWaitCondition。下面舉一個(gè)例子來(lái)說(shuō)明問(wèn)題:classKey{public:Key(){key=0;}intcreatKey(){++key;returnkey;}intvalue()const{returnkey;}private:intkey;};12.2

多線程控制雖然類Key產(chǎn)生主鍵的函數(shù)creatKey()只有一條語(yǔ)句執(zhí)行修改成員變量key的值,但是C++的“++”操作符并不是原子操作,通常編譯后,它將被展開(kāi)成為以下三條機(jī)器命令:

將變量值載入寄存器。

將寄存器中的值加1。

將寄存器中的值寫(xiě)回主存。假設(shè)當(dāng)前的key值為0,如果線程1和線程2同時(shí)將0值載入寄存器,執(zhí)行加1操作并將加1后的值寫(xiě)回主存,則結(jié)果是兩個(gè)線程的執(zhí)行結(jié)果將互相覆蓋,實(shí)際上僅進(jìn)行了一次加1操作,此時(shí)的key值為1。12.2.1互斥量1.QMutex類QMutex類是對(duì)互斥量的處理。它被用來(lái)保護(hù)一段臨界區(qū)代碼,即每次只允許一個(gè)線程訪問(wèn)這段代碼。QMutex類的lock()函數(shù)用于鎖住互斥量。如果互斥量處于解鎖狀態(tài),則當(dāng)前線程就會(huì)立即抓住并鎖定它,否則當(dāng)前線程就會(huì)被阻塞,直到持有這個(gè)互斥量的線程對(duì)它解鎖。線程調(diào)用lock()函數(shù)后就會(huì)持有這個(gè)互斥量,直到調(diào)用unlock()操作為止。QMutex類還提供了一個(gè)tryLock()函數(shù)。如果互斥量已被鎖定,則立即返回。例如:classKey{public:Key(){key=0;}intcreatKey(){mutex.lock();++key;returnkey;mutex.unlock();}intvalue()const{mutex.lock();returnkey;mutex.unlock();}private:intkey;QMutexmutex;};12.2.1互斥量2.QMutexLocker類Qt提供的QMutexLocker類可以簡(jiǎn)化互斥量的處理,它在構(gòu)造函數(shù)中接收一個(gè)QMutex對(duì)象作為參數(shù)并將其鎖定,在析構(gòu)函數(shù)中解鎖這個(gè)互斥量,這樣就解決了以上問(wèn)題。例如:classKey{public:Key(){key=0;}intcreatKey(){QmutexLockerlocker(&mutex);++key;returnkey;}intvalue()const{QmutexLockerlocker(&mutex);returnkey;}private:intkey;QMutexmutex;};12.2.2信號(hào)量生產(chǎn)者/消費(fèi)者實(shí)例中對(duì)同步的需求有兩處:(1)如果生產(chǎn)者過(guò)快地生產(chǎn)數(shù)據(jù),將會(huì)覆蓋消費(fèi)者還沒(méi)有讀取的數(shù)據(jù)。(2)如果消費(fèi)者過(guò)快地讀取數(shù)據(jù),將越過(guò)生產(chǎn)者并且讀取到一些過(guò)期數(shù)據(jù)。針對(duì)以上問(wèn)題,可以有兩種解決方法:(1)首先使生產(chǎn)者填滿整個(gè)緩沖區(qū),然后等待消費(fèi)者讀取整個(gè)緩沖區(qū),這是一種比較笨拙的方法。(2)使生產(chǎn)者和消費(fèi)者線程同時(shí)分別操作緩沖區(qū)的不同部分,這是一種比較高效的方法。12.2.2信號(hào)量【例】(難度一般)(CH1202)基于控制臺(tái)程序?qū)崿F(xiàn)。(1)源文件“main.cpp”中添加的具體實(shí)現(xiàn)代碼如下:#include<QCoreApplication>#include<QSemaphore>#include<QThread>#include<stdio.h>constintDataSize=1000;constintBufferSize=80;intbuffer[BufferSize]; //(a)QSemaphorefreeBytes(BufferSize); //(b)QSemaphoreusedBytes(0); //(c)(2)Producer類繼承自QThread類,作為生產(chǎn)者類,其聲明如下:classProducer:publicQThread{public:Producer();voidrun();};12.2.2信號(hào)量Producer構(gòu)造函數(shù)中沒(méi)有實(shí)現(xiàn)任何內(nèi)容:Producer::Producer(){}Producer::run()函數(shù)的具體實(shí)現(xiàn)代碼如下:voidProducer::run(){for(inti=0;i<DataSize;i++){freeBytes.acquire(); //(a)buffer[i%BufferSize]=(i%BufferSize); //(b)usedBytes.release(); //(c)}}12.2.2信號(hào)量(3)Consumer類繼承自QThread類,作為消費(fèi)者類,其聲明如下:classConsumer:publicQThread{public:Consumer();voidrun();};Consumer構(gòu)造函數(shù)中沒(méi)有實(shí)現(xiàn)任何內(nèi)容:Consumer::Consumer(){}12.2.2信號(hào)量Consumer::run()函數(shù)的具體實(shí)現(xiàn)代碼如下:voidConsumer::run(){for(inti=0;i<DataSize;i++){usedBytes.acquire(); //(a)fprintf(stderr,"%d",buffer[i%BufferSize]); //(b)if(i%16==0&&i!=0)fprintf(stderr,"\n");freeBytes.release(); //(c)}fprintf(stderr,"\n");}12.2.2信號(hào)量(4)main()函數(shù)的具體內(nèi)容如下:intmain(intargc,char*argv[]){QCoreApplicationa(argc,argv);Producerproducer;Consumerconsumer; /*啟動(dòng)生產(chǎn)者和消費(fèi)者線程*/producer.start();consumer.start(); /*等待生產(chǎn)者和消費(fèi)者各自執(zhí)行完畢后自動(dòng)退出*/producer.wait();consumer.wait();returna.exec();}12.2.2信號(hào)量(5)最終運(yùn)行結(jié)果如圖12.3所示。12.2.3線程等待與喚醒【例】(難度一般)(CH1203)使用QWaitCondition類解決生產(chǎn)者和消費(fèi)者問(wèn)題。源文件“main.cpp”的具體內(nèi)容如下:#include<QCoreApplication>#include<QWaitCondition>#include<QMutex>#include<QThread>#include<stdio.h>constintDataSize=1000;constintBufferSize=80;intbuffer[BufferSize];QWaitConditionbufferEmpty;QWaitConditionbufferFull;QMutexmutex; //(a)intnumUsedBytes=0; //(b)intrIndex=0; //(c)12.2.3線程等待與喚醒生產(chǎn)者線程Producer類繼承自QThread類,其聲明如下:classProducer:publicQThread{public:Producer();voidrun();};Producer構(gòu)造函數(shù)無(wú)須實(shí)現(xiàn):Producer::Producer(){}12.2.3線程等待與喚醒Producer::run()函數(shù)的具體內(nèi)容如下:voidProducer::run(){for(inti=0;i<DataSize;i++) //(a){mutex.lock();if(numUsedBytes==BufferSize) //(b)bufferEmpty.wait(&mutex); //(c)buffer[i%BufferSize]=numUsedBytes; //(d)++numUsedBytes; //增加numUsedBytes變量bufferFull.wakeAll(); //(e)mutex.unlock();}}12.2.3線程等待與喚醒其中,(a)for(inti=0;i<DataSize;i++){mutex.lock();…mutex.unlock();}:for循環(huán)中的所有語(yǔ)句都需要使用互斥量加以保護(hù),以保證其操作的原子性。(b)if(numUsedBytes==BufferSize):首先檢查緩沖區(qū)是否已經(jīng)填滿。(c)bufferEmpty.wait(&mutex):如果緩沖區(qū)已經(jīng)填滿,則等待“緩沖區(qū)有空位”(bufferEmpty變量)條件成立。wait()函數(shù)將互斥量解鎖并在此等待,其原型如下:boolQWaitCondition::wait( QMutex*mutex, unsignedlongtime=ULONG_MAX)(d)buffer[i%BufferSize]=numUsedBytes:如果緩沖區(qū)未被填滿,則向緩沖區(qū)中寫(xiě)入一個(gè)整數(shù)值。(e)bufferFull.wakeAll():最后喚醒等待“緩沖區(qū)有可用數(shù)據(jù)”(bufferEmpty變量)條件為“真”的線程。12.2.3線程等待與喚醒消費(fèi)者線程Consumer類繼承自QThread類,其聲明如下:classConsumer:publicQThread{public:Consumer();voidrun();};Consumer構(gòu)造函數(shù)中無(wú)須實(shí)現(xiàn)內(nèi)容:Consumer::Consumer(){}12.2.3線程等待與喚醒Consumer::run()函數(shù)的具體內(nèi)容如下:voidConsumer::run(){forever{mutex.lock();if(numUsedBytes==0)bufferFull.wait(&mutex); //(a)printf("%ul::[%d]=%d\n",currentThreadId(),rIndex,buffer[rIndex]); //(b)rIndex=(++rIndex)%BufferSize; //將rIndex變量循環(huán)加1--numUsedBytes; //(c)bufferEmpty.wakeAll(); //(d)mutex.unlock();}printf("\n");}12.2.3線程等待與喚醒main()函數(shù)的具體內(nèi)容如下:intmain(intargc,char*argv[]){QCoreApplicationa(argc,argv);Producerproducer;ConsumerconsumerA;ConsumerconsumerB;producer.start();consumerA.start();consumerB.start();producer.wait();consumerA.wait();consumerB.wait();returna.exec();}12.2.3線程等待與喚醒程序最終的運(yùn)行結(jié)果如圖12.4所示。12.3

多線程應(yīng)用12.3.1【實(shí)例】:服務(wù)器編程【例】(難度中等)(CH1204)服務(wù)器編程。首先,建立服務(wù)器端工程“TimeS”。文件代碼如下。(1)在頭文件“dialog.h”中,定義服務(wù)器端界面類Dialog繼承自QDialog類,其具體代碼如下:#include<QDialog>#include<QLabel>#include<QPushButton>classDialog:publicQDialog{Q_OBJECTpublic:Dialog(QWidget*parent=0);~Dialog();private:QLabel*Label1; //此標(biāo)簽用于顯示監(jiān)聽(tīng)端口QLabel*Label2; //此標(biāo)簽用于顯示請(qǐng)求次數(shù)QPushButton*quitBtn; //退出按鈕};12.3.1【實(shí)例】:服務(wù)器編程(2)在源文件“dialog.cpp”中,Dialog類的構(gòu)造函數(shù)完成了初始化界面,其具體代碼如下:#include"dialog.h"#include<QHBoxLayout>#include<QVBoxLayout>Dialog::Dialog(QWidget*parent):QDialog(parent){setWindowTitle(tr("多線程時(shí)間服務(wù)器"));Label1=newQLabel(tr("服務(wù)器端口:"));Label2=newQLabel;quitBtn=newQPushButton(tr("退出"));QHBoxLayout*BtnLayout=newQHBoxLayout;BtnLayout->addStretch(1);BtnLayout->addWidget(quitBtn);BtnLayout->addStretch(1);QVBoxLayout*mainLayout=newQVBoxLayout(this);mainLayout->addWidget(Label1);mainLayout->addWidget(Label2);mainLayout->addLayout(BtnLayout);connect(quitBtn,SIGNAL(clicked()),this,SLOT(close()));}12.3.1【實(shí)例】:服務(wù)器編程(3)此時(shí)運(yùn)行服務(wù)器端工程“TimeS”,界面顯示如圖12.5所示。12.3.1【實(shí)例】:服務(wù)器編程(4)在服務(wù)器端工程“TimeS”中,添加C++Class文件“timethread.h”及“timethread.cpp”。在頭文件“timethread.h”中,工作線程TimeThread類繼承自QThread類,實(shí)現(xiàn)TCP套接字,其具體代碼如下:#include<QThread>#include<QtNetwork>#include<QTcpSocket>classTimeThread:publicQThread{Q_OBJECTpublic:TimeThread(intsocketDescriptor,QObject*parent=0);voidrun(); //重寫(xiě)此虛函數(shù)signals:voiderror(QTcpSocket::SocketErrorsocketError); //出錯(cuò)信號(hào)private:intsocketDescriptor; //套接字描述符};12.3.1【實(shí)例】:服務(wù)器編程(5)在源文件“timethread.cpp”中,TimeThread類的構(gòu)造函數(shù)只是初始化了套接字描述符,其具體代碼如下:#include"timethread.h"#include<QDateTime>#include<QByteArray>#include<QDataStream>TimeThread::TimeThread(intsocketDescriptor,QObject*parent):QThread(parent),socketDescriptor(socketDescriptor){}12.3.1【實(shí)例】:服務(wù)器編程TimeThread::run()函數(shù)是工作線程(TimeThread)的實(shí)質(zhì)所在,當(dāng)在TimeServer::ingConnection()函數(shù)中調(diào)用了thread->start()函數(shù)后,此虛函數(shù)開(kāi)始執(zhí)行,其具體代碼如下:voidTimeThread::run(){QTcpSockettcpSocket; //創(chuàng)建一個(gè)QTcpSocket類

if(!tcpSocket.setSocketDescriptor(socketDescriptor)) //(a){emiterror(tcpSocket.error()); //(b)return;}QByteArrayblock;QDataStreamout(&block,QIODevice::WriteOnly);out.setVersion(QDataStream::Qt_5_8);uinttime2u=QDateTime::currentDateTime().toTime_t();//(c)out<<time2u;tcpSocket.write(block); //將獲得的當(dāng)前時(shí)間傳回客戶端

tcpSocket.disconnectFromHost(); //斷開(kāi)連接

tcpSocket.waitForDisconnected(); //等待返回}12.3.1【實(shí)例】:服務(wù)器編程(6)在服務(wù)器端工程“TimeS”中添加C++Class文件“timeserver.h”及“timeserver.cpp”。在頭文件“timeserver.h”中,實(shí)現(xiàn)了一個(gè)TCP服務(wù)器端,類TimeServer繼承自QTcpServer類,其具體代碼如下:#include<QTcpServer>classDialog; //服務(wù)器端的聲明classTimeServer:publicQTcpServer{Q_OBJECTpublic:TimeServer(QObject*parent=0);protected:voidingConnection(intsocketDescriptor); //(a)private:Dialog*dlg; //(b)};12.3.1【實(shí)例】:服務(wù)器編程(7)在源文件“timeserver.cpp”中,構(gòu)造函數(shù)只是用傳入的父類指針parent初始化私有變量dlg,其具體代碼如下:#include"timeserver.h"#include"timethread.h"#include"dialog.h"TimeServer::TimeServer(QObject*parent):QTcpServer(parent){dlg=(Dialog*)parent;}重寫(xiě)的虛函數(shù)ingConnection()的具體代碼如下:voidingConnection(intsocketDescriptor){TimeThread*thread=newTimeThread(socketDescriptor,0); //(a)connect(thread,SIGNAL(finished()),dlg,SLOT(slotShow())); //(b)connect(thread,SIGNAL(finished()),thread,SLOT(deleteLater()),Qt::DirectConnection); //(c)thread->start(); //(d)}12.3.1【實(shí)例】:服務(wù)器編程(8)在服務(wù)器端界面的頭文件“dialog.h”中添加的具體代碼如下:classTimeServer;publicslots:voidslotShow(); //此槽函數(shù)用于界面上顯示的請(qǐng)求次數(shù)private:TimeServer*timeServer; //TCP服務(wù)器端timeServerintcount; //請(qǐng)求次數(shù)計(jì)數(shù)器count12.3.1【實(shí)例】:服務(wù)器編程(9)在源文件“dialog.cpp”中,添加的頭文件如下:#include<QMessageBox>#include"timeserver.h"其中,在Dialog類的構(gòu)造函數(shù)中添加的內(nèi)容,用于啟動(dòng)服務(wù)器端的網(wǎng)絡(luò)監(jiān)聽(tīng),其具體實(shí)現(xiàn)如下:count=0;timeServer=newTimeServer(this);if(!timeServer->listen()){QMessageBox::critical(this,tr("多線程時(shí)間服務(wù)器"),tr("無(wú)法啟動(dòng)服務(wù)器:%1.").arg(timeServer->errorString()));close();return;}Label1->setText(tr("服務(wù)器端口:%1.").arg(timeServer->serverPort()));在源文件“dialog.cpp”中,槽函數(shù)slotShow()的具體內(nèi)容如下:voidDialog::slotShow(){Label2->setText(tr("第%1次請(qǐng)求完畢。").arg(++count));}12.3.1【實(shí)例】:服務(wù)器編程(10)在服務(wù)器端工程文件“TimeS”中添加如下代碼:QT+=network(11)最后運(yùn)行服務(wù)器端工程“TimeS”,結(jié)果如圖12.6所示。12.3.2【實(shí)例】:客戶端編程【例】(難度中等)(CH1205)客戶端編程。界面效果如圖12.7所示。12.3.2【實(shí)例】:客戶端編程操作步驟如下。(1)建立客戶端工程“TimeC”。在頭文件“timeclient.h”中,定義了客戶端界面類TimeClient繼承自QDialog類,其具體代碼。(2)在源文件“timeclient.cpp”中,TimeClient類的構(gòu)造函數(shù)完成了初始化界面,其具體代碼。在源文件“timeclient.cpp”中,enableGetBtn()函數(shù)的具體代碼如下:voidTimeClient::enableGetBtn(){getBtn->setEnabled(!serverNameLineEdit->text().isEmpty()&&!portLineEdit->text().isEmpty());

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論