Тема: Актуально. Получение списка блоков в Excelle(VB)

Приветствую знатоков VB!
Есть у меня на Visual Basice программка.
Public Sub GetCensus()
Dim oAutoCad As Object
Dim oModelSpace As Object
Dim wksCensus As Worksheet
Dim intI As Integer
' Get the open instance of AutoCAD
Set oAutoCad = GetObject(, "AutoCAD.Application")
If Not oAutoCad Is Nothing Then
Set wksCensus = Worksheets("Census")
wksCensus.Range("A2", "E1000").Clear
Set oModelSpace = oAutoCad.ActiveDocument.ModelSpace
wksCensus.Cells(3, 6) = oAutoCad.ActiveDocument.Name
wksCensus.Cells(4, 6) = oModelSpace.Count & " total objects"
For intI = 0 To oModelSpace.Count — 1
With oModelSpace.Item(intI)
wksCensus.Cells(intI + 2, 1) = .EntityName
wksCensus.Cells(intI + 2, 2) = .EntityType
wksCensus.Cells(intI + 2, 3) = .Color
wksCensus.Cells(intI + 2, 4) = .Layer
wksCensus.Cells(intI + 2, 5) = .Linetype
End With
Next intI
End If
End Sub
Она вставляет в Excell столбцы EntityName, EntityType и прочее из открытого Acadoвского файла при активации макроса в Excelle. А вот может ли кто-нибудь разбирающийся в VB ее чуть подправить, чтобы в Excell переносились названия блоков(нединамических) и их количество?
И, конечно, поделиться результатом! :)

Re: Актуально. Получение списка блоков в Excelle(VB)

> Serg7
Оба файла должны быть открыты
В файле Эксель должен быть лист "Census"

Option Explicit
Dim thisdrawing As Object
Dim blkVar()
Dim total As Long
Public Sub GetCensus()
Dim oAutoCad As Object
Dim oModelSpace As Object
Dim wksCensus As Worksheet
Dim intI As Integer
' Get the open instance of AutoCAD
Set oAutoCad = GetObject(, "AutoCAD.Application")
If Not oAutoCad Is Nothing Then
Set thisdrawing = oAutoCad.ActiveDocument
Call CountBlocks
Set wksCensus = Worksheets("Census")
wksCensus.Range("A2", "E1000").Clear
'Set oModelSpace = oAutoCad.ActiveDocument.ModelSpace
For intI = LBound(blkVar, 1) To UBound(blkVar, 1)
'With oModelSpace.Item(intI)
wksCensus.Cells(intI + 2, 1) = blkVar(intI, 0)
wksCensus.Cells(intI + 2, 2) = blkVar(intI, 1)
total = total + blkVar(intI, 1)
'wksCensus.Cells(intI + 2, 3) = .Color
'wksCensus.Cells(intI + 2, 4) = .Layer
'wksCensus.Cells(intI + 2, 5) = .Linetype
'End With
Next intI
wksCensus.Cells(3, 3) = oAutoCad.ActiveDocument.Name
wksCensus.Cells(4, 3) = total & " total blocks"
End If
End Sub
Private Sub CountBlocks()
' by Fatty T.O.H ()2007 * all rights removed
' not working with dynamic blocks
  Dim oBlocks As AcadBlocks
  Dim oBlock As AcadBlock
  Dim oBlkRef As AcadBlockReference
  Dim oEnt As AcadEntity
  Dim fType(1) As Integer, fData(1)
  Dim oSset As AcadSelectionSet
  Dim blkName As String
  Dim iCount As Integer
  Dim dxfCode, dxfData
  Dim tmp(1)
  Dim blkColl As New Collection
  fType(0) = 0: fData(0) = "INSERT"
  fType(1) = 2
On Error GoTo Err_Trapp
          With thisdrawing.SelectionSets
               While .Count > 0
                    .Item(0).Delete
               Wend
          End With
