VBA копировать / вставить - PullRequest
       34

VBA копировать / вставить

0 голосов
/ 07 апреля 2020

У меня есть 80 машин и 80 вкладок в книге Excel. На каждой вкладке есть список дат одного месяца в столбце (A) с записью в столбце (C) того, сколько часов накопления машина отработала в течение месяца. Таким образом, ежедневное увеличение составляет от 0 (если машина вышла из строя) до 24.

Я ищу решение для автоматизации записи в тех случаях, когда ежедневное добавление равно нулю часов. В этом случае накопленная сумма за предыдущий день должна быть скопирована в ячейку следующего дня в столбце (C).

Я уверен, что это довольно просто, но не могу разобраться, и я не нашел подобного вопроса, который задавался ранее в сети.

Заранее спасибо

Ian

1 Ответ

0 голосов
/ 08 апреля 2020

Код ниже позволит вам ввести общее количество часов для каждого дня. Это добавит число, которое вы вводите к предыдущему итогу, и заменит вашу запись на сумму. Вы можете ввести ноль, в результате чего будет получен новый итог, который не изменился по сравнению с предыдущим. После ввода код перейдет к следующему листу, выбрав ячейку для заполнения на день и выделив зеленую дату. Если запись уже есть, выделение будет розовым.

Если в предыдущие дни не было записей, предполагается, что часы не отработаны, и запись завершена соответственно над строкой, в которую вы вводите текущие часы. Нельзя вводить отрицательные числа часов или часов в превышение 24. Вы не можете вводить в ячейки, где есть записи ниже ячейки, которую вы хотите изменить, даже если эта ячейка пуста.

Код состоит из двух компонентов. Первый взнос должен go в стандартный модуль кода. Это тот, который не существует в вашей книге. Найдите способ добавить модуль. Если его имя похоже на Module1, это правильно. Вставьте код ниже в него. Я бы предпочел переименовать модуль (возможно, как «STO_200408»), но в этом нет необходимости.

Option Explicit

Enum Nws                                ' worksheet navigation
    ' Variatus @STO 08 Apr 2020
    NwsFirstDataRow = 2                 ' modify if your data don't start in row 2
    NwsDate = 1                         ' date column: 1 identifies column A
    NwsHours = 3
End Enum

