Windows界面编程_Miniblink(3) 事件绑定

Miniblink继承保留了cef里js事件回调的方法,我们可以使用miniblink里jsBindFunction函数来对html里与js脚本绑定的button或者对其标签进行js绑定。

注意使用这个框架开发的坏处在于你必须会前端编程和后端技术,懂得交互过程,因为后面还要介绍如何获取页面的消息事件

如果不想这样写的话,可以去我的github上下载开源的封装ui库,基于miniblink,无需会前后端知识,只需要懂得控件消息即可

第一步先编写一个html文件:

<html>
<body>



</body>
</html>

增加hand头,在hand头里写js函数

<html>
<head>
<script>
function myFunction()
{

}
</script>
</head>
<body>
<p id="demo">A Paragraph</p>
<button type="button" onclick="myFunction()">Try it</button>

</body>
</html>

这个js函数的意思是修改dom树里 id为demo的值,改为"My First JavaScript Function"

button里的onclick事件与之对应

然后我们续上一篇工程,在初始化函数里加上绑定函数:

回调函数原型:

jsValue JS_CALL myTest(jsExecState es){

}

先说一下 miniblink绑定原理,miniblink只能绑定js函数,注意不是我们的js脚本函数,是js默认自带的函数,如msg这样的执行函数。

我们在js函数里使用js系统函数msg,然后在绑定这个函数,当miniblink执行这个函数时会去执行我们自己的c语言函数,产生了映射

我们先修改js函数里,使用msg来传递参数

<html>
<head>
<script>
function myFunction()
{
   var obj = msgBox("");
   var name = obj.name;
   alert(name);
   var age = obj.age;
   alert(age);
}
</script>
</head>
<body>
<p id="demo">A Paragraph</p>
<button type="button" onclick="myFunction()">Try it</button>

</body>
</html>

上面这段js就是申请一个数组,去获取miniblink执行c函数后传递回来的参数

 

注意上面说了 js只能绑定js的系统函数,所以有一个问题,那就是很难交互,不能动态响应多个组件

那么怎么办呢? 博主就想出了一种解决方案

记录式的交互

这种方法就是在每次使用msgbox传值给索引,然后后端我们在写一个中转函数,来记录值的索引去调用不同的函数然后在把不同的函数处理结果传递回来,这样每个js函数就获得了对应的想要的结果

好了,那么我们动手写一写吧:

修改js函数里的msg穿值给1:

var obj = msgBox("1");

后端的中转系统:

//中转函数
jsValue JS_CALL js_msgBox(jsExecState es)
{
	const wchar_t* FuncIndex = jsToStringW(es, jsArg(es, 0));
	//开始中转
	if (wcscmp(FuncIndex, L"1") == 0){//执行索引一
		//funck
		
	}
	return jsStringW(es, L"0X00");

}

然后在ini函数里绑定:

 jsBindFunction("msgBox", js_msgBox, 1);//JS调用C++

第一个参数是函数名,只能是js的系统函数

第二个是回调函数,注意最好是全局函数

第三个代表告诉miniblink有前端js执行传递进来了多少参数,注意这个我们获取不到的,只是miniblink获取这个值用户给c++传值

 

绑定完成后所有执行msgbox的函数全部都会被执行我们的中转函数,然后我们写一个我们自己的函数,用于返回一个字符串和数值:

//索引函数
jsValue JS_CALL js_Index1(jsExecState es)
{
	jsValue jv = jsEmptyObject(es);	   
	jsValue jOv1 = jsStringW(es, L"dsad");
	jsValue jOv2 = jsInt(2);	  
	jsSet(es, jv, "name", jOv1);	    
	jsSet(es, jv, "age", jOv2);	    
	return jv;
	
}

这个是索引一的函数,在中转函数里回调:


 

//中转函数
jsValue JS_CALL js_msgBox(jsExecState es)
{
	const wchar_t* FuncIndex = jsToStringW(es, jsArg(es, 0));
	//开始中转
	if (wcscmp(FuncIndex, L"1") == 0){//执行索引一
		//func
		return js_Index1(es);
	}
	return jsStringW(es, L"0X00");

}

直接runturn就可以了,miniblink框架会帮我传值

其次说一下这个函数

const wchar_t* FuncIndex = jsToStringW(es, jsArg(es, 0));

es参数是代表指针指向传递进来值的内存块,可以通过规定函数大小来取值,更多的后面介绍,本文只介绍重点如何绑定事件,以及思路

我们执行一下看看:

 

可以看到界面出来了,我们点击按钮:

 

我们使用js里的alert信息框提示的信息也弹了出来,证明前后端交互成功o(* ̄▽ ̄*)ブ

整数值也获取到了,脚本语言最大的好处是不需要考虑类型

我们在稍微修改一下代码,将后端传递进来的name字符串修改我们的上面的标签字

   var obj = msgBox("1");
   var name = obj.name;
   document.getElementById('demo').innerHTML=name;
   var age = obj.age;