Set oSset = thisdrawing.SelectionSets.Add("$BlkInstances$")
oSset.Clear
Set oBlocks = thisdrawing.Blocks
  'loop through all block definitions
  For Each oBlock In oBlocks
  If oBlock.IsLayout = False And oBlock.IsXRef = False Then
  blkName = oBlock.Name
  fData(1) = blkName
  dxfCode = fType
  dxfData = fData
  oSset.Select acSelectionSetAll, , , dxfCode, dxfData
  iCount = 0
  For Each oBlkRef In oSset
  iCount = iCount + 1
    Next oBlkRef
    tmp(0) = blkName: tmp(1) = iCount
    If iCount > 0 Then
    blkColl.Add tmp
    End If
    Erase tmp
    oSset.Clear
    End If
  Next oBlock
  Debug.Print "Used Block Definitions: " & blkColl.Count
  oSset.Delete
  Set oSset = Nothing
  ' convert collection to two-dimensional array
  Dim i As Long, j As Long
  ReDim blkVar(blkColl.Count - 1, 1)
  For i = 1 To blkColl.Count
  blkVar(i - 1, 0) = blkColl.Item(i)(0)
  blkVar(i - 1, 1) = blkColl.Item(i)(1)
  Next
Err_Trapp:
If Err Then
 MsgBox "Error occured:" & vbNewLine & Err.Description
 End If
End Sub

~'J'~

Re: Актуально. Получение списка блоков в Excelle(VB)

Спасибо!
Не ожидал, что так быстро можно написать программу, и не ожидал, что она будет такая большая. Ведь исходная гораздо меньше, а 4 столбца заполняет какими-то деталями из чертежа.
Но, программа не заработала. Понимаете, в этом файле есть прямо в excellевской таблице кнопка, после нажатия на которую и должна заполняться таблица. Я в файле заменил исходную программу этой, но при нажатии на кнопку открывается редактор VB с текстом программы да еще небольшое окошечко, которое сообщает:
«ошибка компиляции
не описан определяемый пользователем тип».
При этом  желтым выделена строка программы
PRIVATE SUB CountBlocks ()  ,
а синим  oBlocks As AcadBlocks в строке
DIM oBlocks As AcadBlocks
Можно ли как-то заставить ее работать нормально?
Возможно, у меня очень старый Excell и поэтому он не так, как надо, подхватывает программу?

Re: Актуально. Получение списка блоков в Excelle(VB)

> Serg7
Посмотри в окне редактора:
Tools->References->AutoCAD 200X Type Library
у тебя должна быть твоя версия АвтоКАДа в
этом списке
Кстати, какая версия, я тестировал на 2008
~'J'~

Re: Актуально. Получение списка блоков в Excelle(VB)

> Serg7
Ссылка на файл:
http://webfile.ru/1833091
~'J'~

Re: Актуально. Получение списка блоков в Excelle(VB)

Fatty! Гутен абенд!  :)
Отвечаю на первой вопрос(прошу не смеяться)- у меня ACAD14.
На более крутую версию зарплаты не хватает  :) да и пока устраивает.

Re: Актуально. Получение списка блоков в Excelle(VB)

> Serg7
Я не понял, что не работает у тебя?
~'J'~

Re: Актуально. Получение списка блоков в Excelle(VB)

Я уже догадываюсь, что с ACADом 14ым ваша программа работать не будет, но ведь исходная  на VB написана и  что-то успешно скидывает в таблицу Excell. Неужели ей не все равно, что туда записывать - список блоков с количеством или типы и цвета линий? Давайте поробуем разобраться - тогда не только мне, а  многим другим (у кого нет ACADa2008)эта программа пригодится, вместе мы ее доведем до ума(наверное).

Re: Актуально. Получение списка блоков в Excelle(VB)

Fatty!
При нажатии на виртуальную кнопку выдается сообщение об ошибке компиляции. Да я все написал в предыдущем сообщении.
Что-то ему не нравится. Он не умеет мыслить категориями A2008го  :)
Если не против, могу прислать сам файл для тестирования.

