Тема: Как программно сделать импорт блока из другого файла?

Здраствуйте!
Имеется файл 1.dwg (не открыт) в кот находиться блок под именем "А". Как программно вставить указанный блок в любой активный чертеж, не открывая файла.

Re: Как программно сделать импорт блока из другого файла?

> Илья
Если непременно надо, чтобы чертёж с блоком "А" НЕ открывался в Акаде, тогда путь один - писать приложение, непосредственно читающее с диска dwg-чертёж. В этом поможет http://www.opendwg.org, раздел download, там есть бесплатные спецификации вплоть до 2000 версии включительно. Но если вы в здравом рассудке:), то лучше ОТКРОЙТЕ файл, содержащий блок "А", а дальше вам поможет https://www.caduser.ru/forum/topic14682.html, там, правда, на Visual Lispe, но я думаю, вы этот язык уже знаете:).

Re: Как программно сделать импорт блока из другого файла?

...Visual Lispe, но я думаю, вы этот язык уже знаете

Интересно из чего это следует?
Я программирую на VB6. Так уж сложилось, что я ег оизучаю со школьной скамьи.
Когда-то видел такую запись InsertBlock.Databases...
Но в синтаксисе не могу разобраться.
В принципе должна реализовываться такая ситуация.
Если в активный чертеж вставить другой чертеж (в кот имеет блоки), а затем его удалить, то в список имеющихся блоков будут занесены все блоки из вставленного (а затем удаленного) чертежа.
Можно конечно реализовать ситуацию с загрузкой нужного чертежа (но без его отображения) и работать через команды Select и Paste, но это будет загружать буфер обмена.
Хотя подойде и этот вариант.

Re: Как программно сделать импорт блока из другого файла?

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

Это очень грязный приём. Лично я предлагаю через команду _WBLOCK (в той ветке https://www.caduser.ru/forum/topic14682.html всё подробно описано). Извините, что не могу дать рекомендацию по VB, сейчас нет времени.

Re: Как программно сделать импорт блока из другого файла?

Это очень грязный приём.

Вот уж не думал, что  в программировании есть такое понятие.

Re: Как программно сделать импорт блока из другого файла?

> Илья
Сейчас нашёл свободное время, вот наваял:)
Инструкции:
1.открыть новый чертёж, alt-F11 (надеюсь, знаешь:))
2.создать в проекте новый модуль (не класс!), оставить название по умолчанию и вклеить туда этот код:

Attribute VB_Name = "Module1"
Option Explicit
Const lib_name = "library.dwg" 'название файла-библиотеки
Const temp_file_path = "c:\" 'полный путь до временного файла
Public blk_name As String 'имя выбранного юзером блока
Sub head()
  Dim lib As AcadDocument
  Dim i As Integer
  Dim error_msg As String
  Set lib = Nothing
  error_msg = "Библиотечный файл  " & lib_name & "  не открыт"
  For i = 0 To AcadApplication.Documents.Count - 1
    If AcadApplication.Documents.Item(i).Name = lib_name Then
      Set lib = AcadApplication.Documents.Item(i)
    End If
  Next i
  If ActiveDocument.Name = lib_name Then
    error_msg = "Библиотечный файл  " & lib_name & "  не должен быть активным документом"
    Set lib = Nothing
  End If
  If lib Is Nothing Then
    MsgBox error_msg
    Else
    insert_block_from_library lib
  End If
End Sub
Private Sub insert_block_from_library(lib As AcadDocument)
  Dim blk As AcadBlock
  Dim i As Integer
  Dim already_present As Boolean
  Dim user_doc As AcadDocument
  Dim old_filedia As Integer
  UserForm1.ListBox1.Clear
  For Each blk In lib.Blocks
    If Not (Left(blk.Name, 1) = "*") Then UserForm1.ListBox1.AddItem blk.Name
  Next blk
  blk_name = ""
  UserForm1.show
  If blk_name = "" Then
      MsgBox "Не был выбран блок"
    Else
      For i = 0 To ActiveDocument.Blocks.Count - 1
        If ActiveDocument.Blocks.Item(i).Name = blk_name Then
          ActiveDocument.SendCommand "_.-insert" & vbCr & blk_name & vbCr
          already_present = True
        End If
      Next i
      If Not already_present Then
        Set user_doc = ActiveDocument
        old_filedia = lib.GetVariable("FILEDIA")
        lib.SetVariable "FILEDIA", 0
        lib.SendCommand "_.-wblock" & vbCr & temp_file_path & blk_name & ".dwg" & vbCr & blk_name & vbCr
        lib.SetVariable "FILEDIA", old_filedia
        user_doc.SendCommand "_.-insert" & vbCr & temp_file_path & blk_name & ".dwg" & vbCr
      End If
  End If