Sub WorksheetActivate(Ws As Worksheet)
    ' Variatus @STO 08 Apr 2020

    Dim Rng As Range

    Set Rng = Ws.Columns(NwsDate).Find(Date, , , xlWhole)
    If Rng Is Nothing Then
        MsgBox "I didn't find today's date on the """ & _
               Ws.Name & """." & vbCr & _
               "It may have been entered using an invalid format.", _
               vbInformation, "Missing or invalid date"
    Else
        WorksheetDeactivate Ws              ' remove existing highlight
        With Rng.Resize(1, NwsHours)
            .Interior.Color = IIf(.Cells(NwsHours).Value, 13431551, 14348258)
            .Cells(NwsHours).Select
        End With
    End If
End Sub

Function WorksheetChange(Target As Range) As Boolean
    ' Variatus @STO 08 Apr 2020
    ' return Not True if accumulator couldn't be set

    Dim Rng As Range
    Dim Hours As Double
    Dim Accu As Double
    Dim R As Long

    With Target
        If .Cells.CountLarge > 1 Then Exit Function

        With .Worksheet
            R = .Cells(.Rows.Count, NwsDate).End(xlUp).Row
            Set Rng = .Range(.Cells(NwsFirstDataRow, NwsHours), _
                             .Cells(R, NwsHours))
        End With

        If Not Application.Intersect(Target, Rng) Is Nothing Then
            Application.EnableEvents = False
            If GetAccu(Accu, Target.Worksheet, .Row) Then
                Hours = Val(.Value)
                ' modify if you record time hours:-
                If (Hours > 24) Or (Hours < 0) Then
                    MsgBox "Please enter a positive value smaller or equal to 24 hours.", _
                           vbExclamation, "Invalid number of hours"
                    GoTo SideExit
                End If
                .Value = Accu + Val(.Value)
                WorksheetChange = True
            Else
SideExit:
                .Select
            End If
            Application.EnableEvents = True
        End If
    End With
End Function

Sub WorksheetDeactivate(Ws As Worksheet)
    ' Variatus @STO 08 Apr 2020

    Dim Rng As Range

    With Ws
        Set Rng = .Range(.Cells(NwsFirstDataRow, NwsDate), _
                         .Cells(.Rows.Count, NwsDate).End(xlUp) _
                                .Offset(0, NwsHours - 1))
        Rng.Interior.Pattern = xlNone
    End With
End Sub

Private Function GetAccu(Accu As Double, _
                         Ws As Worksheet, _
                         ByVal Rt As Long) As Boolean
    ' Variatus @STO 08 Apr 2020
    ' 'Accu' is a return variable
    ' return Not True if no b/f total could be determined

    Dim R As Long

    With Ws
        If .Cells(.Rows.Count, NwsHours).End(xlUp).Row > Rt Then
            MsgBox "There may be no entries in the 'Hours' column" & vbCr & _
                   "below the entry now being processed." & vbCr & _
                   "Remove existing entries and repeat.", _
                   vbExclamation, "Record irregularity"
        Else
            GetAccu = True
            With .Cells(NwsFirstDataRow, NwsHours)
                If Len(.Value) = 0 Then .Value = 0
            End With

            R = Rt
            Do
                R = R - 1
                With .Cells(R, NwsHours)
                    If Len(.Value) Then
                        Accu = Val(.Value)
                        Exit Do
                    End If
                End With
            Loop While R > NwsFirstDataRow

            For R = (R + 1) To (Rt - 1)
                .Cells(R, NwsHours).Value = Accu
            Next R
        End If
    End With
End Function

Sub GotoNextSheet()
    ' Variatus @STO 08 Apr 2020

    Dim Idx As Integer

    Idx = ActiveSheet.Index + 1
    If Idx > Worksheets.Count Then Idx = 1
    Worksheets(Idx).Activate
End Sub

Далее найдите модуль кода, принадлежащий листу, на котором вы храните часы для машины. Если дважды щелкнуть имя рабочего листа в проводнике проектов VB Editor, откроется правильный лист кода. Вставьте код, который вы найдете ниже, в этот лист.

Option Explicit

Private Sub Worksheet_Activate()
    ' Variatus @STO 08 Apr 2020
    WorksheetActivate ActiveSheet
End Sub

Private Sub Worksheet_Change(ByVal Target As Range)
    ' Variatus @STO 08 Apr 2020
    If WorksheetChange(Target) Then GotoNextSheet
End Sub

Private Sub Worksheet_Deactivate()
    ' Variatus @STO 08 Apr 2020
    WorksheetDeactivate ActiveSheet
End Sub

Этот код связывает то, что происходит на этом листе, с кодом в Module1. Теперь вы можете сделать записи в столбце C этого листа и увидеть действие. Я предлагаю вам сделать это, чтобы проверить и код, и его местоположение.

Поскольку вы хотите выполнить действие на всех своих 80 листах, один и тот же код должен быть вставлен в лист кодов для всех 80. Обратите внимание, что код будет скопирован в копию листа, если вы создаете его, используя правую кнопку мыши на вкладке, но не если вы выбираете весь лист и вставляете его на новый лист. Таким образом, чтобы начать новый месяц, вы можете создавать копии из шаблона, который включает в себя код, и вам не придется беспокоиться о копировании кода отдельно.

Как только все ваши 80 листов будут иметь код события, для которого вы установили go. Обратите внимание, что код будет переходить к следующему листу после каждой записи, а l oop - к первому при попадании в последний. Вы узнаете, когда закончите, когда увидите, что цвет выделения изменился на розовый, а выбранная ячейка уже содержит сумму.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...