让 Anchor 属性拥有设计时行为

原创 2017年01月31日 23:26:15

用过 vfp9 的人都知道这个好用的新属性,宿主控件大小变化时,其内部控件可以用这个属性来自动调整它们的位置和大小,不用再像 vfp6 中要写代码来调整;不过,大家也看到了,这个属性只是一个运行时行为,设计时是不起作用的。

趁着春节休息,想试试是否有办法,能使这个属性在设计时也起作用。这就想起以前有老外写过的一个,设计时可以让内部控件随容器自动调整的示例,网上是找不到了,幸运的是还有咱们万能的百事通 xinjie大笑,要来了这个示例。

研究了半天得出以下结论:

1. 任意控件的某个属性,如果其值是一个表达式(例如:=myfunc() ),vfp 在打开前都会先计算其值;这就给控件设计者一个干涉的机会!(重要:如果这个表达式无法计算(例如:函数不存在或者找不到),vfp 不会报错,仅简单的忽略它),所以,要想达到目的,这个函数必须在 curdir() 指向的路径上,或者 vfp 可以成功调用到这个函数,才会起作用

2. 这个表达式函数可以使用 This 将控件对象传递到表达式指向的函数中,这也是要达到目的的充要条件之一,注意这个 This 指向的对象是在设计时,而非运行时

做以下试验来验证:

1. 新建一个项目
2. 粘贴下列代码并保存为 test.prg

Lparameters toCtrl

m.toCtrl.Caption = Sys(2015)
Return Rgb(255, 0, 0)
3. 再新建一表单,将 BackColor 属性改成 = test(This)

表单背景色和标题是否变了? 

什么! 没变 ???

那就对了,因为没找到 test.prg

先关闭表单 ...

在命令窗口中键入 set deafult to ? 

回车,找到你刚才保存 test.prg 所在的文件夹

重新打开表单

要是你还是没发现有变化,下面的内容可以不用看了 ... 偷笑

如果你幸运的看到类似下面的样子,恭喜你!可以继续


(图一)

这个实验验证了上面的两点:

1. test.prg 必须在当前路径上

2. = test(This) 中的 This 传递给了 test 函数的 toCtrl 参数,它成功的用  toCtrl.Caption = sys(2015) 改变了表单的 Caption


做一个实用的工具

既然可以传入对象,那么就可以获取和设置对象的属性。本文开始时指出,vfp 控件的 anchor 属性仅在运行时才起作用,设计时时这样的:


(图二)


我们把它拖到一个新建的表上,一开始是这样:


(图三)

当我们将这个容器拉大后,仅容器变大了,里面的按钮并未按 anchor 属性设置的值那样自动调整到右下角:


(图四)

我们希望的 anchor 设计时行为,其结果应该是这样:


(图五)


现在,我们来添加一些代码,让它达到我们期望的结果

1. 设计我们的 resizer:新建一个 prg,贴入下列代码,并保存为 resizer.prg

Public goResizer
m.goResizer = NewObject('resizer')

