为什么我写的Activex控件,切换窗口后画的图就没有了

小崔爱读书 2010-02-04 12:08:36
各位,我用ATL做了一个Activex控件,用于在web页面上接受用户的手写签批输入,我可以做出这个Activex控件,也可以在上面用鼠标模拟画图签字,但只要我一切换窗口,或者这个ActiveX控件被其他窗口遮盖住,所有的背景、我画的图就都没了,我不知道是不重绘还是什么意思。或者是我取的DC错了?我使用的getDC(m_hWnd)取的DC,应该也没问题吧。希望谁给点儿知道意见。谢谢。
...全文
280 25 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
sjdev 2010-02-04
  • 打赏
  • 举报
回复
没有。

你说的方法,除非是窗口一直在最上,不然一重绘就没了。
小崔爱读书 2010-02-04
  • 打赏
  • 举报
回复
这个有点儿不合适吧?我知道你这样说的可以实现,但不应该这么处理的。Windows窗口岂会没有自己的一块儿内存来保持它上面绘制的东西啊?还需要我手动来处理这个吗?并且如果我做的是一个普通windows应用,在上面手动画图,绝对不需要我组织一个链表的。
有没有更符合windows原理的一些方法?我觉得应该是某些项或参数我没有设置对,或者我没有继承和实现某些接口,谁能给点儿指导?
sjdev 2010-02-04
  • 打赏
  • 举报
回复
你如果StartPoint和EndPoint不记录下来,那当然没法显示了。
sjdev 2010-02-04
  • 打赏
  • 举报
回复
你得定义一个point的链表,每次操作时,把相应点放到链表中。

OnDraw函数中,不考虑操作。

只考虑把这些点显示出来。

当然了,最好把数据做一下封装。

譬如线,可以封装它的点。
譬如圆,可以封装它的圆心和半径。

小崔爱读书 2010-02-04
  • 打赏
  • 举报
回复
我试了一下,不行的,假设我先得处理背景吧,我应该在OnDraw中FillRect吧?如果我只是写FillRect这是可以的,因为每次切换或有窗口遮盖其上的时候,就不停的调用OnDraw,自然背景就总是正确的,但如果我是相应鼠标事件来绘图在上面的话,那么我把开始的Point和最终的Point发送给OnDraw,然后LineTo一下画出线,随着我的鼠标移动StartPoint和EndPoint都是不断变化的,一旦切换窗口或遮盖其上的时候,鼠标画出的东西是根本不会显示出来的。
小崔爱读书 2010-02-04
  • 打赏
  • 举报
回复
哦,你的意思是要把数据传递给onDraw方法来绘图?
谢谢。我试试啊。
小崔爱读书 2010-02-04
  • 打赏
  • 举报
回复
之前也写过几个窗口上绘图的程序,不过没写过web activex控件,没想到这个这么腻歪,不知怎么回事儿。
sjdev 2010-02-04
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 cuipy 的回复:]
我是在OnLButtonDown OnLButtonUp onMouseMove这三个时间组合,来实现鼠标画图的。
是移开以后挡住部分消失了,但我用Invalidate也不行的。不知道什么原因。我调用Invalidate了。
[/Quote]

你在这三个函数中更新所绘制的数据是可以的,但真正把数据绘制成图像,应该在Draw(OnDraw)??函数中。

数据更新后,掉Invalidate就ok了。
小崔爱读书 2010-02-04
  • 打赏
  • 举报
回复
我是在OnLButtonDown OnLButtonUp onMouseMove这三个时间组合,来实现鼠标画图的。
是移开以后挡住部分消失了,但我用Invalidate也不行的。不知道什么原因。我调用Invalidate了。
数世纪 2010-02-04
  • 打赏
  • 举报
回复
是挡住的地方移开后没有了?还是挡住部分全部消失?
如果是部分没有,是没有重绘,invalidate就行了,全部消失要再分析一下
sjdev 2010-02-04
  • 打赏
  • 举报
回复
是在Draw函数中画的吗?

小崔爱读书 2010-02-04
  • 打赏
  • 举报
回复
我最后解决了。我想大家说的都是有道理的,不过就100分,平分吧。

我没用链表,将DC存在内存中,然后OnDraw的时候读的内存中的DC,再覆盖一下现在的DC。
fandouC 2010-02-04
  • 打赏
  • 举报
回复
需要用链表保存点坐标的
jameshooo 2010-02-04
  • 打赏
  • 举报
