軟件自動更新解決方案及QT實現

from:https://blog.csdn.net/hulinhulin/article/details/46839107

軟件自動更新解決放案及QT實現...1

1 文件的版本控制-XML.2

2 更新程序的實現...2

2.1 界面設置...2

2.2 程序功能...3

2.2.1 下載網絡數據...3

2.2.2 XML文件的分析...6

2.2.3 下載XML文件的DownLoadXML函數...8

2.2.4 返回指定XML文件中的name版本號...8

2.2.5 返回指定XML文件中的name版本號...10

2.2.6 比較兩個XML文件CheckUpdateFiles.11

2.2.7 下載文件DownLoadUpdateFiles.13

2.2.7 退出當前程序,并啟動指定的程序...16

3 更新程序的啟動...16

3.1 從主程序啟動更新程序...16

3.2 主程序的關閉...17

3.3 更新程序關閉時啟動主程序...17

4 程序調試...17

軟件自動更新解決放案及QT實現

需要考慮解決的問題:

1)?需要知道哪些文件需要更新,哪些不需要;

2)?從哪里下載更新文件;

3)?將舊的文件用新的文件替換掉(包含版本控制文件);

4)?更新完畢后重新啟動主程序;

?

第一個問題,可以為程序所使用的文件都設定一個版本號,版本號都記錄在一個 XML 文件中,升級時,檢查最新程序的版本控制文件和當前的版本控制文件,最新版本號較大時,表示該文件需要更新。如果一個文件不再需要了,則將該文件的版本信息從最新的版本控制文件中刪除,通過對比控制文件,就知道該文件不再需要了,可以將之刪除;

第二個問題,最新的版本控制文件需要放在一個可供方便下載的地方,例如FTP或者一個固定的IP;

第三個問題,通過對比新的版本控制文件和舊的版本控制文件來確定哪些需要替換或者刪除;

第四個問題,更新程序運行完后,啟動主程序即可,需要一個標識來說明是否更新完成;

?

按照以上的思路,下面對每一個步驟結合程序進行詳細地闡述,軟件使用QT5.1實現。

?

1?文件的版本控制-XML

下面是使用XML文件來表示的版本控制文件:

<?xml version="1.0"encoding="utf-8"?>?

<filelist>?

?<filename="qico.dll" dir="imageformats"version="1.0"/>

?<filename="qminimal.dll" dir="imageformats"version="1.0"/>

…..

?<file name="main.exe"version="1.0"/>

</filelist>?

Name表示文件的名稱;

dir表示所在的目錄(相對目錄);

version表示當前文件的版本;

2?更新程序的實現

更新程序使用QT5.1來實現,最終生成一個可執行文件(exe文件)。新建工程時選擇QT GUI應用,其他都默認,工程名為Updater。

2.1?界面設置

在構造函數中設置界面。

應用程序在屏幕中間:

QDesktopWidget *deskdop = QApplication::desktop();

this->move((deskdop->width() -this->width())/2, (deskdop->height() - this->height())/2);

?

無標題欄:

this->setWindowFlags(Qt::FramelessWindowHint);//沒有標題欄

?

隱藏菜單欄和工具欄??

this->ui->menuBar->hide();

this->ui->mainToolBar->hide();

?

固定高和寬:

this->setFixedSize(400,200);

???

設置背景顏色(兩種方法都可以)

???//this->setStyleSheet("QMainWindow{background:rgb(240,250,250)}");

QPalette pal;

pal.setColor(QPalette::Background,QColor(255,245,225) );

this->setPalette(pal);

this->setAutoFillBackground(true);

2.2?程序功能

??? 程序功能包括從網絡下載數據,分析XML文件,比較當前的XML及下載的XML文件,并最終確定哪些文件需要更新或者添加

2.2.1?下載網絡數據

新建類CHttpDownLoadFile,類功能:從指定網絡中下載指定的文件,并且存儲到指定的本地文件目錄中。

主要的成員函數及槽函數:

