ok,开工吧:
开发工具:推荐用delphi 2010(d7也可以,不过添加属性,方法等过程要手动,稍微麻烦点)
1.启用delphi2010-->File->New->Other-->Active Library
2.项目命名为MyActiveX
3.File-->Save All 全部保存
实际上这样就能编译了,不过只是空的dll
4.File-->New-->Other-->Active Form
改名为MyForm
将对应的单元文件,保存为UMyForm.pas
5.打开MyAcitveX.ridl文件,切换到design视图,选中IMyForm接口,右击New-->Property
添加一个属性Msg
将Msg属性的Type改为BSTR 即WideString类型
完了之后,点击工具栏中的Refresh
Implementation(即上图中工具栏中圈起来的部分)--这一步很重要,点击之后,它将自动生成属性Msg对应的声明和实现代码模板
6.打开UMyForm.pas--即ActiveForm对应的单元,找到Set_Msg以及Get_Msg的实现部分,补充代码如下:
function TMyForm.Get_Msg: WideString
begin
result:=_msg
end
procedure TMyForm.Set_Msg(const Value: WideString)
begin
_msg := value
end
当然TMyForm的private部分,得先加一个私有成员
type
TMyForm = class(TActiveForm, IMyForm)
private
{ Private declarations }
_msg:WideString
...
这样我们就为即将生成的ActiveX控件,添加了一个字符串类型的属性Msg,下面来测试一下:
7.编译项目,会生成一个MyActiveX.ocx,在运行栏里输入
regsvr32 C:\Users\jimmy.yang\Desktop\Delphi_activex\MyActiveX\MyActiveX.ocx
注:这里ocx的路径,请各位根据自己的实际路径修改
这样就完成了ocx的注册。
8.放到html里测试一下:
<OBJECT ID='x' name='x' CLASSID='CLSID:52D17094-0687-4A2F-B2DB-30F3189AC659' align=center hspace=0 vspace=0 ></OBJECT>
<script type='text/JavaScript'>
var x = document.getElementById("x")
alert(x.Msg)
</script>
关于CLSID在哪里查看,打开:MyActiveX_TLB.pas文件,定位到下面这里:
const
// TypeLibrary Major and minor versions
MyActiveXMajorVersion = 1
MyActiveXMinorVersion = 0
LIBID_MyActiveX: TGUID = '{49138437-8265-4B1A-9EAE-D0F615D68464}'
IID_IMyForm: TGUID = '{54A20855-29A3-4C92-85DE-A419DA457C7A}'
DIID_IMyFormEvents: TGUID = '{60BBC967-E1E6-4E98-BAE5-776BFD06E9CC}'
CLASS_MyForm: TGUID = '{52D17094-0687-4A2F-B2DB-30F3189AC659}'
其中 CLASS_MyForm: TGUID对应的就是ClassID
运行后,除了d出一个空白的警告框,暂时看不到其它:)(可不就是这样么?Msg属性没给任何初始值,当然是空字符串,所以d出一个空的警告框是正常的)
9.我们再来添加一些控件和方法,以验证刚才设置的属性确实有效
在MyForm上添加一个文件框,一个按钮
按钮的事件如下:
procedure TMyForm.Button1Click(Sender: TObject)
begin
_msg:= self.Edit1.Text
end
即把文本框的值赋给属性Msg
再继续定位到Set_Msg,略做修改
procedure TMyForm.Set_Msg(const Value: WideString)
begin
_msg := value
self.Edit1.Text := _msg
end
即设置Msg属性时,同时也把值显示在文本框里,以便等会儿我们好测试在js中给activeX属性赋值的效果
ok了,再来测试一下,编译一下,如果通不过,请先运行
regsvr32 C:\Users\jimmy.yang\Desktop\Delphi_activex\MyActiveX\MyActiveX.ocx /u
将刚才注册的ocx反注册,同时关掉浏览器,不然该ocx文件一直被占用,无法更新.
修改一下html的代码:
<OBJECT ID='x' name='x' CLASSID='CLSID:52D17094-0687-4A2F-B2DB-30F3189AC659' align=center hspace=0 vspace=0 ></OBJECT>
<hr />
<input type='button' value='显示Msg属性的值' onclick='ShowMsg()'/>
<input type='button' value='设置Msg属性的值' onclick='SetMsg()'/>
<script type='text/JavaScript'>
var x = document.getElementById("x")
var ShowMsg = function(){
alert(x.Msg)
}
var SetMsg = function(){
x.Msg = 'js传过来的值'
}
</script>
想要在Qt里使用全局热键,最好的办法是重载QApplication里的winEventFilter函数。这个函数是用来响应Windows系统信息的。其函数原型为virtual bool winEventFilter(MSG *msg, long *result)。当msg指针中的message(MSG结构中的一个元素)为WM_HOTKEY类型时,就是用户激发了热键。整个过程和在VC的消息响应机制很类似,只不过换成了Qt而已。而如果我们想要添加自己的全局热键,只需要使用RegisterHotKey函数即可。其函数原型为:
BOOL RegisterHotKey( HWND hWnd, int id, UINT fsModifiers, UINT vk )
HWND类型是Windows中的窗口句柄类型,在Qt中,QWidget及其子类均可使用winId()函数得到。
第二个参数,是一个原子 *** 作类型,用ATOM GlobalAddAtom(LPCTSTR lpString )函数得到。这也是一个Win32API,根据一个string参数可以得到一个唯一的值。使用完之后,必须使用GlobalDeleteAtom函数删除掉整个ATOM。其函数原型为ATOM GlobalDeleteAtom( ATOM nAtom )。
后面两个参数,一个是修饰键,一个是普通按键。例如,假设我们想注册Ctrl+F4这个热键组合,则fsModifiers就是MOD_CONTROL,而vk就是VK_F4。
如果注册成功,就返回true,否则,返回false。
注意,使用完之后,要使用UnregisterHotKey函数注销,否则你可能再也无法注册这个热键了!除非重启。其函数原型为:BOOL UnregisterHotKey(HWND hWnd, int id )。
ok,热键注册就完成了。当按下热键后,我们就会在QApplication里的winEventFilter函数中收到一个msg。这个msg,前面也说过,我们需要知道它的一个元素message是不是WM_HOTKEY。如果是,就证明我们收到了Windows系统的热键信息。在MSG结构中,我们可能还需要理解的元素有两个,分别是wParam和lParam。wParam是注册热键时所用的id,也就是ATOM(原子)。而lParam就是我们的热键了。其实际上是一个32位的类型,前面16位代表普通按键,后16位代表的是修饰键。
在QT中,我们经常使用 qDebug() 、 qInfo() 等来打印调试的信息,但是当打印信息过多时,很不利于查找阅读。所以本文介绍使用 QtMessageHandler 类中的 qInstallMessageHandler() 来自定义处理调试信息。
一、在主线程中注册调试信息处理回调
这里的 outputMessage 即为自定义的触发函数,当程序有调试信息时,将会调用此函数
二、实现触发函数
说明:此函数需要接受三个参数
QtMsgType type :表示调试信息类型,包括 QtDebugMsg (调试消息)、 QtInfoMsg (信息消息)、 QtWarningMsg (警告消息和可恢复的错误)、 QtCriticalMsg (关键错误和系统错误)、 QtFatalMsg (致命错误)
const QMessageLogContext &context :表示有关日志消息的其他信息,比如文件名 context.file 、行号 context.line 等等。
const QString &msg :表示原始的调试信息。
这样,我们就可以根据调试信息类型,自定义处理调试信息,并打印到日志文件等等。
但是有时候,我们会有这样的需求,有些类型的信息需要打印到屏幕,而有些类型的信息需要打印到日志。当注册了调试信息处理的回调,如何分类去处理呢?
查看QT文档中对于 qInstallMessageHandler() 的描述,可以知道该函数返回一个指向上一个消息处理程序,可以理解为上一个消息处理函数的指针。因此在使用 qInstallMessageHandler() 注册回调时,可以保存函数的返回,从而用之前的处理程序来处理调试信息
例如:
使用 s_messageHandler 来保存函数的返回值,即指向了上一个消息处理函数。在 outputMessage() 函数中使用 s_messageHandler
这样就实现了将Info等信息打印到日志,而debug信息打印到屏幕。
注: 以上写入日志文件的写法,并不是线程安全的,需要加锁来保证线程安全,这里就不再赘述。
正常的运行程序,日志内容如下:
实际项目中遇到了编译出的Release版本,日志输出没有文件信息、行数的问题。如下:
解决方法:
在.pro文件中添加宏
一定要先删除掉之前编译的中间文件,重新qmake!这样就可以在Release版本中正确输出日志信息。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)