回复
还有好几个概念你还没弄明白,所以解释有点困难。

1、ATL制作的控件可以是有窗口的,也可以是无窗口的,你的是哪一类?
2、不管有没有窗口,你只需重载OnDraw方法,并且用参数提供的HDC来绘制,ATL库内部屏蔽了有窗口和无窗口控件绘制之间的区别,有窗口控件的绘制来源是WM_PAINT消息,无窗口控件的绘制来源是容器对 OnDraw 的调用。
3、无窗口控件重绘必须调用容器的 Invalidate 方法,由容器再次调用控件的 OnDraw 方法执行重绘,不能使用任何窗口相关的API,也不能在 OnDraw 外部绘制。
4、有窗口控件就是一个标准的窗口,所以按照 WM_PAINT 方式绘制一个窗口,可以使用所有的窗口API。
5、所有窗口在大多数情况下都应该在 WM_PAINT 里面执行所有的绘制任务,但不是绝对的,有一些特殊的需求一般在 WM_PAINT 之外绘制,例如用鼠标选择一段文字时文字的背景和前景色变成高亮状态、编辑控件的光标闪烁等等,请记住一个原则,只要是不怕被消掉的就可以在外部绘制,文字高亮在窗口失去焦点时就可以失效,闪烁的光标通过定时器触发时再绘制,它们都不怕被消掉。问题是你的需求不符合这个原则,所以不应该放到外部绘制。还是 SJDEV 说的,你的每一次鼠标操作都应该产生一些数据保存起来,在 OnDraw 中绘制这些数据,这种做法不会导致被擦除。
6、还有一些概念,我都不知道该如何解释起。至于 CS_OWNDC 的作用,在你搞明白基本概念后,再去看看MSDN的解释就能理解了。
小崔爱读书 2010-02-04
  • 打赏
  • 举报
回复
我是用vs.2008开发的,是不是在开始创建组件的时候需要选择什么特别的选项啊?
小崔爱读书 2010-02-04
  • 打赏
  • 举报
回复
是不是因为ATL创建的是一个控件,而不是继承自CWindowImpl的窗口?没有自己重绘DC的功能啊?
小崔爱读书 2010-02-04
  • 打赏
  • 举报
回复
CS_OWNDC 这个是什么啊?我是一个ATL创建的控件,继承的都是一堆接口,另外。。我可以在其他地方绘图,就是绘图完毕后,这个控件一被覆盖后就不自绘之前我画到上面的东西了。连背景都没了。
jameshooo 2010-02-04
  • 打赏
  • 举报
回复
看起来你的控件是有窗口句柄的,这个窗口类是什么?如果是自定义类的话,在RegisterClass时把WNDCLASS::style的值里面加上 CS_OWNDC 标记,你就可以在OnDraw或WM_PAINT之外绘图了。
小崔爱读书 2010-02-04
  • 打赏
  • 举报
回复
必须嘛?我什么也没操作也要调用吗?
wwgddx 2010-02-04
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 cuipy 的回复:]
还有,我的控件不能处理WM_PAINT消息,我一旦创建了这个消息的处理方法,即便我什么代码也不写,cpu也持续100%,弄得我都几乎无法关闭ie窗口。
[/Quote]