public slots:

???void ReplyNewDataArrived();//響應m_netReply有新的數據到達

???void ReplyFinished();//響應數據接收完成

public:

???QNetworkAccessManager *m_netAccessManager;//網絡參數

???QNetworkReply *m_netReply;

?

???QUrl m_urlAdress;//網絡地址

???QString m_strFileName;//需要下載的文件名

???QString m_strDir;//文件的存儲位置

?

???QFile *m_file;//下載的文件

?

??? ???qint64m_nReceived;//下載文件時,已經接收的文件大小和總共大小

???qint64m_nTotal;

主要函數及功能:

a.構造函數

CHttpDownloadFile(QString url,QStringfileName,QString dir,QObject *parent = 0);

url表示文件的網絡地址;

filename表示文件名;

dir表示文件存儲路徑

??? 如果fileName不為空,那么文件名使用fileName,否則從url提取(注:不需要加后綴)。如果dir不為空,那么將文件存儲到dir指向的文件夾中,否則存儲在默認路徑中(即與可執行文件在同一個文件夾中),如果文件夾不存在,那么會創建,dir舉例:c:/temp/,或者c:/temp,如果前面不加盤符,那么將會在默認文件夾中創建。

b. 開始下載文件的函數:void DownLoadFile()

m_netReply=m_netAccessManager->get(QNetworkRequest(m_urlAdress));

connect(m_netReply,SIGNAL(readyRead()),

this,SLOT( ReplyNewDataArrived()) );//當有新數據到達時就會觸發此信號

connect(m_netReply, SIGNAL(finished()),

this,SLOT( ReplyFinished()) );//完成數據接收后發送此信號

connect(m_netReply, SIGNAL(error(QNetworkReply::NetworkError)),this, SLOT( ReplyError(QNetworkReply::NetworkError)) );//出現錯誤時發送此信號;

connect(m_netReply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(ReplyDownloadProgress(qint64,qint64) ) );//用來提示文件下載進度

?

???/*************存儲文件的檢測及使用************/

???if( m_strFileName.isEmpty() )//文件名

??? {

???????QFileInfo fileInfo(m_urlAdress.path());

???????m_strFileName = fileInfo.fileName();

??? }

?

???if( !m_strDir.isEmpty() )//文件夾

??? {

???????QDir directory( m_strDir );

?

???????if( !directory.exists() )//沒有此文件夾,則創建

???????{

???????????directory.mkpath( m_strDir );

???????}

?

???????m_strFileName = m_strDir + "/"+m_strFileName;//添加/是為了防止用戶名沒有加/,因為對于文件夾來說兩個/都會當成一個/

??? }

???if( QFile::exists(m_strFileName) )//如果文件已經存在,那么刪除

??? {

???????QFile::remove(m_strFileName);

??? }

???m_file = new QFile( m_strFileName );

???if (!m_file->open(QIODevice::WriteOnly))

??? {

???????qDebug()<<"不能存儲文件:"<<m_strFileName;

???????delete m_file;

???????m_file = NULL;

???????return;

??? }

c.槽函數void ReplyFinished(),當下載網絡數據結束時響應此函數,主要是釋放資源

???m_netAccessManager->deleteLater();

???m_netReply->deleteLater();

???m_file->close();

???m_file->deleteLater();

?

d.槽函數voidReplyNewDataArrived()—當數據到達時調用此函數,并存儲到指定的文件中
??? if(m_file)
??? {
??????? m_file->write(m_netReply->readAll());
??????? m_file->flush();//注意需要刷新
??? }
??? else
??? {
??????? qDebug()<<m_netReply->readAll();
??? }

2.2.2 XML文件的分析

??? QFile file(filename);

??? if(!file.open(QIODevice::ReadOnly | QFile::Text)) {

???????qDebug()<<"open for read error..." ;

??? }

??? QString errorStr;

??? int errorLine;

??? int errorColumn;

??? QDomDocument doc;