Re: Актуально. Получение списка блоков в Excelle(VB)

> Serg7
Скинь файл только я не уверен что смогу
под 14-ю версию что-нибудь придумать
~'J'~

Re: Актуально. Получение списка блоков в Excelle(VB)

Fatty!
Файлы скинул. И еще меня очень интересует вопрос, можно ли, имея готовый файл xls(в котором есть 2 столбца среди прочих с именами блоков и их количествами)заставить количества подсчитанных в ACADe блоков материализовываться прямо в таблице в столбце,предназначенном для количеств, в ячейке, соответствующей его имени?
В теме про LISP я тоже про это спрашивал,но пока никто этим не заинтересовался.Надо будет напомнить.Думаю,что для настоящих спецов это не так сложно устроить.

Re: Актуально. Получение списка блоков в Excelle(VB)

> Serg7
Попробуй с кнопки вызывать такую процедуру
(пока на твоих не проверял)

Option Explicit
Dim oAutoCad As Object
Dim aDoc As Object
Dim oModelSpace As Object
Dim wksCensus As Object
Dim intI As Long
Dim total As Long
Sub countB()
Dim arrBlk() As Variant
Dim i As Long, j As Long
Dim cnt As Integer, k As Integer
Dim gotcha As Boolean
Set oAutoCad = GetObject(, "AutoCAD.Application")
If Not oAutoCad Is Nothing Then
  Set aDoc = oAutoCad.ActiveDocument
End If
cnt = aDoc.ModelSpace.count
    i = 0: total = 0
    For k = 0 To cnt - 1
        If aDoc.ModelSpace.Item(k).ObjectName = _
"AcDbBlockReference" Then
            j = 1
            gotcha = False
            While j <= i
                If arrBlk(0, j) = _
                   aDoc.ModelSpace.Item(k).Name Then
                    arrBlk(1, j) = arrBlk(1, j) + 1
                    j = i
                    gotcha = True
                End If
                j = j + 1
            Wend
            If Not gotcha Then
                i = i + 1
                ReDim Preserve arrBlk(2, i)
                arrBlk(0, i) = aDoc.ModelSpace.Item(k).Name
                arrBlk(1, i) = 1
            End If
        End If
    Next k
ReDim arrData(0 To UBound(arrBlk, 2) - 1, 0 To 1)
For k = 1 To UBound(arrBlk, 2)
    arrData(k - 1, 0) = arrBlk(0, k)
    arrData(k - 1, 1) = arrBlk(1, k)
Next k
Set wksCensus = ThisWorkbook.Worksheets("Census")
With wksCensus
  .Range("A2", "E1000").Clear
  .Range("1:1").Font.Bold = True
  .Cells(1, 1).Value = "Block Name"
  .Cells(1, 2).Value = "Quantity:"
  .Cells(1, 3).Value = "Total:"
For intI = LBound(arrData, 1) To UBound(arrData, 1)
  .Cells(intI + 2, 1).Value = arrData(intI, 0)
  .Cells(intI + 2, 2).Value = arrData(intI, 1)
  total = total + arrData(intI, 1)
Next intI
  .Cells(3, 3).Value = oAutoCad.ActiveDocument.Name
  .Cells(4, 3).Value = CStr(total) & " total blocks"
  .Range("A:C").Columns.AutoFit
End With
MsgBox "Holy crap, do you got it to work?!" & vbCr & "I can't believe it!"
Set aDoc = Nothing
Set oAutoCad = Nothing
End Sub

Возможно эту строчку :

If aDoc.ModelSpace.Item(k).ObjectName = _
"AcDbBlockReference" Then

надо будет проверять через EntityType
Насчет последнего вопроса - ничего не понял,
был бы пузырь под рукой, тогда бы может и въехал еще :)
~'J'~

Re: Актуально. Получение списка блоков в Excelle(VB)

