cppquery:C++でjqueryの探索を模倣する

12697 ワード

cppqueryを取得するには:https://github.com/coderebot/cppquery
CPPQueryって何?
CPPQueryはjqueryに倣い、その名の通りc++queryである.Windows API向けのGUIで、jqueryのようなインタフェースを提供しています.目的は:GUIのプログラミングを簡略化し、最終的な目的はより簡潔でスマートなMVCアーキテクチャを構築することである.主な目標は次のとおりです.
  • GUIに分散されたコードを集中的に処理し、特に各種イベント処理コードを処理する.
  • は、データとコントロール間のインテリジェントな連動を実現するデータバインドフレームワークを提供する.
  • はデータソースフレームワークを提供し、容器類データの自動充填、データ変化の連動を実現する.
  • はCSSのようなインタフェーススタイルの制御フレームワークを提供し、インタフェースの表示と制御を分離する.

  • cppqueryはc++のテンプレートを主な手段とし,テンプレートシミュレーションにより閉パケットと匿名関数をシミュレートし,jqueryのような使用方法を達成することが望ましい.
    cppqueryのほとんどのコードはテンプレートとして表示されるため、cppqueryは非常にコンパクトで軽量なGUIパッケージライブラリです.cppqueryの初期には、View-Documentアーキテクチャなどのcover MFCの大部分の特性が考慮される.後で、きらびやかなインタフェースを作成できるグラフィックライブラリが提供されます.
    なぜCPPQueryを作るのですか?
    現在のWindows GUIには、MFC、UIPowerなど、成熟したライブラリがたくさんあります.しかし、これらのライブラリには似たようなアーキテクチャがあり、一般的にはウィンドウをクラスにカプセル化し、インタフェースを作成するには、対応するクラスを作成する必要があります.多くのコントロールは、このクラスに対応しています. 
    C++の継承プロパティが使用されていますが、クラスごとにインタフェースが異なり、タスクを完了するには、多くのクラスとインタフェースを覚えておく必要があります.
    近年、HTML 5の発展とjqueryの勃興に伴い、オブジェクト向けではなく断面向けの新しいインタフェース開発フレームワークが登場している.例えば、jqueryはCSS選択子によって、HTML DOM構造を知る必要がない場合に、所望のノードを得ることができ、イベント処理ハンドルを追加し、ページの表示状態を変更することができる.この方法はより徹底的に分離され,コードの結合がより低く,使用がより簡単である.さらに重要なのは、非同期モードを採用する場所が多く、インタフェースの反応速度とユーザー体験を大幅に向上させることです.
    そのため、私はcppqueryをして、このような思想をNativeのインタフェースの開発に導入することを望んでいます.
    Windowsプラットフォームを選んだのは、主にwindowsプラットフォームのユーザーが多く、開発者も多いからです.私自身もwindows開発に詳しいです.Windowsプラットフォームはより成熟しており、多層実装の問題を考慮しすぎず、上層のアーキテクチャに専念する必要はありません.
    Windowsで成功した後、androidなどの他のプラットフォームに普及することができます(実際にandroidプラットフォームにはaqueryがあります).
    スタート
    現在CPPQueryは最も簡単な機能しか実現していない.
    私はVSを使用してWin 32プロジェクトを生成し、簡単なウィンドウが1つしかなく、メニューが1つあり、「Exit」と「About」の2つのメニュー項目しかありません.これはVS自動生成のコードで、私はこのコードを修正し、機能は変わらないが、実現方法はcppqueryを使用します.
    まずコードの一覧をあげます.
    // cppquery.cpp : Defines the entry point for the application.
    //
    
    #include "stdafx.h"
    #include "cppquerytest.h"
    #include "api/cppquery.h"
    using namespace cppquery;
    
    #define MAX_LOADSTRING 100
    
    // Global Variables:
    HINSTANCE hInst;								// current instance
    TCHAR szTitle[MAX_LOADSTRING];					// The title bar text
    TCHAR szWindowClass[MAX_LOADSTRING];			// the main window class name
    HWND g_hMainWnd;
    
    // Forward declarations of functions included in this code module:
    ATOM				MyRegisterClass(HINSTANCE hInstance);
    BOOL				InitInstance(HINSTANCE, int);
    
    int APIENTRY _tWinMain(HINSTANCE hInstance,
                         HINSTANCE hPrevInstance,
                         LPTSTR    lpCmdLine,
                         int       nCmdShow)
    {
    	UNREFERENCED_PARAMETER(hPrevInstance);
    	UNREFERENCED_PARAMETER(lpCmdLine);
    
     	// TODO: Place code here.
    	MSG msg;
    	HACCEL hAccelTable;
    
    	// Initialize global strings
    	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    	LoadString(hInstance, IDC_CPPQUERY, szWindowClass, MAX_LOADSTRING);
    	MyRegisterClass(hInstance);
    
    	// Perform application initialization:
    	if (!InitInstance (hInstance, nCmdShow))
    	{
    		return FALSE;
    	}
    
    	hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CPPQUERY));
    
    
    	// Main message loop:
    	while (GetMessage(&msg, NULL, 0, 0))
    	{
    		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
    		{
    			TranslateMessage(&msg);
    			DispatchMessage(&msg);
    		}
    	}
    
    	return (int) msg.wParam;
    }
    
    
    
    //
    //  FUNCTION: MyRegisterClass()
    //
    //  PURPOSE: Registers the window class.
    //
    //  COMMENTS:
    //
    //    This function and its usage are only necessary if you want this code
    //    to be compatible with Win32 systems prior to the 'RegisterClassEx'
    //    function that was added to Windows 95. It is important to call this function
    //    so that the application will get 'well formed' small icons associated
    //    with it.
    //
    ATOM MyRegisterClass(HINSTANCE hInstance)
    {
    	WNDCLASSEX wcex;
    
    	wcex.cbSize = sizeof(WNDCLASSEX);
    
    	wcex.style			= CS_HREDRAW | CS_VREDRAW;
    	wcex.lpfnWndProc	= DefWindowProc;
    	wcex.cbClsExtra		= 0;
    	wcex.cbWndExtra		= 0;
    	wcex.hInstance		= hInstance;
    	wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CPPQUERY));
    	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
    	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
    	wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_CPPQUERY);
    	wcex.lpszClassName	= szWindowClass;
    	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
    
    	return RegisterClassEx(&wcex);
    }
    
    //
    //   FUNCTION: InitInstance(HINSTANCE, int)
    //
    //   PURPOSE: Saves instance handle and creates main window
    //
    //   COMMENTS:
    //
    //        In this function, we save the instance handle in a global variable and
    //        create and display the main program window.
    //
    
    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
    {
       HWND hWnd;
    
       hInst = hInstance; // Store instance handle in our global variable
    
       hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
          CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
    
       if (!hWnd)
       {
          return FALSE;
       }
    
       ShowWindow(hWnd, nCmdShow);
       UpdateWindow(hWnd);
    
       static WindowFrontPeer::MessageHandle about_handles[] = {
            WindowFrontPeer::Command(IDOK, MK_FUNC(FUNC(EndDialog), _1, 0)),
            WindowFrontPeer::Command(IDCANCEL, MK_FUNC(FUNC(EndDialog), _1, 0)),
            NULL,
       };
       
        Window window(hWnd);
        window.onCommand(IDM_EXIT, MK_FUNC(FUNC(DestroyWindow), hWnd))
              .onDestroy(MK_FUNC(FUNC(PostQuitMessage), 0))
              .onCommand(IDM_ABOUT, MK_FUNC(FUNC(DoDialogModel),hInst, hWnd, IDD_ABOUTBOX, about_handles));
       return TRUE;
    }
    

    ヘッダファイルのインポート:
    #include "api/cppquery.h"
    using namespace cppquery;

    キー部分コード
       static WindowFrontPeer::MessageHandle about_handles[] = {
            WindowFrontPeer::Command(IDOK, MK_FUNC(FUNC(EndDialog), _1, 0)),
            WindowFrontPeer::Command(IDCANCEL, MK_FUNC(FUNC(EndDialog), _1, 0)),
            NULL,
       };
       
        Window window(hWnd);
        window.onCommand(IDM_EXIT, MK_FUNC(FUNC(DestroyWindow), hWnd))
              .onDestroy(MK_FUNC(FUNC(PostQuitMessage), 0))
              .onCommand(IDM_ABOUT, MK_FUNC(FUNC(DoDialogModel),hInst, hWnd, IDD_ABOUTBOX, about_handles));

    それだけで、もともと自動生成されていたWndProcやAbout関数はもう必要ありません.
    以下重点的に解説する
    Windowオブジェクト
    Windowはウィンドウを表すパッケージクラスです.通常のパッケージとは異なり、実際にはアクセスしやすいインタフェースにすぎません.「on」で始まる関数がたくさんあり、各関数はメッセージコールバックを表します.onCommand関数でWM_が追加されますCOMMANDメッセージの処理ハンドルonDestroyはWMを追加しますDESTROYの処理関数です.
    Windowの各関数は、Windowオブジェクト自体を返します.これにより、連続的に呼び出すことができます.このような設計の目的は主に書くのが便利で効率的である.Windowオブジェクトはqueryメソッドによって大量に検索され生成されるため、このメソッドにより、Windowオブジェクトの再生成を可能な限り回避することができる.
    クローズドテンプレート
    大量に使用されているMK_FUNCマクロとFUNCマクロは、実際にはテンプレート関数の再定義です.文のように
    MK_FUNC(FUNC(DestroyWindow), hWnd)
    は実際にDestroyWindow(hWnd)に対して同じ効果を持つ呼び出しを形成しているが、この呼び出しはウィンドウでWM_を受信する.COMMANDメッセージ、そしてLOWORD(wParam)==IDM_EXITの時にトリガーされます.
    これはboostのようなパッケージです.
    この2つのマクロの定義は
    #define MK_FUNC make_function
    #define FUNC func_ptr

    func_ptrはテンプレート関数であり、この例では
    template<class R, class T1> struct function_ptr_cbapi1 {
        typedef R result_type;
        typedef R (CBAPI *Func)(T1); 
        Func f_;
        function_ptr_cbapi1(Func const& f) : f_(f) {}
        function_ptr_cbapi1(const function_ptr_cbapi1& f) : f_(f.f_) {}
        template
        result_type operator()(A1 a1) const 
        { return f_(arg_cast(a1)) ; }
        result_type operator()(T1 t1) const 
        { return f_(t1); }
    };
    template
    function_ptr_cbapi1 func_ptr(R (CBAPI *f)(T1) ) 
    { return function_ptr_cbapi1(f); }
    func_ptr     function_ptr_cbapi1  。(       function_ptr_cbapi0~function_ptr_cbapi9,           ,CBAPI   __stdcall,  windows callback     )。  DestroyWindow     ,       function_ptr_cbapi1。
    

    function_ptr_cbapiはパッケージテンプレートクラスにすぎず、DestroyWindowを が むように び すことを としています.
    make_functionもテンプレート であり、その は
    template<class F, class A1>
    function_t<F, list1<A1> > make_function(F const& f, A1 a1)
    { return function_t<F, list1<A1> >(f, list1<A1>(a1)); }
    
    make_functionにも10 のリロードがあり、パラメータによって なります.
    ここでは、パラメータの に します.
    function_を しますtオブジェクト、 オブジェクトにはlist 1オブジェクトも まれています.
    function_tオブジェクト:
    template<class F, class L>
    struct function_t : public func_base_t<function_t<F, L> >{
    	typedef typename F::result_type result_type;
    	F f_;
    	L l_;
    
    	function_t(F const& f, L const &l) : f_(f), l_(l) { }
    	function_t(const function_t & f)  : f_(f.f_), l_(f.l_){ }
    
    	
    	result_type operator()() const {
    		list0 l;
    		return l_(f_, l);
    	}
    
    	template<class R>
    	R operator()(type<R>) const {
    		list0 l;
    		return call(type<R>(), type<result_type>(), l_, f_, l);
    	}
    	template<class R, R const RDef>
    	R operator()(type_default<R, RDef>) const {
    		list0 l;
    		return call(type_default<R, RDef>(), type<result_type>(), l_, f_,l);
    	}
    
    	/* dynamic_list call */ 
    	result_type operator()(dynamic_list const& l) const { 
    		return l_(f_, l.driver()); 
    	} 
    	template<class R> 
    	R operator()(type<R> const& r, dynamic_list const& l) const {
    		return call(r, type<result_type>(), l_, f_, l.driver());
    	}
    	template<class R, R const RDef>
    	R operator()(type_default<R, RDef> const& rd, dynamic_list const& l) const {
    		return call(rd, type<result_type>(), l_, f_, l.driver());
    	}
    	
    	template<class TList>
    	bool checkArg(const list_t<TList>& l) const {
    		return l_.isElementHolderInList(l);
    	}
    
    
    	template<class A1> result_type operator()(list1<A1> const& l) const
    	{ return l_(f_, l); }
    	template<class R, class A1> R operator()(type<R> const& r, list1<A1> const& l) const 
    	{ return call(r, type<result_type>(), l_, f_, l); }
    	template<class R, R const RDef, class A1> R operator()(type_default<R, RDef> const& rd, list1<A1> const& l) const 
    	{ return call(rd, type<result_type>(), l_, f_, l); }
    	template<class A1> result_type operator()(A1 a1) const 
    	{ return (*this)(list1<A1>(a1)); }
    	template<class R, class A1> R operator()(type<R> const& r, A1 a1) const 
    	{ return (*this)(r, list1<A1>(a1)); }
    	template<class R, R const RDef, class A1> R operator()(type_default<R, RDef> const& rd, A1 a1) const 
    	{ return (*this)(rd, list1<A1>(a1)); }
    ....... //     ,            
    };
    function_tコアは2つのメンバー,Funcとlistである.funcは び された を するために され、listはパラメータリストを するために されます.
    function_を び すとtのoperator()オペレータをリロードする function_tはl_を び す(f_, l). l_リストテンプレートであり、 されたパラメータテンプレートを し、lは び し が えたパラメータを す.
    l_(f_,l)このような び し は、パラメータが しく び されることを するためである. DestroyWindowでfunction_tのFuncはDestroyWindowのポインタであり、l_list 1で、hWndのポインタが されています.l_いつもとf_を しています とタイプが するパラメータは、l_を して(f_,l)を び し, が しく び されることを する.
    placeholder
    このコードに してください
       static WindowFrontPeer::MessageHandle about_handles[] = {
            WindowFrontPeer::Command(IDOK, MK_FUNC(FUNC(EndDialog), _1, 0)),
            WindowFrontPeer::Command(IDCANCEL, MK_FUNC(FUNC(EndDialog), _1, 0)),
            NULL,
       };
    ご ください1この .
    まず、WindowFrontPeer::MessageHandleはメッセージの ハンドルを し、WindowFrontPeerの Command、Destroyなどで できます.これらはonCommand とonDestroy と ていますが、onシリーズ はMessageHandleを し、ウィンドウに けられますが、それらは けられていないだけを します.ウィンドウウィンドウが した にのみ けられます.
    _1はplaceholderオブジェクト、すなわちプレースホルダであり、この にパラメータテーブルの のパラメータを することを します. 
    の :
    WindowFrontPeer::Command(IDOK, MK_FUNC(FUNC(EndDialog), _1, 0)),
    WM_COMMANDメッセージが ると、このように び されます:command_handle(HWND hwnd, int id); だから のコードは、 にはこうなります
     
      
    function_t<Endialog, list2<HWND,INT> > endialog_func;
    endialog_func.f_ = EndDialog;
    endialog_func.l_.t1 = _1;
    endialog_func.l_.t2 = 0;
    //  
    endialog_func(hDlg, IDOK); 
    //    EndDialog(hDlg, 0)   
    
    _1は、hDlgをEndDialogの のパラメータに め む です.
    _1の は
    static const ArgIndexHolder<1> _1;

    ArgIndexHolderはいくつかのテンプレートクラスであり, の を たす.パラメータテーブルから された のパラメータが_に め まれます.1 の .
    のある はapi/cqholderを むことができます.hのコード.
    もっと、 しみにしてください.....