???if(!doc.setContent(&file, false, &errorStr, &errorLine,&errorColumn)) {

???????qDebug()<<"setcontent error..." ;

??????? file.close();

??? }

??? file.close();

??? QDomElement root =doc.documentElement();

??? if (root.tagName() !="filelist")

??? {

??????qDebug()<<"root.tagname != filelist.." ;

??? }

??? else

??? {

??????? QDomNodeListnodeList = root.elementsByTagName("file");

??????? for(inti=0;i<nodeList.size();i++)

??????? {

???????? ???qDebug()<<nodeList.at(i).toElement().attribute("name")

?????????????????????<<nodeList.at(i).toElement().attribute("dir")

???????????????????????<<nodeList.at(i).toElement().attribute("version");

??????? }

}???????

}

這里只是將XML文件的內容輸出,詳細的代碼在工程Updater的其他函數中。

2.2.3?下載XML文件的DownLoadXML函數

函數下載XML文件,當XML文件下載完成時發送下載完成信號,提示進行下一步操作。

????/**從網頁下載XML版本控制文件,里面記錄了最新的文件版本**/

????QStringstrCurrentDir=QDir::currentPath();//當前程序運行路徑

????QStringstrDownLoad=strCurrentDir+"/download/";//存放下載文件的路徑

?

????QDirdirectory(strDownLoad);//如果路徑不存在,則創建

????if(!directory.exists())

????{

???????directory.mkpath(strDownLoad);

????}

?

????m_httpXML=newCHttpDownloadFile("http://www.***.com/download/**.xml","",strDownLoad,this);//調用下載文件的類

????connect(m_httpXML,SIGNAL(DownloadFinishedSignal()),this,SLOT(ReplyHttpFinished()));//發生錯誤時一樣會發送此信號

m_httpXML->DownLoadFile();

在ReplyHttpFinished()函數中需要錯誤處理。

實例化m_httpXML時,需要將parent設置為this,這樣當程序結束時,會自動釋放。

2.2.4?返回指定XML文件中的name版本號

????/***********在xml中查找名字與name相同的元素,并返回版本號**

?????*xml:xml文件的路徑;

?????*name:需要查找的元素名稱;

?????*

?????*return:QString:版本號,如果有則返回,沒有則為空

?????************************************************/

?QStringGetElementVersion(QStringxml,QStringname);

?

實現:

GetElementVersion(QStringxml,QStringname)

{

????QStringresult="";

????if(xml.isEmpty()||name.isEmpty())

????{

???????qDebug()<<"名稱或者xml文件路徑為空";

???????returnresult;

????}

?

????if(!QFile::exists(xml))

????{

???????qDebug()<<"xml文件不存在";

???????returnresult;

????}

?

????QFilefile(xml);

????if(file.open(QIODevice::ReadOnly|QFile::Text))//文件打開成功

????{

???????QDomDocumentdoc;

???????if(doc.setContent(&file))

???????{

???????????QDomElementroot=doc.documentElement();

???????????if(root.tagName()=="filelist")

???????????{

????????????????inti=0;

????????????????QDomNodeListnodeList=root.elementsByTagName("file");

????????????????for(;i<nodeList.size();i++)

????????????????{

????????????????????QStringtempName???=nodeList.at(i).toElement().attribute("name");

????????????????????//QStringdir????=nodeList.at(i).toElement().attribute("dir");

????????????????????QStringversion=nodeList.at(i).toElement().attribute("version");

?

????????????????????if(name==tempName)

????????????????????{

????????????????????????qDebug()<<"find!"<<name;

????????????????????????result=version;

????????????????????????break;

????????????????????}

????????????????}

?

????????????????if(i==nodeList.size())

????????????????{

????????????????????qDebug()<<"can'tfind!"<<name;

????????????????}

???????????}

???????????else

???????????{

????????????????qDebug()<<"root.tagname!=filelist..";

???????????}

???????}

???????else

???????{

???????????qDebug()<<"setcontenterror...";

???????}

?

???????file.close();

????}

????else

????{

???????qDebug()<<"openforreaderror...";

????}

?

????returnresult;

}