Define Class resizer as Custom
	Dimension aCtrls[1]
	resizing = .f.
	
	Procedure Hook(toCtrl)
		Local cClass, ii
		If This.resizing
			Return
		EndIf
		
		m.cClass = Lower(m.toCtrl.BaseClass)
		If InList(m.cClass, 'container')	&& , pageframe, page, optiongroup, commandgroup, grid
			If Alen(This.aCtrls) == 1
				m.ii = 1
			Else
				m.ii = 1 + Alen(This.aCtrls, 1)
			EndIf
			Dimension This.aCtrls[m.ii, 3]
			This.aCtrls[m.ii, 1] = This.GetFullPath(m.toCtrl)
			This.aCtrls[m.ii, 2] = m.toCtrl.Width
			This.aCtrls[m.ii, 3] = m.toCtrl.Height
			BindEvent(m.toCtrl, 'resize', This, 'resize')
			BindEvent(m.toCtrl, 'destroy', This, 'destroy')
		EndIf
	EndProc
	
	Procedure Destroy
		Dimension This.aCtrls[1]
		This.aCtrls = .f.
	EndProc
	
	Procedure resize
		If This.resizing
			Return
		EndIf
		This.resizing = .t.
		
		Local ii, nw, nh, cc, c1, o1
		Local oo as Container
		Local oForm as Form
		Local array aTemp[1]
		
		AEvents(m.aTemp, 0)
		m.oo = m.aTemp[1]
		m.ii = Ascan(This.aCtrls, This.GetFullPath(m.oo), 1, -1, 1, 1+2+4+8)
		If m.ii > 0
			m.c1 = m.oo.ReadExpression('zzz_hook')
			m.oo.WriteExpression('zzz_hook', '')
			m.nw = m.oo.Width
			m.nh = m.oo.Height
			m.oo.Width  = This.aCtrls[m.ii, 2]
			m.oo.Height = This.aCtrls[m.ii, 3]
			m.cc = Sys(2015)
			m.oo.SaveAsClass(m.cc, m.cc)
			m.oForm = NewObject('Form')
			m.oForm.NewObject(m.cc, m.cc, m.cc)
			With GetPem(m.oForm, m.cc)
				.Move(0, 0, m.nw, m.nh)
				.Visible = .t.
				For each m.o1 in .Controls
					With GetPem(m.oo, m.o1.name)
						.Move(m.o1.Left, m.o1.Top, m.o1.Width, m.o1.Height)
					EndWith
				EndFor
			EndWith
			m.o1 = Null
			m.oForm = Null
			
			This.aCtrls[m.ii, 2] = m.nw
			This.aCtrls[m.ii, 3] = m.nh
			m.oo.Width  = m.nw
			m.oo.Height = m.nh
			m.oo.WriteExpression('zzz_hook', m.c1)
			
			Clear Class (m.cc)
			Erase (m.cc + '.vc?')
		EndIf
		
		This.resizing = .f.
	EndProc
	
	Procedure GetFullPath(toCtrl)
		Local oo, cc
		
		m.oo = m.toCtrl
		m.cc = m.oo.name
		Do while PemStatus(m.oo, 'Parent', 5) and !(m.oo.BaseClass == 'Form')
			Try
				m.oo = m.oo.Parent
				m.cc = m.oo.name + '.' + m.cc
			Catch
			EndTry
		EndDo
		Return Lower(m.cc)
	EndProc
EndDefine

说明一下:

A. 这个 resizer.resize 方法中的变量命名很没规矩,不要学大笑

B. 一开始的试验,验证了属性表达式中调用的函数必须在当前路径下,或者 vfp 可以找到(例如,你可以启动 vfp 后运行一个单独的 prg 来 set default to ...,或用 set proc to ... 或 set path to ... 将这 resizer.prg 放置在可搜索的过程或路径中);我们这里使用另外一种方式,定义一个设计时用的全局变量 goResizer,并让它在 vfp 启动时自动加载到设计环境中,这样就可以不再受 curdir() 的影响,因为它已在内存中了。


(图六)

好了,现在重启 vfp,在 debugger 中应该可以看到已经有一个全局变量 goResizer


(图七)


2. 怎样使用这个 resizer ?

  A. 按图二创建一个容器控件,放两个按钮,下面一个按钮紧靠右下,并设置它的 anchor 为 12

  B. 关键一步:给这个容器添加一个名为 zzz_hook 的设计时钩子属性,属性值为 * =goResizer.hook(This),因为现在我们只希望这个控件在表单设计器上拥有设计时 anchor 行为,而不是在类设计器中,所以在这个控件类的 zzz_hook 属性值前加了一个 * 号注释掉它