End Sub

3. создать в проекте форму, оставить имя по умолчанию, создать на ней листбокс (НЕ комбобокс!), оставить ему имя по умолчанию, щёлкнуть по нему мышой и добавить следующий код:

Option Explicit
Private Sub ListBox1_Change()
  If Me.ListBox1.ListCount > 0 Then Module1.blk_name = Me.ListBox1.Value
  Me.Hide
End Sub

На этом всё. Можно создать в меню на тулбаре графическую кнопку с макрокодом:

^C^C_.-vbarun;head;

Теперь "руководство пользователя".
1. должен быть открыт чертёж с именем library.dwg (храниться он может в любом месте, хоть на сервере), в котором в пространстве модели определены несколько блоков. При вызове макроса этот чертёж не должен быть активен!
2. юзер должен работать с любыми другими чертежами, и, когда ему захочется, вызывать макрос "head" (можно через графическую кнопку меню на тулбаре). Можно также редактировать как угодно чертёж-библиотеку library.dwg, но работая в ней, повторяю, вызывать макрос нельзя (хотя эта ситуация нормально обрабатывается в макросе и не приводит к краху системы:))
3. важное замечание: при вставке блока в юзерский чертёж макрос сначала ищет такой блок в этом же файле, и только если не находит, вставляет из файла-библиотеки. Это значит, что если в библиотеке более свежие блоки, то юзеру надо удалить все вхождения этих блоков в своём чертеже и сделать команду PURGE, чтобы избавиться от старых определений блоков. После этого при первой же вставке блока через макрос, блок будет не найден в текущем чертеже и взят уже из библиотеки, более свежий. В принципе, это тоже несложно автоматизировать:).

Re: Как программно сделать импорт блока из другого файла?

Ой, строка Attribute VB_Name = "Module1" в самом начале кода не нужна, она попала случайно!!! Первой строкой должна быть Option Explicit

Re: Как программно сделать импорт блока из другого файла?

Добрый день. Если можно, то поясните:
1)    Как при вставки блока исключить появления запроса об масштабе и угле вставки блока;
2)    Как удалить временный файл с изображением блока.

Re: Как программно сделать импорт блока из другого файла?

Пожалуйста, ответьте мне на мой вопрос.
1) Как при вставки блока исключить появления запроса об масштабе и угле вставки блока;
2) Как удалить временный файл с изображением блока.

Re: Как программно сделать импорт блока из другого файла?

> Андрей
Мне так кажется нужно просто в коде указать, чему равен масштаб, и угол вставки, и тогда запрос не будет появляться

Re: Как программно сделать импорт блока из другого файла?

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

Re: Как программно сделать импорт блока из другого файла?

https://www.caduser.ru/forum/topic24156.html

Re: Как программно сделать импорт блока из другого файла?

Я работаю таким образом:
Загрузка блока из другого файла

Sub loadBlock4(fileName$, blockName$)
    'Цель: Загрузка блока в активный файл из другого файла
    'Дано:
        'fileName$ - имя файла, содержащего требуемый блок
        'blockName$ - имя требуемого блока
    'Результат: Требуемый блок загружен в активный файл
    'чтение содержимого текущего файла. Нижеследующую конструкцию сделал, т.к.
        'при каких-то изменениях в меню Window, теряется свойство Active у видимого файла
        Dim targetDoc As AcadDocument 'имя файла, в который надо загрузить блок
        Dim i%, n%: n = Documents.Count 'общее количество файлов в приложении
        For i = 0 To n - 1
            If Documents(i).Active Then Set targetDoc = Documents.Item(i) 'комплект-набор текущего файла
        Next i
    'работа с файлом-донором
        'открытие файла
                On Error GoTo myExit1 'если нет файла в данном компьютере
                ThisDrawing.Application.Documents.Open (fileName)