2.2.5?返回指定XML文件中的name版本號

????/**************比較兩個版本號*******************

?????*@params:

?????*?v1,v2:兩個版本號,格式:1.1.0,不能為空

?????*

?????*@return:

?????*?true:如果兩個版本號碼相同;

?????*?false:兩個版本號不同

?????*

?????*說明:暫時只比較了是否相同

?????*******************************************/

?boolCheckVersion(QStringv1,QStringv2);

實現比較簡單,就不貼代碼了。

2.2.6?比較兩個XML文件CheckUpdateFiles

通過比較兩個XML文件來確定需要下載的文件。

/************比較兩個XML文件****************

?????*@params:

?????*?name1,name2:兩個XML文件,不能為空,并且文件需要存在,name1必須是最新的xml文件(剛剛下載下來的),name2是本地的xml文件;

?????*

?????*@return:

?????*0-someerrorhappens,elsesuccess

?????*將需要更新的文件名存儲到m_listFileName

?????*路徑存儲到m_listFileDir

?????*

?????*注意:m_listFileDir和m_listFileName的個數是一樣的,

?????*????如果沒有元素表示所有的文件都不用更新

?????******************************************/

?intCheckUpdateFiles(QStringname1,QStringname2);

?

實現:

CheckUpdateFiles(QStringname1,QStringname2)

{

????m_listFileDir.clear();

????m_listFileName.clear();

?

????if(name1.isEmpty()||name2.isEmpty())return0;

?

????if(QFile::exists(name2))

????{

???????if(QFile::exists(name1))

???????{

???????????m_strTip="檢查需要更新的文件...";

?

???????????QFilefile(name1);

???????????if(file.open(QIODevice::ReadOnly|QFile::Text))//文件打開成功

???????????{

????????????????QStringerrorStr;

????????????????interrorLine;

????????????????interrorColumn;

?

????????????????QDomDocumentdoc;

????????????????if(doc.setContent(&file,false,&errorStr,&errorLine,&errorColumn))

????????????????{

????????????????????QDomElementroot=doc.documentElement();

????????????????????if(root.tagName()=="filelist")

????????????????????{

????????????????????????QDomNodeListnodeList=root.elementsByTagName("file");

????????????????????????for(inti=0;i<nodeList.size();i++)

????????????????????????{

????????????????????????????QStringname???=nodeList.at(i).toElement().attribute("name");

????????????????????????????QStringdir????=nodeList.at(i).toElement().attribute("dir");

????????????????????????????QStringversion=nodeList.at(i).toElement().attribute("version");

?

????????????????????????????QStringversionDownload=GetElementVersion(name2,name);//獲取本地xml文件對應文件(name)的版本信息

????????????????????????????if(versionDownload.isEmpty())//本地XML沒有此文件:下載,并放到相應的目錄中

????????????????????????????{

????????????????????????????????m_listFileDir.append(dir);

????????????????????????????????m_listFileName.append(name);

????????????????????????????}

????????????????????????????else

????????????????????????????{

????????????????????????????????/**檢查版本,如果本地版本低于下載的版本,則下載**/

????????????????????????????????if(!CheckVersion(version,versionDownload))

???????????????????????? ???????{

????????????????????????????????????m_listFileDir.append(dir);

????????????????????????????????????m_listFileName.append(name);

????????????????????????????????}

????????????????????????????????else

????????????????????????????????{

?????????????????????????????????????qDebug()<<name<<"文件是最新版本,不需要更新";

????????????????????????????????}

????????????????????????????}

????????????????????????}

?

????????????????????????return1;//此時要退出,避免關閉程序

????????????????????}

????????????????????else

????????????????????{

????????????????????????m_strTip="XML內容錯誤!";

????????????????????????return0;

????????????????????}

????????????????}

????????????????else

????????????????{

????????????????????qDebug()<<"setcontenterror...";

????????????????????return0;

????????????????}

?

????????????????file.close();

???????????}

???????????else

???????????{

????????????????m_strTip="不能打開更新文件!";

????????????????return0;

???????????}

???????}

???????else

???????{

???????????m_strTip="下載更新文件錯誤!";

???????????return0;

???????}

????}

????else

????{

???????m_strTip="本地的更新文件不存在!";

???????return0;

????}

}