WM_PAINT消息必须调用BeginPain();和EndPaint();这两个函数.
加载更多回复(5)
VB6.0动态加载ActiveX控件漫谈 深圳 罗汉军 罗德昌 熟悉VB的朋友对使用ActiveX控件一定不会陌生,众多控件极大地方便了编程, 但唯一的缺陷是不能动态加载控件,必须在设计时通过引用,将控件放置在窗体上。 VB6.0已能够解决该问题,只是帮助中没有明确说明,并且没有描述到一些关键功 能,由于以前的版本中可以动态创建进程外服务:如果对象是外部可创建的,可在 Set 语句中用 New 关键字、CreateObject 或 GetObject 从部件外面将对象引用赋予变 量。 如果对象是从属对象,则需使用高层对象的方法,在 Set 语句中指定一个对象引 用: Dim xlApp1 As Excel.Application Set xlApp1 = New Excel.Application 或 Dim xlApp As Object '定义存放引用对象的变量。 Set xlApp = CreateObject("excel.application") xlApp.Visible = True ---- 这些语法很容易造成误导,以为动态加载ActiveX控件也是此方法,可能有朋 友也象我一样利用CreateObject尝试了无数次,却无功而返,不知微软公司是出于何种 考虑,动态加载ActiveX控件是扩展控件集合的方式实现,通过实际摸索,终于就如 何实现动态ActiveX控件找出了一条切实可行的方法,下面以一个具体的实例来详细说 明。 一、ActiveX控件 ---- ActiveX 控件是 Visual Basic 工具箱的扩充部分。使用 ActiveX 控件的方 法与使用其它标准内装的控件,如 CheckBox 控件,完全一样。在程序中加入 ActiveX 控件后,它将成为开发和运行环境的一部分,并为应用程序提供新的功能。 ---- ActiveX 部件通过客户端/服务器关系与应用程序— 及与部件相互之间— 交 互作用。客户端是使用部件功能的应用程序代码或部件。服务器是部件及其关联的对象。 例如,假设应用程序使用 ActiveX 控件来提供一个标准的雇员窗体,供公司的多种 应用程序使用。提供雇员窗体的 ActiveX 控件就是服务器,使用这个控件的应用程序 就是服务器的客户端。 二、加载方法 ---- VB6.0中对Controls 集合进行了扩展,以前版本中Controls 集合在窗体上列 举出已加载的控件,这在迭代过程中是很有用的。Controls 集合标识一个叫做 Controls的内在窗体级变量。如果忽略可选的 object 所在处的整数,则关键字 Controls 必须包括在内。我们通常在窗口中使用如下代码: Text1.Text="Hello, world" 其实也可以使用如下代码达到同一目的: Controls(1).Text="Hello, world" ---- 在VB6.0中除了原来的Clear、Remove 方法外(很奇怪,为什么微软在VB5.0中 只提供这两种方法,而没有提供Add方法,因为没有Add,这两种方法也就没什么用处), 增加了Add方法,该方法就是用于动态加载控件的: Controls.Add(progid as String, Name as String); progid: ActiveX部件的ProgID,如:"VB.CheckBox"; Name:ActiveX部件加载后的名称,如: "MyCheckBox"; 若要在窗体上添加一个名为MyButton的按钮,可以使用: dim oControl as Object '窗体级变量 注意:这里声明为Object对象类型 Private Sub LoadControl() Set oControl = Controls.Add ("VB.CommandButton", "MyButton") oControl.Left = 10 oControl.Top = 10 oControl.Visible = True '使控件可见 End Sub ---- 这是VB6.0的标准语法,它在例程中也是如此演示的,不过该方法虽然现实了 控件的动态加载,按钮显示在窗体上,可以象普通按钮一样按下去,但加载的控件不能 预先设计响应事件代码,如:事件Sub MyButton_Click()将是非法的,当然,可以将要 响应的事件封装在控件内部。就编程的观点来看该方法没什么大的用处,开发ActiveX 控件的目的是为了资源共享,为了被其他开发人员利用,所以要提供必要的事件接口, 显然利用该方法不行,通过分析VBControls等相关对象,找出VBControlExtender对象 与EventInfo相结合能提供事件陷井捕捉,VBControlExtender对象对动态添加控件特 别有用,它提供了一套通用的属性、方法、事件给开发人员,它的一个突出特点是能编 程设计控件的事件,熟习类编程的朋友对带事件的对象声明一定不会陌生: ---- Dim WithEvents objElemt as CElemtVBControlExtender也不例外,声明的 语法一样,只不过它有个特殊的事件ObjectEvent(Info As EventInfo),它能捕捉到对 象使用RaiseEvent产生的所有事件,EventInfo数据结构映射了事件的名称、参数个数 和参数的值。VBControlExtender和 EventInfo相结合,采用Select Case 就可以预先 将不同类对象的事件放置一起,各自独立运作。将上面的代码改一下就能提供Click 事件了: ---- Dim WithEvents oControl As VBControlExtender '带事件声明声明之后您 就可以在代码窗口的左上角的对象下拉框中发现该对象出现了,也就是说,该对象有了 事件或方法了,它的事件有DragDrop,DragOver ,LostFocus ,GotFocus , ObjectEvent和Validate,其中ObjectEvent是通用的事件捕捉。 Private Sub LoadControl() Set oControl = Controls.Add ("VB. CommandButton", "MyButton") oControl.Visible = True End Sub Private Sub oControl_ObjectEvent(Info As EventInfo) Select Case Info.Name Case "Click" 'Click事件 '您可以添加处理Click事件代码 MsgBox "您按了MyButton!" Case Else ' 其他事件 ' Handle unknown events here. End Select End Sub ---- 当然对微软提供的标准控件能采用该方法添加,大家都不会怀疑,但自己开 发的控件也能吗?答案是肯定的,我们可以用一个实际的例子进行说明。 三、实例描述 ---- 假设一个本地网络的监控系统,需要在原理与实物示意切换,原理 包括组网结构、传输资源、监控主机等,而实物示意包括路由器、设备、采集器等, 当然两种的事件要一致,如双击某个设备形将显示给设备的实时数据等,为了简化 维护,将原理与实物示意封装成ActiveX控件,由于每种需要加载许多形控 件,消耗资源较大,不能同时加载,需要将其分解为两个控件,在切换时首先卸载一个 控件,然后加载另一个控件,所以要实现动态加载ActiveX控件。 ---- 原理控件为--Theory.ocx ,对应工程为CTheory; ---- 实物控件为---Fact.ocx ,对应工程为CFact; ---- 注意:为了简化,在设计控件时不设置许可证关键字。 ---- 实物控件上的形对象可以被拖动,拖动后的位置信息通过事件 ChangePosition来通知拥有该控件的窗体,以便下次加载能显示在最后位置,实物 和原理控件都有双击事件完成的工作相同,其他事件此处忽略。 ---- 四、具体示例 ---- 1、准备工作 ---- 对控件Theory.ocx 、Fact.ocx 进行注册(利用Regsvr32.exe注册); ---- 建立窗体frmTest.frm ,在窗体上放置按钮cmdLoadOcx—“原理” ---- 2、声明窗体级变量与加载函数LoadControl Dim WithEvents oControl As VBControlExtender '地仿真控件对象 Dim mblnTheory As Boolean '是否显示原理 Private Function LoadControl(intType As Integer) If Not oControl Is Nothing Then '首先判断对象是否存在,若存在则卸载 Controls.Remove("MapView") '卸载控件,此操作非常重要 End If If intType = 0 Then Set oControl = Controls.Add ("CTheory. Theory", "MapView") Else Set oControl = Controls.Add ("CFact.Fact", "MapView") End If oControl.Height = 3500 oControl.Width = 6500 oControl.Top = 100 oControl.Visible = True End Function Private Sub Form_Load() mblnTheory = True End Sub ---- 3、为按钮cmdLoadOcx编代码 Private Sub cmdLoadOCX_Click() If mblnTheory Then Call LoadControl(0) mblnTheory = False cmdLoadOCX.Caption = "实物" Else Call LoadControl(1) mblnTheory = True cmdLoadOCX.Caption = "原理" End If End Sub ---- 4、为事件ChangePosition编代码 Private Sub oControl_ObjectEvent (Info As EventInfo) Select Case Info.Name Case "ChangePosition" MsgBox CStr(Info.EventParamters.Item( 1).Value) + ":" + _ CStr(Info.EventParamters.Item(2).Value) Case "DbClick" '双击处理代码 Case Else ' End Select End Sub ---- 注意: EventInfo的参数EventParamters集合中是以1开始的,一般来说,微 软新的集合一般是以1开始的,而旧的是以0开始的,如RdoErrors.Item(0)。 ---- 5、关闭窗口前卸载控件 Private Sub Form_Unload(Cancel As Integer) Controls.Remove("MapView") Set oControl = Nothing End Sub ---- 6、特别注意 ---- 通过Controls.Add方法添加的ActiveX控件一定不能在该工程中有该控件的任 何引用,否则系统将出错。 四、小结 ---- 通过使用动态加载ActiveX控件使用庞大的应用程序变得很小,将不同的 ActiveX控件进行各种组合,使应用程序更加灵活多变,如您的应用系统要处理三十种门禁, 而某个具体的用户可能只有一种或两种门禁,根本没必要首先将所有门禁包含到应用 中,可将各个门禁独立封装,只安装注册需要的组件,就象Windows的自定义安装一样。 微软的未来技术基础是分布式的组件技术(DCOM),将会把代码的重用发挥得淋漓尽致。 您不妨试一试动态加载,也许会产生令您惊喜的效果! ---- 本代码在Win98、VB6.0(英文版)上编译、运行。

3,248

社区成员

发帖
与我相关
我的任务
社区描述
ATL,Active Template Library活动(动态)模板库,是一种微软程序库,支持利用C++语言编写ASP代码以及其它ActiveX程序。
社区管理员
  • ATL/ActiveX/COM社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