Переставить набор картинок VBA

#excel #vba

#excel #vba

Вопрос:

Я пытаюсь упорядочить набор данных на листе Excel. Я очень новичок в vba, поэтому прошу прощения, если я не очень хорошо объясняю свою конечную цель…С этим я вслепую нащупываю в темноте! В основном я пытаюсь сделать следующее: пользователь вводит некоторые данные в разные ячейки и изображение, связанное с данными. Есть ячейка, в которую они вводят порядок, в котором они хотели бы отображать данные (см. Номер ошибки в столбце A на рисунке ниже (скриншот рабочего листа)). Скриншот рабочего листа

Так, например, — они будут вводить информацию для 2 разных «ошибок», и они расположены в порядке 2, 1. (Это упрощенный пример — будет до 80 «ошибок») При нажатии кнопки «Упорядочить ошибки» данные будут переставлены. У меня нет проблем с перестановкой текста, и это работает отлично. У меня возникла проблема с захватом изображения, связанного с данными. Я перепробовал множество разных способов сделать это и нахожусь в полной растерянности.

Ниже приведен мой код для перестановки — то, что я сделал, это создал объект ‘fault’. При нажатии кнопки «Упорядочить ошибки» создается массив ошибок, они упорядочиваются в соответствии с номером ошибки, а затем вставляются в нужное место. В этом подразделе вызываются подразделы «Переместить изображение большего размера» / «Переместить изображение меньшего размера».

Я знаю, что мой код многословен, но я добавляю его для ясности. Соответствующий раздел находится в конце — либо подраздел ‘MoveLargerImage’ / ‘MoveSmallerImage’. Как только я получу один рабочий, я почти уверен, что смогу заставить работать второй, поскольку он делает то же самое. Любые указания в правильном направлении очень ценятся.

Благодарю вас!

 Public Sub ReArrangeFaults()

'Set up a counter to hold the array length
Dim arrayLength As Integer
arrayLength = 0

'Set counter to indicate cells
Dim i As Integer
i = 6

'Set a counter
Dim counter As Integer
counter = 0

'*******************Loop through to count faults********************************
While Len(Worksheets("Analysis").Cells(i, 1)) <> 0
arrayLength = arrayLength   1
i = i   30
'MsgBox "Count at: " amp; arrayLength
Wend
'*******************Loop end********************************

'Reset i
i = 6

'*****Set up an array in which faults will be held and loop through to populate it*****
Dim faultArray() As cFault
ReDim faultArray(0 To arrayLength) As cFault
Dim oShape As Shape
Dim shapeName As String

While counter < arrayLength

    'Create a fault class and assign all variables
    Dim f As cFault
        f.faultNumber = Worksheets("Analysis").Cells(i, 1)
        f.Priority = Worksheets("Analysis").Cells(i, 3)
        f.Location = Worksheets("Analysis").Cells(i   1, 3)
        f.EquipmentID = Worksheets("Analysis").Cells(i   2, 3)
        f.Component = Worksheets("Analysis").Cells(i   3, 3)
        f.FigureNumber = Worksheets("Analysis").Cells(i   4, 3)
        f.AnalysisParagraph = Worksheets("Analysis").Cells(i   11, 2)
        f.ActionRequired = Worksheets("Analysis").Cells(i   21, 2)
        f.StartPosition = Worksheets("Analysis").Cells(i, 1)

    faultArray(counter) = f
    'MsgBox "Count at: " amp; counter
    i = i   30 'To set where to find data
    counter = counter   1 'To increment loop
    Wend
'*******************End array creation********************************

'*******************Sort array according to fault number**************
Dim SrtTemp As cFault
Dim m As Long
Dim n As Long

    For m = 0 To arrayLength - 1
         For n = m   1 To arrayLength - 1
             If faultArray(m).faultNumber > faultArray(n).faultNumber Then
                 SrtTemp = faultArray(n)
                 faultArray(n) = faultArray(m)
                 faultArray(m) = SrtTemp
             End If
         Next n
     Next m
'*******************End of sorting algorithm*************************