Fatty!
Пока не проверил еще, но про последний вопрос могу сказать, что ты это, c пузырями-то поосторожнее, лучше совсем их отодвинь подальше, а то можно и того. :)
Я спрашиваю, можно ли подсчитанные блоки вставлять сразу в готовую таблицу Excell? Например, есть 5 столбцов,из них один пустой(туда должны вставляться количества блоков),следующий столбец содержит имена блоков, остадьные столбцы пусть содержат что угодно. Так вот, все находящиеся на чертеже AutoCADa блоки нужно вставить в столбец "количество" по их именам с сооветствующие ячейки. Например, блок с именем 100 встретился в чертеже 10раз, получается, что в первом столбце появляется "10" рядом со значением "100" из второго столбца. Т.е., мы как бы должны закрепить конкретную ячейку в Excelle за количеством повторения имени блока в AutoCADe. В состоянии ли современное программирование справиться с такой задачей?

Re: Актуально. Получение списка блоков в Excelle(VB)

> Serg7
Задача несложная но нет времени
Попробуй сам
Сначала собери информацию в коллекцию или массив:
- первый элемент - имя
- второй элемент количество
- и так далее для остальных блоков
Потом идешь в Эксель, сравниваешь значения из
столбца с именами блоков в цикле,
если совпадают, получаешь номер строки где
совпало
через фунцию Ofset добавляешь в другой столбец
количество (иторой элемент)
~'J'~

Re: Актуально. Получение списка блоков в Excelle(VB)

> Serg7
Вот пример:
В первом столбце имена блоков
в следующий будет вставляться количество

Option Explicit
Dim oAutoCad As Object
Dim aDoc As Object
Dim wksCensus As Object
Dim intI As Long
Dim total As Long
Sub AddCount()
Dim arrBlk() As Variant
Dim i As Long, j As Long
Dim cnt As Integer, k As Integer
Dim gotcha As Boolean
Set oAutoCad = GetObject(, "AutoCAD.Application")
If Not oAutoCad Is Nothing Then
  Set aDoc = oAutoCad.ActiveDocument
End If
cnt = aDoc.ModelSpace.Count
    i = 0: total = 0
    For k = 0 To cnt - 1
        If aDoc.ModelSpace.Item(k).EntityType = 7 Then
            j = 1
            gotcha = False
            While j <= i
                If arrBlk(0, j) = _
                   aDoc.ModelSpace.Item(k).Name Then
                    arrBlk(1, j) = arrBlk(1, j) + 1
                    j = i
                    gotcha = True
                End If
                j = j + 1
            Wend
            If Not gotcha Then
                i = i + 1
                ReDim Preserve arrBlk(2, i)
                arrBlk(0, i) = aDoc.ModelSpace.Item(k).Name
                arrBlk(1, i) = 1
            End If
        End If
    Next k
ReDim arrdata(0 To UBound(arrBlk, 2) - 1, 0 To 1)
For k = 1 To UBound(arrBlk, 2)
    arrdata(k - 1, 0) = arrBlk(0, k)
    arrdata(k - 1, 1) = arrBlk(1, k)
Next k
'Set wksCensus = ThisWorkbook.Worksheets("Census")
Set wksCensus = ThisWorkbook.Worksheets(1)
Dim cel As Object
For intI = LBound(arrdata, 1) To UBound(arrdata, 1)
With wksCensus.Range("A1:A1000")
Set cel = .Cells(intI + 1, 1)
If Not IsNull(Assoc(arrdata, cel.Value)) Then
       cel.Offset(, 1).Value = Assoc(arrdata, cel.Value)(1)
End If
End With
Next intI
MsgBox "Done!"
Set aDoc = Nothing
Set oAutoCad = Nothing
End Sub
Function Assoc(source() As Variant, match As Variant) As Variant
'' by Fatty T.O.H()2007 * all rights removed
    Dim elem
    Dim ret(1) As Variant
        Dim i
        i = -1
        For Each elem In source
        i = i + 1
            If (elem = match) Then
                ret(0) = elem: ret(1) = source(i, 1)
             Exit For
            End If
        Next
        Assoc = ret
End Function

~'J'~