执行结果:

 

重点在于:

document.getElementById('demo').innerHTML=name;

这行代码是获取dom树下的名为id的子树,然后将子树内容改为变量name也就是我们获取的值

不建议在进行这样操作的时候使用信息框,因为内核渲染会优先处理完信息框在来绘制我们的改变页树的消息

在说一个上面如果传递进来不正确我们默认返回0X00 可以在js脚本里判断函数是否找到,防止意外出现,当然也可以使用别的方法让这个架构体系变得更加牢固,安全,健壮!

完整代码:

Win32

// Win32Project1.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include "Win32Project1.h"
#include "wke.h"
#define MAX_LOADSTRING 100

// 全局变量: 
HINSTANCE hInst;								// 当前实例
TCHAR szTitle[MAX_LOADSTRING];					// 标题栏文本
TCHAR szWindowClass[MAX_LOADSTRING];			// 主窗口类名

// 此代码模块中包含的函数的前向声明: 
ATOM				MyRegisterClass(HINSTANCE hInstance);
BOOL				InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK	About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPTSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

 	// TODO:  在此放置代码。
	MSG msg;
	HACCEL hAccelTable;

	// 初始化全局字符串
	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadString(hInstance, IDC_WIN32PROJECT1, szWindowClass, MAX_LOADSTRING);
	MyRegisterClass(hInstance);

	// 执行应用程序初始化: 
	if (!InitInstance (hInstance, nCmdShow))
	{
		return FALSE;
	}

	hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32PROJECT1));

	// 主消息循环: 
	while (GetMessage(&msg, NULL, 0, 0))
	{
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	return (int) msg.wParam;
}



//
//  函数:  MyRegisterClass()
//
//  目的:  注册窗口类。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32PROJECT1));
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_WIN32PROJECT1);
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

	return RegisterClassEx(&wcex);
}

//
//   函数:  InitInstance(HINSTANCE, int)
//
//   目的:  保存实例句柄并创建主窗口
//
//   注释: 
//
//        在此函数中,我们在全局变量中保存实例句柄并
//        创建和显示主程序窗口。
//
wkeWebView m_web;
//索引函数
jsValue JS_CALL js_Index1(jsExecState es)
{
	jsValue jv = jsEmptyObject(es);	   
	jsValue jOv1 = jsStringW(es, L"dsad");
	jsValue jOv2 = jsInt(2);	  
	jsSet(es, jv, "name", jOv1);	    
	jsSet(es, jv, "age", jOv2);	    
	return jv;
	
}
//中转函数
jsValue JS_CALL js_msgBox(jsExecState es)
{
	const wchar_t* FuncIndex = jsToStringW(es, jsArg(es, 0));
	//开始中转
	if (wcscmp(FuncIndex, L"1") == 0){//执行索引一
		//func
		return js_Index1(es);
	}
	return jsStringW(es, L"0X00");

}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // 将实例句柄存储在全局变量中

   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);
   wkeSetWkeDllPath(L"node.dll");

   wkeInitialize();
   RECT rtClient;
   GetClientRect(hWnd,&rtClient);
   rtClient.top += 24;
   m_web = wkeCreateWebWindow(WKE_WINDOW_TYPE_CONTROL, hWnd, rtClient.left, rtClient.top, rtClient.right - rtClient.left, rtClient.bottom - rtClient.top);
   wkeLoadFile(m_web, "index.html");
   jsBindFunction("msgBox", js_msgBox, 1);//JS调用C++
   wkeShowWindow(m_web, TRUE);

  
   return TRUE;
}

//
//  函数:  WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的:    处理主窗口的消息。
//
//  WM_COMMAND	- 处理应用程序菜单
//  WM_PAINT	- 绘制主窗口
//  WM_DESTROY	- 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;

	switch (message)
	{
	case WM_COMMAND:
		wmId    = LOWORD(wParam);
		wmEvent = HIWORD(wParam);
		// 分析菜单选择: 
		switch (wmId)
		{
		case IDM_ABOUT:
			DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
			break;
		case IDM_EXIT:
			DestroyWindow(hWnd);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		// TODO:  在此添加任意绘图代码...
		EndPaint(hWnd, &ps);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

// “关于”框的消息处理程序。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(lParam);
	switch (message)
	{
	case WM_INITDIALOG:
		return (INT_PTR)TRUE;

	case WM_COMMAND:
		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
		{
			EndDialog(hDlg, LOWORD(wParam));
			return (INT_PTR)TRUE;
		}
		break;
	}
	return (INT_PTR)FALSE;
}

html:

<html>
<head>
<script>
function myFunction()
{
   var obj = msgBox("1");
   var name = obj.name;
   document.getElementById('demo').innerHTML=name;
   var age = obj.age;
}
</script>
</head>
<body>
<p id="demo">A Paragraph</p>
<button type="button" onclick="myFunction()">Try it</button>
</body>
</html>

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章