程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 掃雷外掛的設計與實現(四)

掃雷外掛的設計與實現(四)

編輯:Delphi
 不得不說,捕獲“掃雷”窗口以及取得它的數據,是本程序的一個難點。現在這個難點已經解決,接下來,完成接口層已經不是問題了。那麼,來看接口層的兩個核心過程:

  =================================================================

  //取得整個雷區每個方塊的狀態,填入Cells中供分析。
  procedure FetchCells;
  var
    i, j: Integer;
  begin
    //掃描每個方塊,根據指定像素的顏色判斷該方塊的性質。
    //特定像素的顏色與方塊性質的對應關系歸納自“掃雷”程序本身的資源。
    for i:=0 to AreaWidth-1 do
    for j:=0 to AreaHeight-1 do
      //首先判斷(0, 0)點的像素
      case TColor(GetPixel(MineDC, LEFT_MARGIN + i*CELL_WIDTH, TOP_MARGIN + j*CELL_HEIGHT)) of
        clWhite:
          //是未挖開的方塊,再判斷(5, 4)點的像素
          case TColor(GetPixel(MineDC, LEFT_MARGIN + i*CELL_WIDTH + 5, TOP_MARGIN + j*CELL_HEIGHT + 4)) of
            clSilver: Cells[i, j] := csUnknown;     //未翻開的方塊
            clRed: Cells[i, j] := csMarked;           //已標記為雷的方塊
            clBlack: Cells[i, j] := csPossible;      //標問號的方塊
          end;
        clGray:
          //是已挖開的方塊,再判斷(7, 4)點的像素
          case TColor(GetPixel(MineDC, LEFT_MARGIN + i*CELL_WIDTH + 7, TOP_MARGIN + j*CELL_HEIGHT + 4)) of
            clSilver: Cells[i, j] := cs0;    //空白,相當於數字0
            clBlue: Cells[i, j] := cs1;      //數字1
            clGreen: Cells[i, j] := cs2;     //數字2
            clRed: Cells[i, j] := cs3;       //數字3
            clNavy: Cells[i, j] := cs4;      //數字4
            clMaroon: Cells[i, j] := cs5;    //數字5
            clTeal: Cells[i, j] := cs6;      //數字6
            clBlack: Cells[i, j] := cs7;     //數字7
            clGray: Cells[i, j] := cs8;      //數字8
          end;
      end;
  end;

  =================================================================

  以上程序中,三個包含 case...of 的行,都用到了前面實測到的數據。執行完之後,掃雷窗口所有方塊的狀態就原原本本地在輸入緩沖區裡了。

  =================================================================

  //將Operations中所記載的對每個方塊的操作真正作用於掃雷窗口。
  procedure OperateCells;
  var
    i, j: Integer;
    downMsg, upMsg: Cardinal;     //按下和抬起鼠標按鈕時分別發送的消息
    wparam, lparam: Integer;      //消息參數
    clickCount: Integer;          //按鍵次數,只有取值1或2
  begin
    //掃描每個方塊
    for i:=0 to AreaWidth-1 do
    for j:=0 to AreaHeight-1 do
    begin
      if Operations[i, j] = opNone then
        Continue;
      //根據操作種類,設定發送的消息及其參數
      lparam := ((TOP_MARGIN + j*CELL_HEIGHT) shl 16) + (LEFT_MARGIN + i*CELL_WIDTH);
      wparam := IfThen(Operations[i, j] = opBothClick, MK_RBUTTON, 0);
      downMsg := IfThen(Operations[i, j] in [opRightClick, opRightDoubleClick], WM_RBUTTONDOWN, WM_LBUTTONDOWN);
      upMsg := IfThen(Operations[i, j] in [opRightClick, opRightDoubleClick], WM_RBUTTONUP, WM_LBUTTONUP);
      //設定發送消息次數,即單擊還是雙擊
      clickCount := IfThen(Operations[i, j] = opRightDoubleClick, 2, 1);
      //發送消息
      repeat
        PostMessage(MineWnd, downMsg, wparam, lparam);
        PostMessage(MineWnd, upMsg, wparam, lparam);
        Dec(clickCount);
      until clickCount = 0;
    end;
  end;

  =================================================================

  這裡需要說的是WM_LBUTTONDOWN、WM_LBUTTONUP、WM_RBUTTONDOWN和WM_RBUTTONUP四個消息。它們是在一個窗口客戶區內按下或抬起鼠標左或右按鈕時,發給這個窗口的消息。所以,手動地發送這些消息,其實就是模擬鼠標的點擊。發送消息用到了WinAPI函數PostMessage,它和大家所熟悉的SendMessage函數的參數是相同的,作用也幾乎相同,主要區別是不等待消息的返回,詳見MSDN。上述四個消息的WParam和LParam都具有同樣的意義:WParam用來指定按下該鍵的時候,還有哪些其它特定的鍵(其它鼠標鍵,或Ctrl,Shift等)被按下。0表示沒有其它鍵被按下,在這裡還用到了值MK_RBUTTON,即按下左鍵時指定右鍵同時也被按下,用來模擬同時按下左右鍵的情況。當然,發送RBUTTONDOWN和RBUTTONUP時指定MK_LBUTTON也是同樣的效果。而LParam則指定了按下或抬起鍵時鼠標指針的坐標,它的高16位為Y坐標,低16位為X坐標。給lparam賦值的那一行,就是把X,Y兩個值組裝成了一個lparam。

  另外提一下IfThen函數,這個函數平時並不見有多人使用,但它真的很方便,至少它解決了對於“Delphi中沒有C的 ? : 運算符”的抱怨^_^。不錯,這就是Delphi的問號運算符,三個參數中第一個是Boolean型,若為真,返回值就是第二個參數,否則是第三個參數。第二、第三個參數類型相同,並且有多個重載版本。數值版本需要包含Math庫,而字符串版本需要StrUtils庫。顯然,編譯上述代碼是需要包含Math庫的。若不願,當然你也可以使用 if...then。

  至此,接口層全部實現完畢,接下來就可以安心的實現“數學模型”了。

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