myExit1:
                If Err <> 0 Then
                    Err.Clear
                    Dim Res1: Res1 = "В этом компьютере нет файла " & fileName & "."
                    Res1 = MsgBox(Res1, vbOKOnly, "MyLibrary4, modACAD, Sub loadBlock")
                    End
                End If
        'чтение содержимого файла
            Dim sourceDoc As AcadDocument
            n = Documents.Count
            For i = 0 To n - 1
                If Documents(i).FullName = fileName Then Set sourceDoc = Documents.Item(i)
            Next i
        'проверка наличия требуемого блока
            Dim oBlocks As AcadBlocks: Set oBlocks = ThisDrawing.Blocks 'коллекция блоков
            n = ThisDrawing.Blocks.Count 'общее количество блоков в файле
            Dim isBlock As Boolean: isBlock = False
            Set oBlocks = sourceDoc.Blocks       'коллекция блоков в файле-доноре
            Dim oBlock As AcadBlock: Set oBlock = oBlocks.Item(blockName)   'искомый блок
            For i = 0 To n - 1
                If oBlocks(i).Name = blockName$ Then isBlock = True
            Next i
            If Not isBlock Then
                Res1 = "В файле " & fileName & Chr(10)
                Res1 = Res1 & "нет блока " & blockName
                Res1 = MsgBox(Res1, vbOKOnly, "MyLibrary4, modACAD, Sub loadBlock")
                End
            End If
    'загрузка блока в текущий файл
        Dim objCopy(0) As AcadObject: Set objCopy(0) = oBlock 'копия блока
        Dim RetVal 'Variant (array of objects). Массив вновь созданных дубликатов объектов.
                    'Only primary objects are returned in this array
        Dim IDPairs 'Variant (array of IDPair objects); input-output; optional
                'Information on what happened during the copy and translation process.
                'Input: an empty variant.
                'Output: an array of IDPair objects
        RetVal = sourceDoc.CopyObjects(objCopy, targetDoc.Blocks, IDPairs)
    'заключительные работы
        sourceDoc.Close False: Set sourceDoc = Nothing 'закрытие файла-донора
End Sub

Вставка блока программно

Function InsertBlock3(blName$, pBase() As Double, _
        Optional Sc# = 1, Optional xs# = 1, Optional ys# = 1, Optional zs# = 1, _
        Optional Layer$ = "активный", Optional blExplode As Boolean = False)
    'Цель: Вставка  блока
    'Дано:
        'blName - имя вставляемого блока
        'pBase() - координаты вставки и угол поворота блока в радианах или формулой: градусы / 180 * Pi.
                    'Если угол > 0, блок поворачивается против часовой стрелки
        'Sc# = 1 - масштаб  для координат точки вставки блока
        'xs# = 1 - масштаб блока по оси X. При xs < 0 блок отображается зеркально относитель-но оси X
        'ys# = 1 - масштаб блока по оси Y. При ys < 0 блок отображается зеркально относитель-но оси Y
        'zs# = 1 - масштаб блока по оси Z. При zs < 0 блок отображается зеркально относительно оси Z
        'Layer$ = "активный". AcadBlockReference вставляется в текущий слой
        'blEx - признак необходимости разрушить блок
     'установка слоя текущим
        If Layer$ <> "активный" Then Call ChangeLayerCur3(Layer$)
    'определение координат точки вставки с учетом масштаба
        Dim BlockRotation#, insertionPnt(0 To 2) As Double
        insertionPnt(0) = pBase(0) * Sc: insertionPnt(1) = pBase(1) * Sc: insertionPnt(2) = pBase(2) * Sc
     'чтение угла поворота блока
        BlockRotation = pBase(3)
    'вставка блока
        Dim CurBlockRefObj As AcadBlockReference
        Set CurBlockRefObj = ThisDrawing.ModelSpace.InsertBlock(insertionPnt, blName, xs, ys, zs, BlockRotation)
    'разрушение блока
        If blExplode Then CurBlockRefObj.Explode
  End Function

Re: Как программно сделать импорт блока из другого файла?

Все хорошо. Но оператор
"Set oBlock = oBlocks.Item(blockName)   'искомый блок
Обращается за блоком раньше чем происходит проверка на его наличие, что приводит к ошибке, которая перехватывается как отсутствие файла ...
если его поставить пониже, то ОК.