XL VBA如何防止在第一个.Show中忽略UserForm的.Top和.Left属性?

我有一个Excel 2007 VBA项目与几个用户窗体,其中之一是包含日历控件12.0对象的dateselect器。 每当用户点击其他表单上的两个文本框控件之一时,dateselect器就被激活。 我想控制dateselect器的启动位置,这样,当显示时,它与任何已经被点击的文本框控件一致。

为此,date选取器userform( frmDatePicker )公开三个公共variables: xOffsetyOffsetfrmParent 。 其意图是,在显示frmDatePicker之前,它的.Top.Left属性将通过引用这三个variables来设置,这些variables本身是由调用子程序初始化的。 (用户.StartUpPosition.StartUpPosition属性也设置为零(即“手动”)以允许以这种方式控制其初始位置。)

这工作完美…除了第一次显示dateselect器。 第一次调用.Show方法时, frmDatePicker不会与单击的文本框alignment。 从第二次起,这个问题就消失了。

frmDatePicker的代码如下:

 Option Explicit Public InitialDate As Variant Public xOffset As Double Public yOffset As Double Public frmParent As Object Private DateSelected As Boolean Function Execute() As Boolean If Not frmParent Is Nothing Then Me.StartUpPosition = 0 Me.Left = frmParent.Left + xOffset Me.Top = frmParent.Top + yOffset End If If Not IsDate(InitialDate) Then InitialDate = DateSerial(Year(Now), Month(Now), 1) calPickDate.Value = InitialDate calPickDate.ValueIsNull = True btnCancel.SetFocus DateSelected = False Me.Show Execute = DateSelected End Function Private Sub btnCancel_Click() DateSelected = False Me.Hide End Sub Private Sub calPickDate_Click() DateSelected = True Me.Hide End Sub Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer) If CloseMode = vbFormControlMenu Then Cancel = True DateSelected = False Me.Hide End If End Sub 

主叫子如下:

 Private Sub GetDate(Target As MSForms.TextBox) With frmDatePicker .Caption = IIf(Target Is txtDstart, "Start date", "End date") Set .frmParent = frmAnalysis .xOffset = Target.Left .yOffset = Target.Top .InitialDate = Target.Value If .Execute() Then Target.Value = Format(.calPickDate, "dd/mm/yyyy") End With End Sub 

我到目前为止所尝试的:

  • 用一个新的用户表单testing一个空白的工作簿,以确保这种行为是不是因为我的项目中的一些cruft或腐败(这不是)

  • 设置frmDatePickerUserForm_InitialiseUserForm_Activate事件中的.Top.Left属性 – 单独以及两者(无差别)

  • 在调用我的.Execute函数并设置位置属性之前,预先frmDatePicker (不起作用)

我真的不想因为“快速显示然后隐藏表格”而退后一步,因为…好吧,这只是一个可怕的解决scheme!

谢谢阅读! 有任何想法吗?

奇怪,正如你说的第一次轮设置.Left/Top似乎重置/被忽略:

SS

不知道为什么。 作为一个解决这似乎工作:

 If Not frmParent Is Nothing Then Me.StartUpPosition = 0 Me.Move frmParent.Left + xOffset, frmParent.Top + yOffset End If 

我已经发布了这个答案只是为了提供更多的信息,在这种情况下实际发生的事情。 亚历克斯K的修复更好。

我做了一些更多的testing,发现只是第一次写入.Left.Top被重置/忽略。

在我上面的例子中,事实certificate,正如所观察到的那样, .Left被重置/忽略,但是写入.Top的值实际上是“粘着”的。 在我的项目中,默认居中位置所需的垂直位移非常小,所以我没有发现这一点。

我的解决scheme是简单地设置第一个属性两次,即

 If Not frmParent Is Nothing Then Me.StartUpPosition = 0 Me.Left = frmParent.Left + xOffset Me.Left = frmParent.Left + xOffset Me.Top = frmParent.Top + yOffset End If 

第一个是.Left还是.Top并不重要,假设第一行可以设置一个虚拟值,因为它将被忽略。 只要你再次设置它,用户窗体第一次显示在所需的位置。