'*******************Loop through array and paste objects**************
counter = 0
i = 6
While counter < arrayLength

        Worksheets("Analysis").Cells(i, 1) = faultArray(counter).faultNumber
        Worksheets("Analysis").Cells(i, 3) = faultArray(counter).Priority
        Worksheets("Analysis").Cells(i   1, 3) = faultArray(counter).Location
        Worksheets("Analysis").Cells(i   2, 3) = faultArray(counter).EquipmentID
        Worksheets("Analysis").Cells(i   3, 3) = faultArray(counter).Component
        Worksheets("Analysis").Cells(i   4, 3) = faultArray(counter).FigureNumber
        'Worksheets("Overview").Range("G10").Formula = "=COUNTIF('List of     Leakages'!A2:A500,""<>"")"
        Worksheets("Analysis").Cells(i   4, 3).Formula = "=A" amp; CStr(i)
        Worksheets("Analysis").Cells(i   11, 2) = faultArray(counter).AnalysisParagraph
        Worksheets("Analysis").Cells(i   21, 2) = faultArray(counter).ActionRequired
        MoveLargeImage faultArray(counter).StartPosition,     faultArray(counter).faultNumber
        MoveSmallImage faultArray(counter).StartPosition,     faultArray(counter).faultNumber

counter = counter   1
i = i   30
Wend

'*******************End Arranging objects*****************************

    MsgBox "Organised!"
End Sub
  

Вот подраздел ‘MoveLargerImage’:

 Sub MoveLargeImage(i As Integer, j As Integer)

    Dim r As Range
    Set r = Range("J" amp; CStr(i) amp; ":J" amp; CStr(i   29))
    Dim oShape As Shape
    Dim shapeName As String
    shapeName = "nothing"
    Dim p As Integer
    If j > 1 Then
    p = ((j - 1) * 30)   8
    End If
    If j = 1 Then
    p = 8
    End If
    Dim count As Integer
    count = 0

    For Each oShape In ActiveSheet.Shapes
    If (oShape.Type = msoPicture) Then
            If Not Intersect(ActiveSheet.Range("J" amp; CStr(i) amp; ":J" amp; CStr(i   29)),  _
                                           oShape.TopLeftCell) Is Nothing Then
                oShape.Name = "LargeImage" amp; i
                shapeName = oShape.Name
            End If
    End If
    Next oShape
    If Not shapeName = "nothing" Then
        Sheets("Analysis").Shapes(shapeName).Cut
        Sheets("Analysis").Paste Sheets("Analysis").Range("J" amp; CStr(p) amp; ":J" amp; CStr(p   19))
    End If
End Sub
  

И вот подраздел ‘MoveSmallerImage’ (практически тот же желаемый результат — просто другое позиционирование)

 Sub MoveSmallImage(i As Integer, j As Integer)

    Dim r As Range
    Set r = Range("E" amp; CStr(i) amp; ":E" amp; CStr(i   29))
    Dim oShape As Shape
    Dim shapeName As String
    shapeName = "nothing"
    Dim p As Integer
    If j > 1 Then
    p = ((j - 1) * 30)   6
    End If
    If j = 1 Then
    p = 6
    End If
    Dim count As Integer
    count = 0

    For Each oShape In ActiveSheet.Shapes
    If Not Intersect(ActiveSheet.Range("E" amp; CStr(i) amp; ":E" amp; CStr(i   10)), _
                                          oShape.TopLeftCell) Is Nothing Then
            oShape.Name = "SmallImage" amp; i
            shapeName = oShape.Name
            End If
            Next oShape
            If Not shapeName = "nothing" Then
    Sheets("Analysis").Shapes(shapeName).Cut
    Sheets("Analysis").Paste Sheets("Analysis").Range("E" amp; CStr(p) amp; ":E" amp; CStr(p   7))
    End If
End Sub
  

Спасибо!!

Комментарии:

1. В чем вопрос? Как переместить фигуру? Измените . Сверху и . Левое свойство объекта shape.

2. Спасибо, я понимаю, что свойства необходимо изменить, но то, что я пытаюсь сделать, это создать массив объектов fault и изменить их порядок. После того, как они будут изменены, они будут перемещены в их новые местоположения. В принципе, я не понимаю, как это сделать, это найти изображение в определенном месте, чтобы вырезать / вставить или изменить свойства. Например. Я знаю, что в ячейке E6 будет изображение с верхним левым углом. Чего я не могу сделать, так это захватить это изображение!!

Ответ №1:

Я думаю, что лучший способ — записывать имена изображений одновременно с заполнением класса ошибок. Поскольку имя каждого изображения уникально, вы будете знать, какие изображения идут с какой ошибкой. Перебор фигур — это единственный способ связать фигуру с диапазоном, так что вы правильно поняли эту часть. Добавьте в свой класс два свойства: SmallImageName и LargeImageName. Затем проверьте эту перезапись.

