程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 如何定制一款12306搶票浏覽器——用戶界面

如何定制一款12306搶票浏覽器——用戶界面

編輯:C++入門知識

界面如下            我觀察了下12306的頁面,它預留了5個乘客信息,所以我也就預留了5個乘客信息。因為我不會寫HTML和javascript,我就從12306中copy出相應的頁面元素,並加以修改。在此感謝下12306網頁設計同學,幫我完成了不少我不會的東西。           一般來說,我們可能一次性不會購買5個人的票。所以在上面的界面中,你想填多少人信息就填多少人信息,我會在代碼中讀取這些人的信息。當我們填完乘客信息後,我們要輸入車次信息。然後我們要點擊一下確定,我會在代碼中捕獲點擊確定的操作,並將已經填寫的信息讀入內存。在之後的搶票過程中,我們將使用到這些信息。最後,我們就要點擊最下面那個超鏈接,跳轉到12306這個頁面,開始我們真正的搶票工作。           我們來看一下源代碼。首先是界面的,我列一個人的信息代碼出來:   [cpp]   <tr class="passenger_class" id="passenger_1">       <td style="width: 6%">           <div id="passenger_1_index">第1位</div>       </td>       <td id="seat">           <select>               <option value="1">硬座</option>               <option value="2">軟座</option>               <option value="3">硬臥</option>               <option value="4">軟臥</option>               <option value="6">高級軟臥</option>               <option value="M">一等座</option>               <option value="O">二等座</option>               <option value="P">特等座</option>               <option value="9">商務座</option>           </select>        </td>       <td style="width: 20%">           <label><strong>請確認所選車次有該坐席</strong> </label>       </td>       <td id="ticket">           <select>               <option value="1">成人票</option>               <option value="2">兒童票</option>               <option value="3">學生票</option>               <option value="4">殘軍票</option>           </select>       </td>       <td id="name">           <input name="passenger_1_name" type="text" id="passenger_1_name" size="12" maxlength="20" class="input_20txt" value=""/>       </td>       <td id="cardtype">           <select>               <option value="1">二代身份證</option>               <option value="2">一代身份證</option>               <option value="C">港澳通行證</option>               <option value="G">台灣通行證</option>               <option value="B">護照</option>           </select>       </td>       <td id="cardno">           <input name="passenger_1_cardno" type="text" id="passenger_1_cardno" size="20" maxlength="35" style="text-transform: uppercase;" class="input_20txt" value=""/>       </td>       <td id="mobileno">           <input name="passenger_1_mobileno" type="text" id="passenger_1_mobileno" size="11" maxlength="20" class="input_20txt" value=""/>       </td>   </tr>           因為我並不知道用戶選擇的車次有什麼類型的座位,所以我將所有的座位都列了出來。   [cpp]   <select>       <option value="1">硬座</option>       <option value="2">軟座</option>       <option value="3">硬臥</option>       <option value="4">軟臥</option>       <option value="6">高級軟臥</option>       <option value="M">一等座</option>       <option value="O">二等座</option>       <option value="P">特等座</option>       <option value="9">商務座</option>   </select>            這兒要特別注意下所有option的value字段,這些值不是我亂取的。而是我檢查了12306頁面的很多火車信息後收集到的。我們會在之後記錄用戶所選席別時,記錄這些值,因為這些值將在操作12306頁面時派上用場。           其他元素應該沒什麼可以解釋的,只是要注意所有Select下的Option的Value值和12306上對應的元素的Value值一致。           我們保存單個用戶的結構體是   [cpp]   struct StSinglePassengerInfo{       ListCString ListSeat;       CString cstrTicket;       CString cstrName;       CString cstrCardtype;       CString cstrCardNo;       CString cstrMobileNo;   };           注意一下ListSeat這個字段,這個字段保存的一個CString的隊列。它記錄著一系列席別代碼。在我最開始設計這個軟件時,我是希望用戶可以選擇一系列可以接受的席別,同時是按優先級關系排列。這樣可以最大程度上滿足用戶的需求。但是我已無心把這個功能繼續做下去,所以設計界面時,只能讓用戶選擇一個席別。         還有一個需要我們關注的是“確定”超鏈接的代碼   [html]   <td>       <a style="width: 60px;" href="http://settingok">確定</a>   </td>           我們點擊“確定”按鈕後,頁面理論上要跳轉到“http://settingok”這個頁面。而實際上,我們只是利用“跳轉”這個操作,讓我們的C++代碼中捕獲到用戶已經設置OK了。我們並不希望頁面真的發生跳轉。所以我們對BeforeNavigate2消息映射函數做了處理,讓跳轉到“http://settingok”的請求終止,並讀取用戶設置的乘客信息和車次信息。 [cpp]   void CBrowserHost::BeforeNavigate2(IDispatch *pDisp, VARIANT *url,           VARIANT *Flags, VARIANT *TargetFrameName, VARIANT *PostData,           VARIANT *Headers, VARIANT_BOOL *Cancel)   {       do  {           if ( NULL != url ) {               CString cstrUrl((LPWSTR)(url->bstrVal));               if ( 0 == cstrUrl.CompareNoCase(SETTINGOK) ) {                   *Cancel = VARIANT_TRUE;                   CComPtr<IWebBrowser2> spWeb;                   HRESULT hr = pDisp->QueryInterface(IID_IWebBrowser2, (LPVOID*)&spWeb);                   CHECKHRPOINTER(hr, spWeb);                      CComPtr<IDispatch> dispDoc;                   hr = spWeb->get_Document(&dispDoc);                   CHECKHRPOINTER(hr, dispDoc);                      CComPtr<IHTMLDocument2> spDoc;               hr = dispDoc->QueryInterface( IID_IHTMLDocument2, (LPVOID*)&spDoc);                   CHECKHRPOINTER(hr, spDoc);                      StTrainNoPassengerInfo stTrainPassenger;                      hr = m_dealSettingPage.GetTrainNoPassengersInSettingPage(spDoc, stTrainPassenger);                      hr = m_AutoMan.SetTrainNoPassengers(stTrainPassenger);               }               ……           }           ……       } while (0);   }           上面代碼中m_dealSettingPage是我處理頁面的類CDeal12306WebPage的對象。GetTrainNoPassengersInSettingPage將解析網頁保存乘客和車次信息。m_AutoMan是我們之前說的“人”線程,此時我們將告訴該線程所有信息,讓它准備開始工作。   [cpp]   HRESULT CDeal12306WebPage::GetTrainNoPassengersInSettingPage( CComPtr<IHTMLDocument2> & spDoc,       StTrainNoPassengerInfo & stTrainPassenger )   {       HRESULT hr = E_FAIL;       do {           CComPtr<IHTMLElement> spBody;           hr = spDoc->get_body(&spBody);           CHECKHRPOINTER(hr, spBody);              CComPtr<IHTMLElement> spTable;           hr = GetElementByID(spBody, L"passengertable", spTable);           CHECKHRPOINTER(hr, spTable);              CComPtr<IHTMLElement> spTBody;           hr = GetElementByIndex( spTable, 0, spTBody);           CHECKHRPOINTER(hr, spTBody);              for ( int i = 0; i < MAXPASSENGERCOUNT; i++ ) {               CString cstrTrID;               cstrTrID.Format(PASSENGERID, i + 1);               CComPtr<IHTMLElement> spTr;               hr = GetElementByID( spTBody, cstrTrID, spTr);               CHECKHRPOINTER(hr, spTr);               StSinglePassengerInfo stSinglePassenger;               hr = GetPassengerInfo(spTr, stSinglePassenger);               CHECKHR(hr);                  if ( FALSE == stSinglePassenger.cstrName.IsEmpty() &&                   FALSE == stSinglePassenger.cstrTicket.IsEmpty() &&                   FALSE == stSinglePassenger.cstrCardNo.IsEmpty() &&                   FALSE == stSinglePassenger.cstrCardtype.IsEmpty() &&                   FALSE == stSinglePassenger.cstrMobileNo.IsEmpty() &&                   0 != stSinglePassenger.ListSeat.size()) {                   stTrainPassenger.vecPassengerInfo.push_back(stSinglePassenger);               }           }              hr = GetTrainNoInSettingPage(spDoc, stTrainPassenger.cstrTrainNo);       } while (0);       return hr;   }           這段代碼大致意思是在“設置”頁面中,找到id為passengertable的元素spTable,然後找到spTable下第一個元素spTBody。spTBody下保存著每個乘客的信息,其中第一個乘客信息保存在id是“passenger_1”的元素下,第二個保存在“passenger_2”元素下……當單個乘客所有信息都不為空時,將其保存在一個stTrainPassenger.vecPassengerInfo中。最後我們要獲取火車車次的信息,將其保存在stTrainPassenger.cstrTrainNo中。         上面的函數大部分是經過封裝的。其中幾個經常用的函數是 [cpp]   HRESULT GetElementCollection(CComPtr<ihtmlelement> & spElem,       CComPtr<ihtmlelementcollection> & spElemCollection );      enum EQUERYTYPE {       EID,       ETAGNAME,       ECLASSNAME,   };          // 通過ID獲取指定節點下第一個ID為cstrID的子節點   HRESULT GetElementByID(CComPtr<IHTMLElement> & spElem,        const CString & cstrID,       CComPtr<IHTMLElement> & spResElem);   // 通過ClassName獲取指定節點下第一個class為cstrClassName的子節點   HRESULT GetElementByClassName(CComPtr<IHTMLElement> & spElem,        const CString & cstrClassName,       CComPtr<IHTMLElement> & spResElem);   // 通過TagName獲取指定節點下第一個tag為cstrTagName的子節點   HRESULT GetElementByTagsName(CComPtr<IHTMLElement> & spElem,        const CString & cstrTagName,       CComPtr<IHTMLElement> & spResElem);   // 通過ID獲取指定節點下第lindex子節點   HRESULT GetElementByIndex(CComPtr<IHTMLElement> & spElem,        LONG lIndex,       CComPtr<IHTMLElement> & spResElem);   HRESULT GetElement(CComPtr<ihtmlelement> & spElem,        EQUERYTYPE eType, const CString & cstrValue,       CComPtr<ihtmlelement> & spResElem);</ihtmlelement></ihtmlelement></ihtmlelementcollection></ihtmlelement>           對應的實現代碼是   [cpp]   HRESULT CDeal12306WebPage::GetElementCollection( CComPtr<IHTMLElement> & spElem, CComPtr<IHTMLElementCollection> & spElemCollection )   {       HRESULT hr = S_FALSE;       do {           CComPtr<IDispatch> spDispatch;           hr = spElem->get_children(&spDispatch);           CHECKHR(hr);           hr = spDispatch->QueryInterface( IID_IHTMLElementCollection, (LPVOID*)&spElemCollection);           CHECKHR(hr);       } while (0);       return hr;   }      HRESULT CDeal12306WebPage::GetElementByID( CComPtr<IHTMLElement> & spElem,        const CString & cstrID, CComPtr<IHTMLElement> & spResElem )   {       return GetElement( spElem, EID, cstrID, spResElem );   }      HRESULT CDeal12306WebPage::GetElementByClassName( CComPtr<IHTMLElement> & spElem,        const CString & cstrClassName, CComPtr<IHTMLElement> & spResElem )   {       return GetElement( spElem, ECLASSNAME, cstrClassName, spResElem );   }      HRESULT CDeal12306WebPage::GetElementByTagsName( CComPtr<IHTMLElement> & spElem,        const CString & cstrTagName, CComPtr<IHTMLElement> & spResElem )   {       return GetElement( spElem, ETAGNAME, cstrTagName, spResElem );   }      HRESULT CDeal12306WebPage::GetElementByIndex( CComPtr<IHTMLElement> & spElem,        LONG lIndex, CComPtr<IHTMLElement> & spResElem )   {       HRESULT hr = E_FAIL;       do {           CComPtr<IHTMLElementCollection> spElemCollecion;           hr = GetElementCollection( spElem, spElemCollecion);           CHECKHR(hr);                      LONG lCollecionCount = 0;           hr = spElemCollecion->get_length(&lCollecionCount);           CHECKHR(hr);                      if ( lCollecionCount < lIndex + 1) {               break;           }           CComVariant VarIndex = lIndex;           CComPtr<IDispatch> spDisp;           hr = spElemCollecion->item(VarIndex, VarIndex, &spDisp);           CHECKHRPOINTER(hr,spDisp);              hr = spDisp->QueryInterface(IID_IHTMLElement, (LPVOID*)&spResElem);       } while (0);       return hr;   }      HRESULT CDeal12306WebPage::GetElement(        CComPtr<IHTMLElement> & spElem,        EQUERYTYPE eType, const CString & cstrValue,        CComPtr<IHTMLElement> & spResElem )   {       HRESULT hr = E_FAIL;       do {           CComPtr<IHTMLElementCollection> spElemCollection;           hr = GetElementCollection( spElem, spElemCollection);           CHECKHRPOINTER(hr,spElemCollection);              LONG lCollecionCount = 0;           hr = spElemCollection->get_length(&lCollecionCount);           CHECKHR(hr);              for ( long i = 0; i < lCollecionCount; i++ ) {               CComVariant VarIndex = i;               CComPtr<IDispatch> spDispatchElem;               hr = spElemCollection->item( VarIndex, VarIndex, &spDispatchElem );               CHECKHRPOINTER(hr,spDispatchElem);                  CComPtr<IHTMLElement> spElem;               hr = spDispatchElem->QueryInterface(IID_IHTMLElement, (LPVOID*)& spElem );               CHECKHRPOINTER(hr, spElem);                  CComBSTR bstrValue;               switch (eType) {               case EID: {                       hr = spElem->get_id(&bstrValue);                   }break;               case ETAGNAME: {                       hr = spElem->get_tagName(&bstrValue);                   }break;               case ECLASSNAME: {                       hr = spElem->get_className(&bstrValue);                   }break;               default:                   break;               }                  CString cstrV((LPWSTR)bstrValue);               if ( 0 == cstrV.CompareNoCase( cstrValue )) {                   spResElem = spElem;                   break;               }           }       } while (0);       return hr;   }           在獲取乘客和車次信息時用到的其他封裝函數的實現是   [cpp]   HRESULT CDeal12306WebPage::GetPassengerInfo( CComPtr<IHTMLElement> & spElem,        StSinglePassengerInfo & stSinglePassenger )   {       HRESULT hr = E_FAIL;       do {           CString cstrSeat;           hr = GetOptionValueHelper(spElem, L"seat", cstrSeat);           CHECKHR(hr);           stSinglePassenger.ListSeat.push_back(cstrSeat);              hr = GetOptionValueHelper(spElem, L"ticket", stSinglePassenger.cstrTicket );           CHECKHR(hr);              hr = GetOptionValueHelper(spElem, L"cardtype", stSinglePassenger.cstrCardtype);           CHECKHR(hr);              hr = GetInputValueHelper(spElem, L"name", stSinglePassenger.cstrName);           CHECKHR(hr);              hr = GetInputValueHelper(spElem, L"cardno", stSinglePassenger.cstrCardNo);           CHECKHR(hr);              hr = GetInputValueHelper(spElem, L"mobileno", stSinglePassenger.cstrMobileNo);       } while (0);       return hr;   }      HRESULT CDeal12306WebPage::GetOptionValueHelper( CComPtr<IHTMLElement> & spElem,        const CString& cstrID, CString& cstrValue )   {       HRESULT hr = E_FAIL;       do {           CComPtr<IHTMLElement> spTd;           hr = GetElementByID(spElem, cstrID, spTd);           CHECKHRPOINTER(hr, spTd);              CComPtr<IHTMLElement> spSel;           hr = GetElementByIndex(spTd, 0, spSel);           CHECKHRPOINTER(hr, spSel);              CComPtr<IHTMLSelectElement> spSelect;           hr = spSel->QueryInterface(IID_IHTMLSelectElement, (LPVOID*)&spSelect);           CHECKHRPOINTER(hr, spSelect);              CComBSTR bstrValue;           hr = spSelect->get_value(&bstrValue);           CHECKHR(hr);                  cstrValue = bstrValue;       } while (0);       return hr;   }      HRESULT CDeal12306WebPage::GetInputValueHelper( CComPtr<IHTMLElement> & spElem,       const CString& cstrID, CString & cstrValue )   {       HRESULT hr = E_FAIL;       do {           CComPtr<IHTMLElement> spTd;           hr = GetElementByID(spElem, cstrID, spTd);           CHECKHRPOINTER(hr, spTd);              CComPtr<IHTMLElement> spInput;           hr = GetElementByIndex(spTd, 0, spInput);           CHECKHRPOINTER(hr, spInput);              CComPtr<IHTMLInputElement> spInputElem;           hr = spInput->QueryInterface(IID_IHTMLInputElement, (LPVOID*)&spInputElem);           CHECKHRPOINTER(hr, spInputElem);              CComBSTR bstrValue;           hr = spInputElem->get_value(&bstrValue);           CHECKHR(hr);              cstrValue = bstrValue;       } while (0);       return hr;   }      HRESULT CDeal12306WebPage::GetTrainNoInSettingPage( CComPtr<IHTMLDocument2> & spDoc,        CString & cstrValue )   {       HRESULT hr = E_FAIL;       do {           CComPtr<IHTMLElement> spBody;           hr = spDoc->get_body(&spBody);           CHECKHRPOINTER(hr, spBody);              CComPtr<IHTMLElement> spTable;           hr = GetElementByID(spBody, L"trainnotable", spTable);           CHECKHRPOINTER(hr, spTable);              CComPtr<IHTMLElement> spTBody;           hr = GetElementByIndex( spTable, 0, spTBody);           CHECKHRPOINTER(hr, spTBody);              CComPtr<IHTMLElement> spTr;           hr = GetElementByIndex(spTBody, 0, spTr);           CHECKHRPOINTER(hr, spTr);              CComPtr<IHTMLElement> spTd;           hr = GetElementByID(spTr, L"trainno", spTd);           CHECKHRPOINTER(hr, spTd);              CComPtr<IHTMLElement> spInput;           hr = GetElementByIndex(spTd, 0, spInput);           CHECKHRPOINTER(hr, spInput);              CComPtr<IHTMLInputElement> spInputElem;           hr = spInput->QueryInterface(IID_IHTMLInputElement, (LPVOID*)&spInputElem);           CHECKHRPOINTER(hr, spInputElem);              CComBSTR bstrValue;           hr = spInputElem->get_value(&bstrValue);           CHECKHR(hr);                      cstrValue = bstrValue;       } while (0);       return hr;  

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved