(中行雷威2020.05.21)
(同一个世界,同一个梦想,交流学习C++Builder and Delphi XE10,传承c++builder and Delphi的魅力!欢迎各地朋友加入我的QQ群484979943,进群密码“BCB”,同时也请将该群号广为宣传,希望能够广集各方高手,共同进步。如需下载开发工具及源代码请加入我的QQ群。)
【阅读倡议】
1、有问题请留言;
2、没问题请点赞;
3、看连载请加群;
4、下源码请加群;
【开发工具】
1、C++Builder and Delphi 10.3.3
2、FMSoft_uniGUI_Complete_Professional_1.70.0.1531(正版)
本人主笔的国内第一本uniGUI教学案例代码已诞生,分为cbuilder和delphi两个版本,买代码送教程,需要的朋友可以加入我的QQ技术交流群484979943给我(群主)留言。资料简介:
1.1 扫码二维码
UniGUI目前(截至1525版本)还没有自己的扫码控件,但是它最大的特点就是打通了对JavaScript的调用,可以调用第三方的js实现扫码,本例将调用ZXing扫码的js代码实现移动设备扫码,它既是一个扫码案例,又是一个详细阐释uniGUI如何调用JavaScript和回调的案例。
- 布局
新建一个项目,配置好并保存项目,然后编译运行项目,生成输出目录结构,然后将本节配套代码files目录下的beep-digital.mp3(扫码声音文件)和zxing.min.js(ZXing的JavaScript文件)复制到Win32\Debug\files目录下;因为ZXing扫码使用了https加密连接,需要SSL证书和SSL库文件,将tools目录下的cert.pem、key.pem、root.pem(SSL证书文件)、libeay32.dll、ssleay32.dll(SSL驱动文件)复制到Win32\Debug目录下(证书文件的生成及https连接的使用方法详见我的《UniGUI入门到精通》教程的“加密连接”章节)。
在MainmForm上添加一个UnimHTMLFrame、两个UnimButton和一个UnimMemo。UnimHTMLFrame1用来关联ZXing的js脚本实现摄像头选择和摄像头扫码;UnimButton一个用来启动扫码,命名为btnStart,一个用来停止扫码,命名为btnStop;UnimMemo1用来记录扫码结果,命名为mResult。
|
控件名称 |
属性 |
取值 |
说明 |
|
UnimHTMLFrame1 |
Align |
alTop |
|
|
|
AlignWithMargins |
TRUE |
保留控件四周边界 |
|
btnStart(UnimButton1) |
Align |
alTop |
|
|
|
AlignWithMargins |
TRUE |
保留控件四周边界 |
|
btnReset(UnimButton2) |
Align |
alTop |
|
|
|
AlignWithMargins |
TRUE |
保留控件四周边界 |
|
mResult(UnimMemo1) |
Align |
alTop |
|
|
|
AlignWithMargins |
TRUE |
保留控件四周边界 |
|
UniServerModule |
CustomFiles |
files/zxing.min.js |
调用Zxing JS代码 |
|
|
FilesFolder |
files\ |
默认文件目录 |
|
|
SSL->Enabled |
TRUE |
启动SSL |
|
|
SSL->Password |
8077 |
HTTPS端口 |
|
|
SSL->CertFile |
cert.pem |
证书文件及配置 |
|
|
SSL->KeyFile |
key.pem |
|
|
|
SSL->Method |
sslvTLSv1_1 |
|
|
|
SSL->Mode |
sslmUnassigned |
|
|
|
SSL->RootCertFile |
root.pem |
|
|
|
SSL->Versions |
[sslvTLSv1_1] |
- 功能
系统启动后直接调用主窗口MainmForm的OnReady事件初始化硬件设备,搜索设备共有几个摄像头,然后列举出来,选择一个后置摄像头,点击btnStart按钮开始扫码,对准条形码或二维码,滴的一声将在下方的UnimMemo里出现扫码结果;点击btnReset按钮将停止扫描,可以重新选择新的摄像头,屏幕中如果同时出现一个条形码和一个二维码,将优先扫描二维码。
3、代码
1)UnimHTMLFrame1的HTML属性代码
<audio id="player" height="0px" src="files/beep-digital.mp3" style="display:none"></audio>
<div>
<video id="video" width="100%" height="100%" style="border: 1px solid gray"></video>
</div>
<div id="sourceSelectPanel" style="display:none">
<label for="sourceSelect">Change video source:</label>
<select id="sourceSelect" style="max-width:400px">
</select>
</div>
- UniServerModule的CustomFiles属性代码
files/zxing.min.js
3)UnimMain.cpp核心代码
void __fastcall TMainmForm::UnimFormReady(TObject *Sender)
{
//初始化摄像头
String tmpStr;
tmpStr=UnimHTMLFrame1->JSName +"._ael=document.getElementById(\"player\");"+ UnimHTMLFrame1->JSName +"._ael.load();"+
UnimHTMLFrame1->JSName + ".oldResultText=\"\";"+
"let selectedDeviceId;"+
" const codeReader = new ZXing.BrowserMultiFormatReader();"+
" codeReader.getVideoInputDevices()"+
" .then((videoInputDevices) => {"+
" const sourceSelect = document.getElementById(\"sourceSelect\");"+
" selectedDeviceId = videoInputDevices[0].deviceId;"+
" if (videoInputDevices.length >= 1) {"+
" videoInputDevices.forEach((element) => {"+
" const sourceOption = document.createElement(\"option\");"+
" sourceOption.text = element.label;"+
" sourceOption.value = element.deviceId;"+
" sourceSelect.appendChild(sourceOption);"+
" });"+
" sourceSelect.onchange = () => {"+
" selectedDeviceId = sourceSelect.value;"+
" };"+
" const sourceSelectPanel = document.getElementById(\"sourceSelectPanel\");"+
" sourceSelectPanel.style.display = \"block\";"+
" }"+
" document.getElementById(\""+ btnStart->JSId +"\").addEventListener(\"click\", () => {"+
" codeReader.decodeFromVideoDevice(selectedDeviceId, \"video\", (result, err) => {"+
" if (result&&result.text!="+UnimHTMLFrame1->JSName+".oldResultText) {"+
" window.ajaxRequest("+ UnimHTMLFrame1->JSName +", \"getResult\", [\"result=\"+result.text]);"+
UnimHTMLFrame1->JSName + ".oldResultText=result.text;"+
" }"+
" if (err && !(err instanceof ZXing.NotFoundException)) {"+
" }"+
" });"+
" });"+
" document.getElementById(\""+ btnReset->JSId +"\").addEventListener(\"click\", () => {"+
" codeReader.reset();"+
" ajaxRequest("+ UnimHTMLFrame1->JSName +", \"getResult\", [\"result=\"+\"\"]);"+
" })"+
" })"+
" .catch((err) => {"+
" alert(err)"+
" })";
UniSession->AddJS(tmpStr);
}
void __fastcall TMainmForm::btnStartClick(TObject *Sender)
{//启动扫码
btnStart->JSInterface->JSCall("element.dom.click","[]");
}
//---------------------------------------------------------------------------
void __fastcall TMainmForm::btnResetClick(TObject *Sender)
{//停止扫码
btnReset->JSInterface->JSCall("element.dom.click", "[]");
}
//---------------------------------------------------------------------------
void __fastcall TMainmForm::UnimHTMLFrame1AjaxEvent(TComponent *Sender, UnicodeString EventName,
TUniStrings *Params)
{//Ajax回调获取扫码结果
if (EventName == "getResult" )
{
mResult->Lines->Add(Now());
mResult->Lines->Add("【"+Params->Values["result"]+"】");//显示扫码结果
UnimHTMLFrame1->JSInterface->JSCall("_ael.play", "[]");//滴滴一声
}
}
4、效果
设置手机,让谷歌浏览器拥有摄像头和声音权限,打开手机的谷歌浏览器,输入https://服务地址:8077,操作体验一下吧(本案例在华为和小米手机均调试通过,在PC版谷歌浏览器上测试时偶尔会出现摄像头快速闪断现象)。