(图八)

  C. 将这个容器拖到表单上,见前面的图三,然后去掉 cnt1.zzz_hook 属性值前面的 * 号

  D. 现在再拉动表单上的这个容器调整下大小,看看右下角的按钮是否自动调整位置了? 再改变下这个按钮的 anchor 的属性,看看是否是你预计的结果

  E. 这个 resizer 的 resize 方法,本来几行代码就可以达到目的的,之所以写得又臭又长,其实是为了实现另一个目的:

      你在设计时往这个容器中加几个控件,并分别设置它们的 anchor 属性试试,虽然他们不是 cnt 控件类自带的,但也同样拥有设计时 anchor 行为。


(图九)

(图十)

这个示例仅测试了 vfp anchor 属性实现设计时行为的可能性,应该还有很多未考虑到的方面,resizer.destroy 中就偷懒了,将记录的所有绑定控件的原始属性都清空了,有兴趣的 foxer 可以按这里描述的方法创建自己的 resizer


示例样本:测试前,请注意按本文(图六)设置好开发环境;或者,先手工运行项目中的  resizer.prg

 http://download.csdn.net/detail/dkfdtf/9745745 



版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

05/11/07

今天不错。中午给弄了一下OD,把OD那个什么修改文件的一个菜单问题弄了一下。下午老大也不在,比较爽。据说老D把钱给我打过来了,虽然没有预想的多,但是也不错了。周末可以去找猪头购物去。打算买个大内存,再...
  • nbw
  • nbw
  • 2005-11-08 00:38
  • 571

COM 免注册技术

通常,实例化 COM 组件(包括采用这一技术的 DLL/ActiveX 控件)前,都需要先用 Regsvr32 注册该组件(或控件),从 XP sp2 开始,微软提供了一种采用 manifest(文件...

扩展 vfp9 自带的对象浏览器提取枚举值

Foxer 在使用第三方控件时,常为枚举值犯愁,这里提供一个简单的方法 1. 下载这个修改过的对象浏览器:http://download.csdn.net/detail/dkfdtf/949...

使用 BLOB 类型字段

vfp9 中增加了 blob 型字段,这可是个好东西!用它来存储图像数据最合适,与 SQL 的交换也很顺利,接下来就是使用它了。使用它当然无外乎是显示/打印图像;显示很简单,表单上放一个 Image ...
  • dkfdtf
  • dkfdtf
  • 2008-09-05 23:32
  • 4936

编程实现可执行文件的数字签名验证及证书安装

为何要制作数字签名,请参见我以前的文章 http://dkfdtf.blogbus.com/logs/10896854.html,我最近的一个项目也需要实现自验证功能,狐狸天堂上的金威先生也恰好有这个...
  • dkfdtf
  • dkfdtf
  • 2009-07-14 22:09
  • 9510

改变 vfp 可执行文件的运行库位置和名称

今天分析了一下如何将 vfp 的 exe 运行时要使用的运行库更名的问题。下面是分析结果,以 vfp9 + 简体中文 Windows 系统为例。我们知道,编译成 exe 的 vfp 程序要加载两个运行...
  • dkfdtf
  • dkfdtf
  • 2009-04-07 17:05
  • 2310

身份证号15位转18位

源自:http://blog.csdn.net/zhanghongju/archive/2009/06/11/4261422.aspx做少量修改,传15位转18位,传17补18位,传18位验证最后一位...
  • dkfdtf
  • dkfdtf
  • 2009-06-26 21:11
  • 1778

转帖:使用 .NET ClickOnce 技术发布和更新 vfp 应用程序

xinjie 最新翻译力作,foxer 从现在开始也可以使用 .Net ClickOnce 技术来发布自己的应用程序,拥有可配置的自动更新方式。来自:http://www.foxsky.net/bbs...
  • dkfdtf
  • dkfdtf
  • 2009-08-09 07:13
  • 2654

计算可打印区域及页边距

其实以前就研究过这个问题,只是当时粗心,漏看了 MSDN 中参数,以至当时没有找到计算的方法。 #define HORZRES 8#define VERTRES ...
  • dkfdtf
  • dkfdtf
  • 2009-03-20 10:58
  • 1796
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)