You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改VBA代码实现带时分秒时间戳的甘特图形状精准定位

问题

我正尝试通过Start_Timestamp列与End_Timestamp列创建甘特图。目前已有可生成仅含日期(时分秒为零)列的代码,当前生成的形状为压缩矩形,希望修改代码使矩形能依据时间戳的时分秒准确起始和结束。以下是现有创建日历及放置形状的VBA代码,恳请提供修改建议以实现正确的形状尺寸与位置设置。


关键修改说明

  • 日历生成逻辑简化:确保每列代表完整一天,方便计算单天宽度基准
  • 精确时间比例换算:通过时间戳的时分秒占全天的比例,计算形状在列内的偏移和宽度
  • 修复原代码中日期差计算的参数顺序错误
  • 减少不必要的Select操作,提升代码稳定性

修改后的创建日历代码

Sub Create_Calendar()
    Sheets("Gantt").UsedRange.Delete
    Sheets("Triece_Calendar").Columns("A:F").Copy Destination:=Sheets("Gantt").Columns("A:F")
    
    Dim ws As Worksheet
    Set ws = Worksheets("Gantt")

    With ws.Range(ws.Cells(1, 1), ws.UsedRange)
        ' 合并日期与时间生成完整时间戳
        .Range(.Range("G2"), .Cells(.Rows.Count, 7)).Formula = "=INT(B2)+MOD(C2,1)"
        .Columns("G").Calculate
        .Columns("G").NumberFormat = "yyyy/mm/dd hh:mm;@"
        .Range("G1").Value = "Start_Timestamp"
        
        .Range(.Range("H2"), .Cells(.Rows.Count, 8)).Formula = "=INT(D2)+MOD(E2,1)"
        .Columns("H").Calculate
        .Columns("H").NumberFormat = "yyyy/mm/dd hh:mm;@"
        .Range("H1").Value = "End_Timestamp"
        
        .Range("B:E").EntireColumn.Hidden = True
    End With
    
    Dim Min_Date As Date, Max_Date As Date, NextDate As Date
    Min_Date = Application.WorksheetFunction.Min(ws.Columns("G"))
    Max_Date = Application.WorksheetFunction.Max(ws.Columns("H"))
    NextDate = DateValue(Min_Date) ' 取纯日期作为起始
    
    ws.Range("I1").Select
    ' 生成每天的日期列(时分秒为0)
    Do Until NextDate > DateValue(Max_Date)
        ActiveCell.NumberFormat = "yyyy/mm/dd"
        ActiveCell.Value = NextDate
        ActiveCell.Offset(0, 1).Select
        NextDate = NextDate + 1
    Loop
    ' 添加最后一列用于边界计算
    ActiveCell.Value = NextDate
    ActiveCell.NumberFormat = "yyyy/mm/dd"
End Sub

修改后的放置形状代码

Sub Create_Gantt()
    ActiveSheet.UsedRange.Delete
    Create_Calendar
    
    Dim X As Integer
    Dim dDayWidth As Double ' 单天列的宽度基准
    Dim dLeft As Double, dtop As Double, dWidth As Double, dHeight As Double
    Dim dtStart As Date, dtEnd As Date, sName As String
    Dim p As Integer
    Dim ws As Worksheet
    Set ws = ActiveSheet
    
    ' 获取单天列的宽度
    dDayWidth = ws.Cells(1, 9).Width
    X = 1
    
    ws.Range("G2").Select
    Do Until ActiveCell.Value = ""
        dtStart = ActiveCell.Value
        dtEnd = ActiveCell.Offset(0, 1).Value
        dtop = ActiveCell.Top + 3
        dHeight = 11
        
        ' 计算形状左侧位置:找到起始日期列 + 当天内的时间偏移
        p = 9
        Do Until ws.Cells(1, p).Value = DateValue(dtStart)
            p = p + 1
        Loop
        Dim startTimeRatio As Double
        startTimeRatio = (dtStart - DateValue(dtStart)) / 1 ' 当天时间占全天的比例
        dLeft = ws.Cells(1, p).Left + (startTimeRatio * dDayWidth)
        
        ' 计算形状右侧位置:找到结束日期列 + 当天内的时间偏移
        p = 9
        Do Until ws.Cells(1, p).Value = DateValue(dtEnd)
            p = p + 1
        Loop
        Dim endTimeRatio As Double
        endTimeRatio = (dtEnd - DateValue(dtEnd)) / 1
        Dim dRight As Double
        dRight = ws.Cells(1, p).Left + (endTimeRatio * dDayWidth)
        
        ' 计算形状宽度
        dWidth = dRight - dLeft
        
        ' 创建形状
        sName = "Scheduled" & X
        Call DynamicBox(dLeft, dtop, dWidth, dHeight, sName)
        
        ActiveCell.Offset(1, 0).Select
        X = X + 1
    Loop
End Sub

Sub DynamicBox(dLeft As Double, dtop As Double, dWidth As Double, dHeight As Double, sName As String)
    Dim shp As Shape
    Set shp = ActiveSheet.Shapes.AddShape(msoShapeFlowchartProcess, dLeft, dtop, dWidth, dHeight)
    
    If InStr(sName, "Scheduled") > 0 Then
        shp.Fill.ForeColor.RGB = RGB(0, 255, 0)
    Else
        shp.Fill.ForeColor.RGB = RGB(0, 0, 255)
    End If
    
    shp.Fill.Solid
    shp.Fill.Visible = msoTrue
    shp.Name = sName
End Sub

内容的提问来源于stack exchange,提问作者Alex Triece

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 05:27:37