2.2.7?下載文件DownLoadUpdateFiles

? 下載需要的文件,完成后啟動主程序 。

/********下載最新的版本的文件,并替換或者增加*********************

?????*舊XML中有的文件,新XML沒有的,此文件不做處理。

?????*下載信息由m_listFileName和m_listFileDir提供

?????*****************************************************/

???voidDownLoadUpdateFiles();

實現:

DownLoadUpdateFiles()

{

????QStringstrServer="http://www.***.com/download/";//需要下載的文件存儲位置

????QStringstrCurrentDir=QDir::currentPath();//當前程序運行路徑

?

????if(m_listFileDir.isEmpty()||m_listFileDir.isEmpty())

????{

???????qDebug()<<"沒有需要下載的文件1";

???????ExitApp(strCurrentDir+"/main.exe");

???????return;

????}

?

????m_strTip="開始下載更新文件...";

?

?

?

????m_bIsFinished=false;

?

????for(inti=0;i<m_listFileName.size();i++)

????{

???????m_strTip="正在下載文件"+m_listFileName.at(i);

???????m_progUpdate->setValue(100*i/m_listFileName.size());

?

???????/**放置下載的文件的路徑**/

???????QStringstrPlaceDir=strCurrentDir+"/download/"+m_listFileDir.at(i);

???????QDirdirectory(strPlaceDir);//如果路徑不存在,則創建

???????if(!directory.exists())directory.mkpath(strPlaceDir);

?

???????QStringstrFileDirServer=strServer+m_listFileDir.at(i)+"/"+m_listFileName.at(i);//文件在服務器中的存儲位置

???????CHttpDownloadFile*http=newCHttpDownloadFile(strFileDirServer,"",strPlaceDir,this);//調用下載文件的類

???????http->DownLoadFile();

???????while(!http->m_bIsFinished)

???????{

???????????if(http->m_nTotal==-1)

???????????{

????????????????m_progDownload->setValue(1);

???????????}

???????????else

???????????{

????????????????m_progDownload->setValue(100*http->m_nReceived/http->m_nTotal);

???????????}

???????????QCoreApplication::processEvents();

???????}

?

???????m_strTip="文件"+m_listFileName.at(i)+"下載完成";

?

?

???????/**將下載好的文件復制到主目錄中,先刪除原先的文件**/

???????QStringstrLocalFileName=strCurrentDir+"/"+m_listFileDir.at(i)+"/"+m_listFileName.at(i);

???????if(QFile::exists(strLocalFileName))QFile::remove(strLocalFileName);

?

???????QDirdirectory1(strCurrentDir+"/"+m_listFileDir.at(i));//如果路徑不存在,則創建

???????if(!directory1.exists())directory1.mkpath(strCurrentDir+"/"+m_listFileDir.at(i));

?

???????QFile::copy(strPlaceDir+"/"+m_listFileName.at(i),strLocalFileName);

????}

?

????m_bIsFinished=true;

????m_strTip="更新完成!";

?

????/**替換舊的xml文件**/

????QStringstrNewXML=strCurrentDir+"/download/**.xml";//最新的XML文件

????QStringstrOldXML=strCurrentDir+"/"+"**.xml";//舊的XML文件

?

????QFile::remove(strOldXML);

????QFile::copy(strNewXML,strOldXML);

?

????ExitApp(strCurrentDir+"/main.exe");

}

2.2.7?退出當前程序,并啟動指定的程序