Во-первых, основная процедура

 Public Sub ReArranageFaults2()

    Dim colFaults As Collection
    Dim i As Long
    Dim lLastRow As Long
    Dim sh As Worksheet
    Dim clsFault As CFault
    Dim rStart As Range

    Set sh = ThisWorkbook.Worksheets("Analysis")
    lLastRow = sh.Cells(sh.Rows.count, 1).End(xlUp).Row
    Set colFaults = New Collection

    'Loop through the worksheet skipping every 30 rows
    'and fill an instance of CFault
    'then add that object to the collection
    For i = 5 To lLastRow Step 30
        Set clsFault = New CFault
        clsFault.FillFromRange sh.Cells(i, 1).Resize(30, 10)
        colFaults.Add clsFault
    Next i

    'sort the collection by fault number
    SortCollection colFaults

    'Now loop through the collection and write
    'the faults back to the worksheet
    Set rStart = sh.Cells(5, 1)
    For i = 1 To colFaults.count
        Set clsFault = colFaults(i)
        With rStart.Offset((i - 1) * 30, 0)
            .Offset(1, 0).Value = clsFault.FaultNumber
            .Offset(1, 2).Value = clsFault.Priority
            .Offset(2, 2).Value = clsFault.Location
            .Offset(3, 2).Value = clsFault.EquipmentID
            .Offset(4, 2).Value = clsFault.Component
            .Offset(5, 2).Value = clsFault.FigureNumber
            .Offset(12, 1).Value = clsFault.AnalysisParagraph
            .Offset(22, 1).Value = clsFault.ActionRequired
            sh.Shapes(clsFault.SmallImageName).Left = .Offset(1, 4).Left
            sh.Shapes(clsFault.SmallImageName).Top = .Offset(1, 4).Top
            sh.Shapes(clsFault.LargeImageName).Left = .Offset(3, 9).Left
            sh.Shapes(clsFault.LargeImageName).Top = .Offset(3, 9).Top
        End With
    Next i

End Sub
  

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

 Public Sub FillFromRange(rRng As Range)

    Dim shp As Shape

    'Fill the properties
    Me.FaultNumber = rRng.Cells(2, 1).Value
    Me.Priority = rRng.Cells(2, 3).Value
    Me.Location = rRng.Cells(3, 3).Value
    Me.EquipmentID = rRng.Cells(4, 3).Value
    Me.Component = rRng.Cells(5, 3).Value
    Me.FigureNumber = rRng.Cells(6, 3).Value
    Me.AnalysisParagraph = rRng.Cells(13, 2).Value
    Me.ActionRequired = rRng.Cells(23, 2).Value

    'Loop through all the shapes on the sheet
    For Each shp In rRng.Parent.Shapes
        'If it's within the range, it's either the large or the small
        If Not Intersect(shp.TopLeftCell, rRng) Is Nothing Then

            'If I haven't assigned a small yet, assume the first image
            'is the small image
            If Len(Me.SmallImageName) = 0 Then
                Me.SmallImageName = shp.Name
            Else 'I've already processed one image and assume it was the small

                'If the already processed image is bigger than the current image
                'then move small to large and save the current as small
                If rRng.Parent.Shapes(Me.SmallImageName).Width > shp.Width Then
                    Me.LargeImageName = Me.SmallImageName
                    Me.SmallImageName = shp.Name
                Else 'If the alread processed image is smaller than the current
                    'image, then it's in the right place, and we have only to
                    'store the large
                    Me.LargeImageName = shp.Name
                End If
            End If
        End If
    Next shp

End Sub
  

И, наконец, процедура сортировки коллекции. Я предпочитаю коллекцию массиву, если только я не делаю что-то конкретное, для чего требуется массив. Используя коллекцию, вы просто добавляете в нее по мере необходимости, вместо того, чтобы заранее определять размеры.

 Public Sub SortCollection(ByRef col As Collection)

    Dim i As Long
    Dim j As Long
    Dim obj As Object

    For i = 1 To col.count - 1
        For j = i To col.count
            If col.Item(i).FaultNumber > col.Item(j).FaultNumber Then
                Set obj = col.Item(i)
                col.Remove i
                col.Add obj, , , j - 1
            End If
        Next j
    Next i

End Sub
  

Комментарии:

1. Спасибо!!!!! Это в основном то, что я изначально пытался сделать, но поскольку я на самом деле не работал с vb, я понятия не имел, как к этому подойти. Большое спасибо за такую детализацию, вы предотвратили множество седых волос 🙂