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

时间:2014-02-21 15:29:32

标签: excel vba position behavior userform

我有一个包含多个用户表单的Excel 2007 VBA项目,其中一个是包含Calendar Control 12.0对象的日期选择器。只要用户单击其中一个表单上的两个文本框控件之一,就会激活日期选择器。我想控制日期选择器的启动位置,以便在显示时,它与任何单击的文本框控件一致。

为此,日期选择器用户表单(frmDatePicker)会公开三个公共变量:xOffsetyOffsetfrmParent。目的是,在显示frmDatePicker之前,将通过引用这三个变量来设置其.Top.Left属性,这三个变量本身由调用子初始化。 (userform的.StartUpPosition属性也设置为零(即“手动”),以允许以这种方式控制其初始位置。)

这完全有效......除了第一次显示日期选择器。第一次调用.Show方法时,frmDatePicker与所点击的文本框不对齐。从第二次开始,这个问题就消失了。

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

到目前为止我尝试过:

  • 在空白工作簿中使用新的用户窗体进行测试,以确保此行为不是因为我的项目中存在某些瑕疵或损坏(不是)

  • .Top的{​​{1}}和.Left事件中设置UserForm_InitialiseUserForm_Activate属性 - 单独和同时设置(无差异) )

  • 在调用我的frmDatePicker函数并设置上述位置属性(无效)之前预加载frmDatePicker

我真的不想回到“快速显示然后隐藏表格”,因为......好吧,这只是一个可怕的解决方案!

感谢阅读!有什么想法吗?

2 个答案:

答案 0 :(得分:1)

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

SS

不确定原因。作为修复,这似乎有效:

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

答案 1 :(得分:1)

我发布此答案只是为了完整性,以提供有关此实例中实际发生情况的更多信息。 Alex K的解决方案更好。

我做了一些测试,发现只有.Left.Top的FIRST写入被重置/忽略。

在上面的示例中,事实证明.Left正在被观察重置/忽略,但写入.Top的值实际上是“坚持”。在我的项目中,默认居中位置所需的垂直位移非常小,所以我没有发现它。

我的解决方案只是将第一个属性设置两次,即

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并不重要,可能第一行只能设置一个虚拟值,因为无论如何它都会被忽略。只要您再次设置它,用户窗体就会在第一轮显示在所需位置。