????/********退出當前程序,并且啟動需要的程序*************************

?????*name:需要啟動的程序,可以使用相對位置

?????*程序不能使用exit(0),會發生線程錯誤,這里使用this->close()函數

?????*****************************************************/

實現:

ExitApp(QStringname)

{

????if(!name.isEmpty())

????{

???????/**運行主程序,并且退出當前更新程序(說明:主程序在上上一級目錄中)**/

???????if(!QProcess::startDetached(name))//啟動主程序,主程序在其上一級目錄

???????{

???????????QMessageBox::warning(this,"警告信息","啟動主程序錯誤!\n可能主程序不存在或者被破壞!\n解決辦法:重新安裝程序!");

???????}

????}

?

????this->close();

}

3?更新程序的啟動

??? 更新程序是獨立的可執行文件,所以在啟動主程序時,首先啟動更新程序(注:網絡檢查放在了更新程序中),然后關閉主程序,更新完成后,再重新啟動主程序。

3.1?從主程序啟動更新程序

??? 首先需要判斷是否需要啟動更新程序,避免更新后再次啟動更新程序;

??? 將是否需要啟動更新程序的參數放在軟件的初始參數文件中,例如params.txt文件中,初始值為true,表示需要啟動更新程序。主程序啟動時,先獲取里面的參數,并判斷是否需要啟動更新程序。完成更新后,將此參數設置為false,表示下次再次啟動主程序時不需更新,當點擊關閉主程序時再次將此參數設置為true,這樣就可以保證每次啟動時都會檢查更新;

啟動更新程序調用QProcess::startDetached()方法,啟動外部程序后立即返回(也就是主程序也運行),即使主程序關閉,啟動的程序也會運行,本程序使用這個方法,因為更新后。

注:如果調用QProcess::execute函數,此方法可以阻塞主程序的運行,直到啟動的程序關閉,因為需要關閉主程序,還要重新啟動更新后得程序,所以不能使用這個方法。

3.2?主程序的關閉

??? 如果QProcess::startDetached方法返回true,則關閉主程序,調用exit(0),或者quit()方法;

3.3?更新程序關閉時啟動主程序

更新程序結束時調用QProcess::startDetached("main.exe"),主程序和更新程序在同一目錄。但是在關閉更新程序的時候使用exit會發送錯誤,錯誤原因:會出現夸線程發送信號的情況,這是不容許的。

當所有文件都下載完成時,使用close函數。

4?程序調試

需要調試以下功能:

(1)主程序啟動時,檢測是否需要啟動更新程序, 檢測params.cq文件里面的is_update參數的值,如果為1則啟動,否則不啟動(代碼在CLoginBox的構造函數中);

(2)如果is_update=1,那么啟動更新程序,更新程序啟動后,is_update設置為0;

(3)主程序退出時,將is_update設置為1,即每次重新啟動主程序的時候都需要檢查更新;

(4)正確下載xml文件,存儲位置:與主程序同目錄下的download文件 夾中(特別提醒:由于更新程序是從主程序中調用的,所以在更新程序中調用獲取當前運行程序的目錄是得到的是主程序的的目錄,但是如果更新程序單獨運行的話,得到的目錄是和更新程序目錄一樣的,所以最好的方式就是講主程序和更新程序放在同一個目錄中);

(5)是否正確調用了更新程序里面的CheckUpdateFiles函數,主要是檢查是否輸入正確的xml文件目錄;

(6)下載的更新文件是否正確放置;

(7)下載完后舊的XML是否換成新的XML;

(8)運行主程序的電腦或者服務端沒有網絡的情況;

版權聲明:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/hulinhulin/article/details/46839107

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/458286.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/458286.shtml
英文地址,請注明出處:http://en.pswp.cn/news/458286.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

java 基本功 —— 內存相關

2019獨角獸企業重金招聘Python工程師標準>>> 首先我們來說說內存&#xff0c;因為從內存的角度來出發來分析一些變量&#xff0c;引用或者對象的生命周期會更好理解一些。 java是一門編程語言&#xff0c;他跟C有什么不同呢&#xff1f;本質上&#xff0c;他們都是一…

DOM事件處理有三個階段

DOM事件處理有三個階段&#xff1a; 捕捉階段&#xff08;capture phase&#xff09;&#xff1a;從最上層元素&#xff0c;直到最下層&#xff08;你點擊的那個target&#xff09;元素。路過的所有節點都可以捕捉到該事件。命中階段&#xff08;target phase&#xff09;&…

客戶端程序自動更新(升級)的方式

from&#xff1a;https://blog.csdn.net/woaitingting1985/article/details/72954652一、C/S自動更新原理C/S程序自動升級是一個很重要的功能&#xff0c;原理其實很簡單&#xff0c;一般包含兩個程序一個是主程序&#xff0c;也就是除了升級功能以外的程序&#xff0c;另一個就…

怎么用源程序把ChemDraw結構復制到Word文檔

在學習化學過程中&#xff0c;不可避免的會接觸到各種化學結構。這個時候就需要通過繪制化學結構來進行這方面的學習和傳播。ChemDraw Professional 15就可以輔助完成這方面的工作。很多的用戶朋友會通過選中后復制粘貼可以將ChemDraw結構復制到Word文檔中&#xff0c;但這只是…

網絡流(最大流) HDU 1565 方格取數(1) HDU 1569 方格取數(2)

HDU 1565 方格取數(1)給你一個n*n的格子的棋盤&#xff0c;每個格子里面有一個非負數。從中取出若干個數&#xff0c;使得任意的兩個數所在的格子沒有公共邊&#xff0c;就是說所取的數所在的2個格子不能相鄰&#xff0c;并且取出的數的和最大。 Input 包括多個測試實例&#…

python學習 第一篇 基礎

上周報名了reboot python 課程&#xff0c;終于下決心要把python 搞好了&#xff0c;希望自己能堅持下來&#xff0c;并得到自己想要的成績#coding:utf-8 #呵呵 #print hello world #xhello world #print x #xraw_input(hello world) #print x #int #print 23 #print 12*3 #pri…

QT串口編程的相關類(QSerialPortInfo)

QT Serial Port相關的類只有兩個QSerialPortInfo(#include<QSerialPortInfo>) 和QserialPort(#include<QSerialPort>) 先來介紹QSerialPortInfo 1&#xff1a;QSerialPortInfo(#include<QSerialPortInfo>) 該類是一個串口的輔助類類&#xff0c;提供主要是提…

用jquery寫一個屬于自己的音樂播放器

看到一個用css3實現的CD的動畫&#xff0c;演示在這兒http://codepen.io/_kieran/pen/QNRmep 突然那我就想說給自己做一個音樂播放器吧&#xff0c;說做就做。演示在https://echolsx.github.io/music/ Github傳送門&#xff1a;https://github.com/EchoLsx/music 主要代碼&…

四年一閏 隨筆

今天日子比較特殊&#xff0c;碰到閏年的2月29日。好久沒有記錄隨筆了&#xff0c;今天隨便記上幾筆吧 1、上家公司居然沒幫我交社保&#xff0c;一整年了&#xff0c;發工資時還照扣社保的錢。。。現在說會補差額給我&#xff0c;算下來一年XXXX&#xff0c;也只是個數字&…

Qt 串口類QSerialPort 使用筆記

Qt 串口類QSerialPort 使用筆記雖然現在大多數的家用PC機上已經不提供RS232接口了。但是由于RS232串口操作簡單、通訊可靠&#xff0c;在工業領域中仍然有大量的應用。Qt以前的版本中&#xff0c;沒有提供官方的對RS232串口的支持&#xff0c;編寫串口程序很不方便。現在好了&a…

什么是H標簽?H1,H2,H3標簽?以及和strong標簽使用的方法及重要性

大家都知道&#xff0c;seo的一個很重要的一點就是要把網站做的條理清晰&#xff0c;讓搜索引擎很容易的讀明白&#xff0c;這個條理清晰不僅體現在網站的物理路徑&#xff0c;url等地 方。在<h1><h2><h3>等方面也是這樣。并不是<h1>對于關鍵字排名有幫…

OC語言中的便利初始化函數和便利構造器

便利遍歷初始化函數與便利構造器&#xff08;以Student類為例&#xff09;&#xff1b; main函數 Student.h&#xff08;聲明&#xff09; 。。。。。。。。。。。。。。。。。。。 Student.m&#xff08;實現&#xff09; 。。。。。。。。。。。。。。。。。 轉載于:https://…

MySQL 性能監控 4 大指標

【編者按】本文作者為 John Matson&#xff0c;主要介紹 mysql 性能監控應該關注的 4 大指標。 文章系國內 ITOM 管理平臺 OneAPM 編譯呈現。 MySQL 是什么&#xff1f; MySQL 是現而今最流行的開源關系型數據庫服務器。由 Oracle 所有&#xff0c;MySQL 提供了可以免費下載的社…

【深度相機系列四】深度相機原理揭秘--結構光(iPhone X 齊劉海原理)

from&#xff1a;https://blog.csdn.net/electech6/article/details/78707839導讀 結構光法&#xff1a;為解決雙目匹配問題而生 深度圖效果&#xff1a;結構光vs.雙目 投射圖案的編碼方式直接編碼時分復用編碼空分復用編碼 Kinect1原理 iPhone X原深感相機是縮小版的更強大的K…

iOS開發中對于一些常用的相對路徑(持續更新)

1.iOS開發的證書的描述文件放置地點 ~/Library/MobileDevice/Provisioning Profiles 2.$(SRCROOT)代表的是這個項目文件夾所在的位置 $(PROJECT_DIR) 表示的包含可執行文件的哪一個文件夾 3.對于pod導入的第三方庫&#xff0c;引用不自動補全問題。選擇target -> BuildSet…

Android倒計時工具類

為什么80%的碼農都做不了架構師&#xff1f;>>> 原文地址:http://my.oschina.net/reone/blog/710003 多謝touch_ping 的回應. 原來api有這個類 android.os.CountDownTimer , 具體實現很下面的差不多. import android.content.Context; import android.os.Handler…

深度相機原理揭秘--雙目立體視覺

歡迎關注計算機視覺life&#xff01;導讀 為什么非得用雙目相機才能得到深度&#xff1f; 雙目立體視覺深度相機的工作流程 雙目立體視覺深度相機詳細工作原理理想雙目相機成像模型極線約束圖像矯正技術基于滑動窗口的圖像匹配基于能量優化的圖像匹配 雙目立體視覺深度相機的優…

微信掃碼支付模式一和模式二的區別

http://www.baidu.com/link?urlAj_xhOM5Q6rpZXkTMBPq4o0UbCO4eLq0esX8B3K2v06bkRS8F8lC4k06rv-3uZARLLTEKJHMhwzI_cdcJiHfqK&wd&eqid904bc71f000181740000000356d7d9bf https://www.zhihu.com/question/35818812/answer/66086727 知乎頁面訪問存在502 Bad Gateway問題…

雙目視覺幾何框架詳解(玉米專欄8篇匯總)

一、圖像坐標&#xff1a;我想和世界坐標談談(A) 玉米竭力用輕松具體的描述來講述雙目三維重建中的一些數學問題。希望這樣的方式讓大家以一個輕松的心態閱讀玉米的《計算機視覺學習筆記》雙目視覺數學架構系列博客。這個系列博客旨在捋順一下已標定的雙目視覺中的數學主線。數…

(原)Ubuntu14中安裝GraphicsMagick

轉載請注明出處&#xff1a; http://www.cnblogs.com/darkknightzh/p/5661439.html 參考網址&#xff1a; http://comments.gmane.org/gmane.comp.video.graphicsmagick.core/514 http://www.graphicsmagick.org/INSTALL-unix.html https://github.com/clementfarabet/graphics…