Логотип сайта поддержки пользователей САПРО сайте поддержки пользователей САПР Translate to:

Примитивы чертежей AutoCAD (часть 4)

Поиск и замена текста во вставленных блоках

Добавление текстового объекта в блок

Блоки

Создание блока из выбранных объектов

Для создания нового блока из набора выбранных объектов нам понадобиться две функции. Первая будет проверять заданное нами имя нового блока на возможность его использования, и, если задаваемое имя уже используется в текущем как имя блока, то эта функция сгенерирует новое имя. Вторая функция будет создавать блок из заданного набора объектов:

Option Explicit

'@=========================================@'
'@ Функция проверки строки на возможность  @'
'@ использования ее в качестве имени блока @'
'@ Если эта строка уже используется в      @'
'@ качестве имени блока, то функция сгене- @'
'@ рирует на базе заданного новое имя      @'
'@=========================================@'
Public Function BlockNameIncrement(strName As String) As String
  Dim objBlocks As AcadBlocks
  Dim objBlock As AcadBlock
  Dim strValue As String
  Dim intCnt As Integer
  Dim blnFound As Boolean
  
  On Error GoTo Err_Control
  Set objBlocks = ThisDrawing.Blocks
  strValue = strName
  Do
    For Each objBlock In objBlocks
      If objBlock.Name = strValue Then
        blnFound = True
        intCnt = intCnt + 1
        strValue = strName & intCnt
        Exit For
      Else
        blnFound = False
      End If
    Next objBlock
  Loop Until Not blnFound
  BlockNameIncrement = strValue
Exit_Here:
    Exit Function
Err_Control:
    MsgBox Err.Description
End Function

'@=========================================@'
'@ Функция для создания блока из набора    @'
'@ объектов objSelSet, с именем strName и  @'
'@ с базовой точкой varPnt                 @'
'@=========================================@'
Public Function BlockSelSet(objSelSet As AcadSelectionSet, _
varPnt As Variant, strName As String) As AcadBlock
  Dim objBlks As AcadBlocks
  Dim objTemp As AcadBlock
  Dim objArray() As AcadEntity
  Dim intCnt As Integer
  Set objBlks = ThisDrawing.Blocks
  For intCnt = 0 To objSelSet.Count - 1
    ReDim Preserve objArray(intCnt)
    Set objArray(intCnt) = objSelSet(intCnt)
  Next intCnt
  Set objTemp = objBlks.Add(varPnt, strName)
  ThisDrawing.CopyObjects objArray, objTemp
  Set BlockSelSet = objTemp
  Set objBlks = Nothing
  Set objTemp = Nothing
End Function

Public Sub TEST_BlockSelSet()
  Dim strBlkName As String
  Dim varPnt As Variant
  Dim objSelSet As AcadSelectionSet
  Dim objSelCol As AcadSelectionSets
  Dim objNewBlock As AcadBlock

  On Error Resume Next
  Set objSelCol = ThisDrawing.SelectionSets
  For Each objSelSet In objSelCol
    If objSelSet.Name = "SelSetForBlock" Then
      objSelSet.Delete
      Exit For
    End If
  Next
  Set objSelSet = ThisDrawing.SelectionSets.Add("SelSetForBlock")
  objSelSet.SelectOnScreen

  With ThisDrawing.Utility
    varPnt = .GetPoint(, vbCr & _
             "Укажите базовую точку блока: ")
    strBlkName = .GetString(False, vbCr & _
                 "Введите имя создаваемого блока: ")
  End With

  Set objNewBlock = BlockSelSet(objSelSet, _
  varPnt, BlockNameIncrement(strBlkName))
End Sub
 

В этом примере функция BlockNameIncrement немного не доработана. Не плохо бы добавить проверку на наличие в задаваемом имене недопустимых символов. Да и в функции BlockSelSet такая проверка не помешает. Но я думаю что обеспечение этой проверки не вызовит у Вас затруднений.

Диалоговое окно для вставки блока

Добавьте в проект новую форму, задайте ей имя frmBlkInsert и разместите на ней следующие элементы управления:

Два переключателя (Option Buttons)
Один флажек (Check box)
Одну метку (Label)
Один раскрывающийся список (Combo Box)
Одну кнопку (Command Button)

В итоге форма должна выглядеть примерно так:

Затем поместите в модуль формы следующий код:
Option Explicit

Private Sub UserForm_Initialize()
  Dim intCnt As Integer
  
  OptionButton1 = True
  'Replace with first blocks name
  'Здесь Вы можете заменить имена вставляемых блоков
  '"One" и "Two" на любые другие, имеющиеся в чертеже
  OptionButton1.Caption = "One"
  'Replace with second blocks name
  OptionButton2.Caption = "Two"
  CommandButton1.Caption = "Insert"
  CommandButton1.Caption = "Вставить"
  'Label1.Caption = "Scale"
  Label1.Caption = "Масштаб"
  For intCnt = 1 To 10
    ComboBox1.AddItem intCnt
  Next intCnt
  ComboBox1.ListIndex = 0
  'CheckBox1.Caption = "Select Insertion Point"
  CheckBox1.Caption = "Указать точку вставки"
End Sub

Private Sub CommandButton1_Click()
  Dim varInsPnt As Variant
  Dim dblBlkScale As Double
  Dim blnScale As Boolean
  Dim strBlock As String

  If Len(ComboBox1.Text) > 0 Then
    blnScale = True
    dblBlkScale = ComboBox1.Text
  End If
  If OptionButton1 Then
    strBlock = OptionButton1.Caption
  Else
    strBlock = OptionButton2.Caption
  End If
  If CheckBox1 Then
    Me.Hide
    varInsPnt = _
    ThisDrawing.Utility.GetPoint(Prompt:="Insertion Point: ")
    If blnScale Then
      InsertOption strBlock, varInsPnt, dblBlkScale
    Else
      InsertOption strBlock, varInsPnt
    End If
    Me.Show
  Else
    If blnScale Then
      InsertOption strBlock, dblScale:=dblBlkScale
    Else
      InsertOption strBlock
    End If
  End If
End Sub

Public Sub InsertOption(strName As String, _
Optional varPnt As Variant, Optional dblScale As Double = 1)
  Dim objUtil As Object
  If IsMissing(varPnt) Then
    Set objUtil = ThisDrawing.Utility
    objUtil.CreateTypedArray varPnt, vbDouble, 0, 0, 0
  End If
  'I just left rotation at 0
  'В данном примере угол поворота вставляемого блока
  'всегда равен 0 градусов
  If ThisDrawing.ActiveSpace = acModelSpace Then
    ThisDrawing.ModelSpace.InsertBlock varPnt, _
    strName, dblScale, dblScale, dblScale, 0
  Else
    ThisDrawing.PaperSpace.InsertBlock varPnt, _
    strName, dblScale, dblScale, dblScale, 0
  End If
  Application.Update
End Sub
 

Теперь добавьте в проект стандартный модуль и добавьте в него процедуру, запускающую наше диалоговое окно:

Option Explicit

Public Sub TEST_frmBlkInsert()
  frmBlkInsert.Show
End Sub
 

Теперь создайте в чертеже два блока с теми именами, которые Вы использовали в качестве свойст Caption к элементам OptionButton1 и OptionButton2 в процедуре UserForm_Initialize модуля формы и запустите макрос TEST_frmBlkInsert. Пример, конечно, очень прост. С помощью этого диалогового окна можно вставльять только два строго определенных заранее блока. В принципе есть возможность вместо двух OptionButton разместить на форме ComboBox и попробовать заполнить его именами всех определенных в чертеже блоков.

Удалите из формы элементы OptionButton и вставьте вместо них еще один ComboBox. У Вас должно получиться что-то похожее на следующую картинку:

Теперь надо слегка изменить процедуры UserForm_Initialize и CommandButton1_Click

Option Explicit

Private Sub UserForm_Initialize()
  Dim intCnt As Integer
  Dim objAcBlocks As AcadBlocks
  Dim objAcBlock As AcadBlock
  
  Set objAcBlocks = ThisDrawing.Blocks
  ' Заполняем список именами блоков
  For Each objAcBlock In objAcBlocks
    If Not Left(objAcBlock.Name, 1) = "*" Then
    ' Нам не нужны анонимные блоки и блоки типа
    ' *Model_Spase и *Paper_Spase
      ComboBox2.AddItem objAcBlock.Name
    End If
  Next
  ComboBox2.ListIndex = 0
  
  'CommandButton1.Caption = "Insert"
  CommandButton1.Caption = "Вставить"
  'Label1.Caption = "Scale"
  Label1.Caption = "Масштаб"
  For intCnt = 1 To 10
    ComboBox1.AddItem intCnt
  Next intCnt
  ComboBox1.ListIndex = 0
  'CheckBox1.Caption = "Select Insertion Point"
  CheckBox1.Caption = "Указать точку вставки"
End Sub

Private Sub CommandButton1_Click()
  Dim varInsPnt As Variant
  Dim dblBlkScale As Double
  Dim blnScale As Boolean
  Dim strBlock As String
  
  If Len(ComboBox1.Text) > 0 Then
    blnScale = True
    dblBlkScale = ComboBox1.Text
  End If
  If Len(ComboBox2.Text) > 0 Then
    strBlock = ComboBox2.Text
  End If
  If CheckBox1 Then
    Me.Hide
    varInsPnt = _
    ThisDrawing.Utility.GetPoint(Prompt:="Insertion Point: ")
    If blnScale Then
      InsertOption strBlock, varInsPnt, dblBlkScale
    Else
      InsertOption strBlock, varInsPnt
    End If
    Me.Show
  Else
    If blnScale Then
      InsertOption strBlock, dblScale:=dblBlkScale
    Else
      InsertOption strBlock
    End If
  End If
End Sub
 

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

Вставка блока в масштабе, равном масштабу текущего размерного стиля

Не буду приводить здесь весю процедуру вставки блока, ее можно посмотреть в предидущих примерах. Рассмотрим отрывок кода, определяющий масштаб, заданный в текущем стиле размеров:

  Dim strStyleName As String
  Dim objSelSet As AcadSelectionSet
  Dim dblScale As Double

  strStyleName = ThisDrawing.ActiveDimStyle.Name
  intType(0) = 0
  intType(1) = 3
  varData(0) = "DIMENSION"
  varData(1) = strStyleName
  Set objSelSet = ThisDrawing.SelectionSets.Add("dimscaleset")
  objSelSet.Select acSelectionSetAll, filtertype:=intType, _
  filterdata:=varData
  If objSelSet.Count > 0 Then
    dblScale = objSelSet.Item(0).ScaleFactor
  Else
    dblScale = 0
  End If
 

Вставка блоков в точки, совпадающие с вершинами выбранной полилинии

Перед использованием примера задайте в процедуре TEST_InsertBlocksEX имя блока, определенного в текущем чертеже.

Option Explicit

Public Sub InsertBlocksEX(sBlockName As String, dXScale As Double, _
dYScale As Double, dZScale As Double, dRotation As Double)
  'Dim objPline As AcadPolyline
  Dim objPline As AcadLWPolyline
  Dim objSelSet As AcadSelectionSet
  Dim intVCnt As Integer
  Dim intType(0) As Integer
  Dim varData(0) As Variant
  Dim retCoord As Variant
  Dim intCnt As Integer
  Dim varVert As Variant
  Dim varPnt As Variant
  Dim varCord As Variant
  Dim varNext As Variant
  Dim varMid As Variant
  Dim intCrdCnt As Integer

  On Error GoTo Exit_Sub
  intType(0) = 0
  'varData(0) = "POLYLINE"
  varData(0) = "LWPOLYLINE"
  Set objSelSet = vbdPowerSet("inserts")
  objSelSet.SelectOnScreen intType, varData
  For Each objPline In objSelSet
    retCoord = objPline.Coordinates
    intCnt = 1
    For Each varVert In retCoord
      intVCnt = intVCnt + 1
    Next
    'For intCrdCnt = 0 To intVCnt / 3 - 1 'For Poly
    For intCrdCnt = 0 To intVCnt / 2 - 1 'For LWPoly
      varCord = objPline.Coordinate(intCrdCnt)
      ReDim Preserve varCord(2)
      varCord(2) = objPline.Elevation
      If ThisDrawing.ActiveSpace = acModelSpace Then
        ThisDrawing.ModelSpace.InsertBlock varCord, sBlockName, _
        dXScale, dYScale, dZScale, dRotation
      Else
        ThisDrawing.PaperSpace.InsertBlock varCord, sBlockName, _
        dXScale, dYScale, dZScale, dRotation
      End If
    Next
  Next
Exit_Sub:
End Sub

Public Function vbdPowerSet(strName As String) As AcadSelectionSet
  Dim objSelSet As AcadSelectionSet
  Dim objSelCol As AcadSelectionSets
  Set objSelCol = ThisDrawing.SelectionSets
    For Each objSelSet In objSelCol
      If objSelSet.Name = strName Then
        ThisDrawing.SelectionSets.Item(strName).Delete
        Exit For
      End If
    Next
  Set objSelSet = ThisDrawing.SelectionSets.Add(strName)
  Set vbdPowerSet = objSelSet
End Function

Public Sub TEST_InsertBlocksEX()
  'Be sure to change the block name and info!
  InsertBlocksEX "sh_spot", 1, 1, 1, 0
End Sub
 

Расчленение блока и перенос всех элементов блока на заданный слой

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

Option Explicit

Public Function ExplodeToLayer(strLayerName As String) As Boolean
  Dim objSelSet As AcadSelectionSet
  Dim objSelCol As AcadSelectionSets
  Dim objBlk As AcadBlockReference
  Dim varObjs As Variant
  Dim intType(0) As Integer
  Dim varData(0) As Variant
  Dim intCnt As Integer
  
  On Error GoTo Err_Control
  
  Set objSelCol = ThisDrawing.SelectionSets
    For Each objSelSet In objSelCol
      If objSelSet.Name = "blockem" Then
        ThisDrawing.SelectionSets.Item("blockem").Delete
        Exit For
      End If
    Next
  Set objSelSet = ThisDrawing.SelectionSets.Add("blockem")
  intType(0) = 0
  varData(0) = "INSERT"
  objSelSet.SelectOnScreen intType, varData
  For Each objBlk In objSelSet
    varObjs = objBlk.Explode
    For intCnt = LBound(varObjs) To UBound(varObjs)
      varObjs(intCnt).Layer = strLayerName
      If TypeOf varObjs(intCnt) Is AcadAttribute Then
        varObjs(intCnt).Delete
      End If
    Next intCnt
    objBlk.Delete
  Next objBlk
  ExplodeToLayer = True
Exit_Here:
  Exit Function
Err_Control:
  MsgBox Err.Description
  Resume Exit_Here
End Function

Public Sub TEST_ ExplodeToLayer()
  If ExplodeToLayer("Layer1") Then
    MsgBox "All blocks exploded to Layer1 and attributes removed"
  Else
    MsgBox "Failed to explode all blocks in selections."
  End If
End Sub
 

"Выдергивание" примитива из блока

Функция из следующего примера позволяе "выдернуть" примитив заданного типа, находящийся на заданном слое из блока с заданным именем, определенным в текущем чертеже. Создайте блок, один из элементов которого полилиния (AcadLWPolyline), находящаяся на слое Layer2. Блок можете даже не вставлять. Просто запустите TEST_GetEntityFromBlock. Полилиния будет вставлена в чертеж так, как она была бы вставлена вместе с блоком, вставленным в точку 0,0,0. У функции есть недостаток (а может это преимущество?): если в блоке несколько полилиний, то возвращена будет та, которая определена в блоке первой. В принципе, функцию можно переделать так, чтобы она выдергивала из блока все объекты заданного типа и вставляла их в точки, указываемые пользователем, но, это уже Ваши проблемы…

Option Explicit

Public Function GetEntityFromBlock(strBlkName As String, _
strType As String, strLayer As String) As AcadEntity
  Dim objBlk As AcadBlock
  Dim objEnt As AcadEntity

  Set objBlk = ThisDrawing.Blocks.Item(strBlkName)
    For Each objEnt In objBlk
      If TypeName(objEnt) = strType Then
        If objEnt.Layer = strLayer Then
          Set GetEntityFromBlock = objEnt
          Exit For
       End If
      End If
    Next objEnt
Exit_Here:
  Exit Function
Err_Control:
  MsgBox Err.Description
  Resume Exit_Here
End Function

Public Sub TEST_GetEntityFromBlock()
  Dim objEnt(0) As AcadEntity
  Dim varRet As Variant

  ' Замените имена блока и слоя (test и Layer2)
  ' на любые другие, определенные в чертеже
  Set objEnt(0) = GetEntityFromBlock("test", _
                  "IAcadLWPolyline", "Layer2")
  varRet = ThisDrawing.CopyObjects(objEnt, _
           ThisDrawing.ModelSpace)
End Sub
 

Нахождение в чертеже всех вставленных блоков с заданным именем

Процедура GetBlkRefs добавляет в созданный ранее набор objSelSet все вставленные в чертеж блоки с именем strBlkName

Option Explicit

'Begin Code Block
Public Sub GetBlkRefs(strBlkName As String, objSelSet As AcadSelectionSet)
  Dim objBlk As AcadBlock
  Dim colBlks As AcadBlocks
  Dim objBlkRefs As AcadBlockReference
  Dim varData(0) As Variant
  Dim intData(0) As Integer
  varData(0) = strBlkName
  intData(0) = 2
  objSelSet.Select acSelectionSetAll, , , intData, varData
End Sub

Public Function vbdPowerSet(strName As String) As AcadSelectionSet
  Dim objSelSet As AcadSelectionSet
  Dim objSelCol As AcadSelectionSets
  
  Set objSelCol = ThisDrawing.SelectionSets
  For Each objSelSet In objSelCol
    If objSelSet.Name = strName Then
      ThisDrawing.SelectionSets.Item(strName).Delete
      Exit For
    End If
  Next
  Set objSelSet = ThisDrawing.SelectionSets.Add(strName)
  Set vbdPowerSet = objSelSet
End Function

'Now you can test it
Public Sub TestRefs()
  Dim objSS As AcadSelectionSet
  Dim objblkRef As AcadBlockReference
  
  Set objSS = vbdPowerSet("llama")
  ' Замените имя блока "test" на любое другое,
  ' определенное в теущем чертеже
  ' Хотя бы один блок с таким именем должен быть вставлен
  GetBlkRefs "test", objSS
  For Each objblkRef In objSS
    objSS.Highlight True
  Next objblkRef
End Sub
'End Code Block
 

Создание в таблице Excel списка всех вставленных в чертеж блоков и их количества

Вставьте в чертеж несколько блоков, запустите MS Excel, в котором создайте новую книгу. Теперь вернитесь к AutoCAD, добавьте в стандартный модуль следующий ниже код. Не забудьте добавить в проект ссылку на Excel Object type Library. Запустите процедуру SortBlocksWithCount. После ее работы в текущей таблице MS Excel будет создан список всех вставленных в чертеж блоко и будет указано их количество. Чем не основа для создания программы, автоматически создающей спецификацию к сборочному чертежу?


Option Explicit

'Remember to add a reference to the
'Excel Object type Library

Public Sub SortBlocksWithCount()
  Dim objExcel As Excel.Application
  Dim objSelSet As AcadSelectionSet
  Dim objBlkRef As AcadBlockReference
  Dim objNext As Range
  Dim intRow As Integer
  Dim intBlkCnt As Integer
  Dim intCnt As Integer
  Dim intType(0) As Integer
  Dim varDat(0) As Variant
  Dim blnTop As Boolean
  
  On Error GoTo Err_Control
  'Excel MUST be running for this sample
  Set objExcel = GetObject(, "Excel.Application")
  'clears all cells - make sure there is nothing you
  'want in the active book
  With objExcel
    .Cells.Select
    .Selection.ClearContents
    .Range("A1").Select
    .ActiveCell.FormulaR1C1 = "Block Name"
    .Range("B1").Select
    .ActiveCell.FormulaR1C1 = "Block Count"
    .Range("A1:D1").Select
    .Selection.Font.Bold = True
    .Columns("A:B").Select
    intRow = 2
    intType(0) = 0
    varDat(0) = "INSERT"
    Set objSelSet = vbdPowerSet("sortblocks")
    objSelSet.Select acSelectionSetAll, filtertype:=intType, _
    filterdata:=varDat
    blnTop = False
    For Each objBlkRef In objSelSet
      .Cells(intRow, intCnt + 1).Value = objBlkRef.Name
      intRow = intRow + 1
    Next objBlkRef
    .ActiveSheet.Range("A1").Sort _
    key1:=.ActiveSheet.Columns("A"), _
    Header:=xlGuess
    .Range("A1").Select
    Set objNext = .ActiveCell.Offset(1, 0)
      Do While objNext <> ""
        .ActiveCell.Offset(1, 0).Select
        intBlkCnt = 1
Check_Value:
      Set objNext = .ActiveCell.Offset(1, 0)
      If .ActiveCell.Value = objNext.Value Then
        intBlkCnt = intBlkCnt + 1
        .ActiveCell.Offset(1, 0).Select
        .Selection.Delete Shift:=xlUp
        .ActiveCell.Offset(-1, 0).Select
        GoTo Check_Value
      Else
        .ActiveCell.Offset(0, 1).Select
        .ActiveCell.Value = intBlkCnt
        .ActiveCell.Offset(0, -1).Select
      End If
    Loop
  End With
Exit_Here:
  Exit Sub
Err_Control:
  MsgBox Err.Description
  Resume Exit_Here
End Sub
 
Public Function vbdPowerSet(strName As String) As AcadSelectionSet
  Dim objSelSet As AcadSelectionSet
  Dim objSelCol As AcadSelectionSets
  Set objSelCol = ThisDrawing.SelectionSets
    For Each objSelSet In objSelCol
      If objSelSet.Name = strName Then
        objSelSet.Delete
        Exit For
      End If
    Next
  Set objSelSet = ThisDrawing.SelectionSets.Add(strName)
  Set vbdPowerSet = objSelSet
End Function
 

Изменение всех длинных имен блоков на короткие

AutoCAD 2000 (15) позволяет создавать блоки с именами, которые состоят более чем из 31 символа, а AutoCAD 14 и более ранние версии не воспринимают таких имен. В случаях, когда в чертеже есть блоки с длинными именами и чертеж нужно сохранить в формате AutoCAD 14 может помоч процедура, подобная следующей:

Option Explicit

Public Sub ReduceNameLength()
  Dim objBlk As AcadBlock
  Dim objBlks As AcadBlocks
  Dim intCnt As Integer
  Set objBlks = ThisDrawing.Blocks
  For Each objBlk In objBlks
    If Len(objBlk.Name) > 31 Then
      intCnt = intCnt + 1
      objBlk.Name = "Block" & intCnt
    End If
  Next objBlk
End Sub
 

Определение масштабных коэффициентов блока по осям

Следующая процедура возвращает массив, в котором содержатся масштабные коэффициенты по осям X, Y и Z, с которыми блок objBlk вставлен в чертеж

Option Explicit

Public Function BlockScales(objBlk As _
AcadBlockReference) As Variant
  Dim dblXScale As Double
  Dim dblYScale As Double
  Dim dblZScale As Double
  Dim varScales As Variant
  dblXScale = objBlk.XScaleFactor
  dblYScale = objBlk.YScaleFactor
  dblZScale = objBlk.ZScaleFactor
  varScales = Array(sblxscale, dblYScale, dblZScale)
  BlockScales = varScales
End Function
 

Изменение слоя всех вставленных блоков

Представленная ниже процедура changeBlockSeqEndLayer изменяет слой всех вставленных блоков на слой с заданным именем.

Option Explicit

Sub changeBlockSeqEndLayer(strNewLayer As String)
  Dim objBlkRef As AcadBlockReference
  Dim objSelSet As AcadSelectionSet
  Dim objSelCol As AcadSelectionSets
  Dim objSeqEnd As AcadEntity
  Dim hexString As String
  Dim intType(0) As Integer
  Dim varData(0) As Variant
  Set objSelCol = ThisDrawing.SelectionSets
  For Each objSelSet In objSelCol
    If objSelSet.Name = "seqend" Then
      objSelSet.Delete
      Exit For
    End If
  Next objSelSet
  Set objSelSet = objSelCol.Add("seqend")
  intType(0) = 0
  varData(0) = "INSERT"
  objSelSet.Select 5, filtertype:=intType, _
  filterdata:=varData
  For Each objBlkRef In objSelSet
    If objBlkRef.HasAttributes Then
    hexString = "&H" & objBlkRef.Handle
    Set objSeqEnd = objBlkRef
      Do While objSeqEnd.EntityName <> _
      "AcDbSequenceEnd"
        hexString = hexString + 1
        Set objSeqEnd = _
        ThisDrawing.HandleToObject(Hex(hexString))
      Loop
      objBlkRef.Layer = strNewLayer
      objSeqEnd.Layer = strNewLayer
    End If
  Next
End Sub

Public Sub TEST_changeBlockSeqEndLayer()
  Dim strLayerName As String
  
  ' Замените имя слоя Layer1 на любое другое,
  ' определенное в чертеже.
  strLayerName = "Layer1"
  changeBlockSeqEndLayer strLayerName
End Sub
 

Замена существующего блока на блок из заданного файла

Создайте новый чертеж, нарисуйте в нем несколько примитивов и сохраните файл под именем C:\myblock. Закройте этот файл и создайте другой чертеж, в котором создайте блок под именем myblock, но, состоящий из других примитивов. Вставьте этот блок в чертеж. Теперь добавьте в стандартный модуль следующую ниже процедуру и запустите ее. В результате ее работы созданный Вами блок будет переопределен на друго, состоящий из примитивов сохраненного Вами файла C:\myblock.

Option Explicit

Public Sub RunReplace()
  Dim objBlkRef As AcadBlockReference
  Dim objSelSet As AcadSelectionSet
  Dim objAllSets As AcadSelectionSets
  Dim objSpace As AcadBlock
  Dim intType(1) As Integer
  Dim varData(1) As Variant
  Dim varPnt As Variant

  '//BUILD SELECTION SET
  Set objAllSets = ThisDrawing.SelectionSets
  For Each objSelSet In objAllSets
    If objSelSet.Name = "replacingblocks" Then
      objSelSet.Delete
      Exit For
    End If
  Next objSelSet
  Set objSelSet = objAllSets.Add("replacingblocks")
  intType(0) = 0
  intType(1) = 2
  varData(0) = "INSERT"
  varData(1) = "myblock"
  objSelSet.Select acSelectionSetAll, _
  filtertype:=intType, filterdata:=varData

  '//REPLACE OLD WITH NEW
  For Each objBlkRef In objSelSet
    varPnt = objBlkRef.InsertionPoint
    'get the correct space
    Set objSpace = ThisDrawing.ObjectIdToObject(objBlkRef.OwnerID)
    objBlkRef.Delete
    objSpace.InsertBlock varPnt, "c:\myblock.dwg", 1#, 1#, 1#, 0
  Next objBlkRef
End Sub
 

Вставка блока с аттрибутами и запрос их значений

Создайте в чертеже блок с аттрибутами или найдите на диске файл, который можно использовать в качестве такого блока. Вставьте в стандартный модуль VBA приведенный ниже код. Теперь подкорректируйте процедуру TEST_VBD_InsertBlock, заменив имя блока, присваеваемое переменной strBlkName на то, которое определено в чертеже или на имя найденного Вами файла. Обращаю Ваше внимание, что имя файла должно быть полным, даже если файл находится в каталоге поддержки AutoCAD. После этого можно запустить процедуру TEST_VBD_InsertBlock

Option Explicit

'@~~~~~~~~~~~~~~ VBD_InsertBlock ~~~~~~~~~~~~~~~~~~@
'Insert a block with attributes and allow the user
'To enter the attribute values.
'@~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~@
Public Function VBD_InsertBlock(strBlkName As String, _
Optional varInsert As Variant, Optional dblScale As Double = 1, _
Optional dblRotation As Double = 0) _
As AcadBlockReference
  Dim objTemp As AcadBlockReference
  Dim objBlk As AcadBlock
  Dim colBlks As AcadBlocks
  Dim strPrompt As String
  Dim strReply As String
  Dim varAtts As Variant
  Dim intCnt As Integer
  On Error GoTo Err_Control
  Set colBlks = ThisDrawing.Blocks
  Set objBlk = colBlks.Item(strBlkName)
  If IsMissing(varInsert) Then
    varInsert = ThisDrawing.Utility.GetPoint(Prompt:=vbCrLf & _
    "Select Insertion Point: ")
  End If
  If ThisDrawing.ActiveSpace = acModelSpace Then
    Set objTemp = ThisDrawing.ModelSpace.InsertBlock(varInsert, strBlkName, _
    dblScale, dblScale, dblScale, dblRotation)
  Else
    Set objTemp = ThisDrawing.PaperSpace.InsertBlock(varInsert, strBlkName, _
    dblScale, dblScale, dblScale, dblRotation)
  End If
  If objTemp.HasAttributes Then
    varAtts = objTemp.GetAttributes
    ThisDrawing.Utility.Prompt vbCrLf & "Enter Attribute values" & vbCrLf
    For intCnt = LBound(varAtts) To UBound(varAtts)
      strPrompt = vbCr & "Enter <" & varAtts(intCnt).TextString & "> "
      strReply = ThisDrawing.Utility.GetString(1, strPrompt)
      If strReply <> "" Then
        varAtts(intCnt).TextString = strReply
      End If
    Next
  End If
  Set VBD_InsertBlock = objTemp
Exit_Here:
  Exit Function
Err_Control:
  MsgBox Err.Description
  Resume Exit_Here
End Function

Public Sub TEST_VBD_InsertBlock()
Dim strBlkName As String
Dim varInsPnt As Variant
Dim dblScale As Double
Dim dblRotAng As Double
Dim objBlock As AcadBlockReference

  On Error GoTo Err_Handler
  With ThisDrawing.Utility
    varInsPnt = .GetPoint(, vbCrLf & "Укажите точку вставки блока: ")
    dblScale = .GetReal(vbCrLf & "Задайте масштаб вставки блока: ")
    dblRotAng = .GetAngle(, vbCrLf & "Угол поворота блока: ")
  End With
  ' В место заданного здесь имени вставляемого блока нужна подставить
  ' имя любого другого блока определенного в чертеже или задать
  ' имя файла, вставляемого как блок. Но, задавая имя файла
  ' нужно задать его полное имя с путем. Например:
  ' strBlkName = "C:\Program Files\ACAD2000\SUPPORT\sh_spot.dwg"
  strBlkName = "sh_spot"
  Set objBlock = VBD_InsertBlock(strBlkName, varInsPnt, _
  dblScale, dblRotAng)
  Exit Sub
Err_Handler:
  MsgBox Err.Description
  Err.Clear
End Sub
 

Задание значений атрибутов на основании данных из базы данных.

Суть функции в следующем. Она открывает базу данных, заданную именем файла базы данных sDBPath (имеется в виду база данных mdb), затем открывает таблицу sTableName. После этого просматриваются имена полей таблици и, если имя поля совпадает с именем какого-нибудь аттрибута из вставленного блока TitleBlock, то аттрибуту присваивается значение из соответствующего поля таблицы. Если блок имеет аттрибуты, то функция возвращает True, а если нет, то False. Используя процедуру, подобную этой, можно создать универсальную программу для вставки блоков со стандартными деталями, значения размеров которой подставляются из выбранной пользователем записи базы данных.

Option Explicit

Public Function FillInTheBlnks(sDBPath As String, _
sTableName As String, TitleBlock As AcadBlockReference) As Boolean
  Dim objDB As DAO.Database
  Dim objWorkSpace As DAO.Workspace
  Dim objRecSet As DAO.Recordset
  Dim objField As DAO.Field
  Dim intCnt As Integer
  Dim vArray As Variant
  Dim blnTemp As Boolean
  On Error GoTo Err_Control
  Set objWorkSpace = DBEngine.Workspaces(0)
  Set objDB = objWorkSpace.OpenDatabase(sDBPath)
  Set objRecSet = objDB.OpenRecordset(sTableName)
  If TitleBlock.HasAttributes Then
    vArray = TitleBlock.GetAttributes
    For Each objField In objRecSet.Fields
      For intCnt = LBound(vArray) To UBound(vArray)
        If StrComp(objField.Name, vArray(intCnt).TagString, _
        vbTextCompare) <> 0 Then
          vArray(intCnt).TextString = objField.Value
          Exit For
        End If
      Next intCnt
    Next objField
    blnTemp = True
  Else
    blnTemp = False
  End If
  objRecSet.Close
  objDB.Close
  objWorkSpace.Close
Exit_Here:
  FillInTheBlnks = blnTemp
  Exit Function
Err_Control:
  blnTemp = False
  Err.Clear
  Resume Exit_Here
End Function
 

Экспорт значений аттрибутов блока в текстовые объекты

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

Option Explicit

Public Sub AttributesToText()
  Dim varPnt As Variant
  Dim varPoint As Variant
  Dim varAtts As Variant
  Dim varHt As Variant
  Dim intCnt As Integer
  Dim objBlk As Object
  Dim strPrompt As String
  
  On Error GoTo Err_Control:

  strPrompt = vbCrLf & "Pick start point for text column: "
  varPnt = ThisDrawing.Utility.GetPoint(Prompt:=strPrompt)
  strPrompt = vbCrLf & "Pick block with attributes to convert: "
  ThisDrawing.Utility.GetEntity objBlk, varPoint, strPrompt
  If TypeOf objBlk Is AcadBlockReference Then
    If objBlk.HasAttributes Then
    varAtts = objBlk.GetAttributes
      For intCnt = LBound(varAtts) To UBound(varAtts)
        varHt = varAtts(intCnt).Height
        If ThisDrawing.ActiveSpace = acModelSpace Then
          ThisDrawing.ModelSpace.AddText varAtts(intCnt).TextString, _
          varPnt, varHt
        Else
          ThisDrawing.PaperSpace.AddText varAtts(intCnt).TextString, _
          varPnt, varHt
        End If
        'you will want to set your own offset distance
        ' Вы можете сами задать дисстанцию, с которой будут
        ' расставлены текстовые объекты
        varPnt(1) = varPnt(1) + (CDbl(varHt) * 1.5)
      Next
    End If
  End If
Exit_Here:
  Exit Sub
Err_Control:
  MsgBox Err.Description
  Resume Exit_Here
End Sub
 

Вставка блока с изменением масштаба отображения аттрибутов

Вставка блоков с аттрибутами это мощьный инструмент значительно облегчающий выполнение многих операций, но и у этого инструмента есть недостатки. Один из них - это невозможность задания разных масштабов собственно для блока и для аттрибутов блока. Действительно, очень часто бывают случаи, когда надо вставить блок с аттрибутами таким образом, чтобы все элементы блока смасштабировались, а высота текста аттрибутов осталась такой, какая она задана для масштаба 1:1. Эта проблема решена в следующем примере. Для его опробывания создадим блок с незапрашиваемым аттрибутом. Создадим мы его из квадрата 50 на 50 и аттрибута с высотой текста 10мм. Содержимое текста текстовое значение аттрибута не важно, лишь бы не пустое. Назовите этот блок "TEST" и запустите процедуру TEST_ExtendedInsert несколько раз, задавая при этом разные масштабы. Видите, размеры прямоугольника зависят от задаваемого масштаба, а высота текста аттрибута во всех случаях 10 мм. Мною замечено, что этот метод не работает для аттрибутов, значение которых не запрашивается при вставке блока, т. е. для констант.
Option Explicit

Public Function ExtendedInsert(BlkName As String, _
dblScale As Double, dblRotation As Double) As AcadBlockReference
  Dim objTemp As AcadBlockReference
  Dim varPnt As Variant
  Dim strPrompt As String
  Dim objAtts As Variant
  Dim intCnt As Integer
  
  strPrompt = "Pick Insertion point for " & BlkName & ": "
  If ThisDrawing.ActiveSpace = acModelSpace Then
    varPnt = ThisDrawing.Utility.GetPoint(Prompt:=strPrompt)
    Set objTemp = ThisDrawing.ModelSpace.InsertBlock(varPnt, BlkName, _
    dblScale, dblScale, dblScale, dblRotation)
  Else
    varPnt = ThisDrawing.Utility.GetPoint(Prompt:=strPrompt)
    Set objTemp = ThisDrawing.ModelSpace.InsertBlock(varPnt, BlkName, _
    dblScale, dblScale, dblScale, dblRotation)
  End If
  If objTemp.HasAttributes Then
      objAtts = objTemp.GetAttributes
      For intCnt = LBound(objAtts) To UBound(objAtts)
        With objAtts(intCnt)
          'Change to match your constant scale
          .ScaleEntity .InsertionPoint, 1 / dblScale
        End With
      Next intCnt
    End If
End Function

Public Sub TEST_ExtendedInsert()
  Dim strBlkName As String
  Dim dblScale As Double
  Dim dblRotAng As Double
  Dim objBlock As AcadBlockReference
  
  dblScale = 2
  dblRotAng = 0
  ' Измените имя блока на определенное в чертеже
  strBlkName = "TEST"
  dblScale = ThisDrawing.Utility.GetReal(vbCrLf & _
  "Задайте масштаб вставки блока: ")
  Set objBlock = ExtendedInsert(strBlkName, dblScale, dblRotAng)
End Sub
 

Выравнивание аттрибутов в повернутом блоке

Вставьте в чертеж какой-нибудь блок с аттрибутами под таким углом, чтобы ориентация текста аттрибутов отличалась от горизонтального (вставьте блок, в котором аттрибуты ориентированы горизонтально, а затем поверните его на какой-нибудь угол). После этого добавьте в стандартный модуль VBA приведенный ниже код и запустите процедуру LevelAttributes. На запрос Select a block выберите повернутый блок. Все аттрибуты будут повернуты таким образом, что их ориентация совпадет с той, которая была бы у них при вставке блока с углом поворота 0 градусов.
Option Explicit

Public Sub LevelAttributes()
  Dim objGen As AcadEntity
  Dim objAtts As Variant
  Dim varPnt As Variant
  Dim intCnt As Integer

  ThisDrawing.Utility.GetEntity objGen, varPnt, "Select a block: "
  If TypeOf objGen Is AcadBlockReference Then
    If objGen.HasAttributes Then
      objAtts = objGen.GetAttributes
      For intCnt = LBound(objAtts) To UBound(objAtts)
        With objAtts(intCnt)
          .Rotate objAtts(intCnt).InsertionPoint, -.Rotation
        End With
      Next intCnt
    End If
  End If
End Sub
 

Отображение нивидимых аттрибутов выбранного блока

Option Explicit

Public Sub AttributesON()
  Dim objEnt As AcadEntity
  Dim objBlkRef As AcadBlockReference
  Dim objAtt As AcadAttributeReference
  Dim varPnt As Variant
  Dim varAtts As Variant
  Dim strPrmt As String
  Dim intCnt As Integer
  On Error GoTo Err_Control
  strPrmt = "Select Block with invisible attribute(s): "
  ThisDrawing.Utility.GetEntity objEnt, varPnt, strPrmt
  If TypeOf objEnt Is AcadBlockReference Then
    Set objBlkRef = objEnt
    If objBlkRef.HasAttributes Then
      varAtts = objBlkRef.GetAttributes
      For intCnt = LBound(varAtts) To UBound(varAtts)
        Set objAtt = varAtts(intCnt)
        If objAtt.Invisible = True Then
          objAtt.Invisible = False
        End If
      Next intCnt
    Else
      MsgBox "No attributes found."
    End If
  Else
    MsgBox "Selected entity is not a block reference."
  End If
Exit_Here:
  Exit Sub
Err_Control:
  MsgBox Err.Description
  Resume Exit_Here
End Sub
 

Изменение цвета аттрибутов

Создайте в чертеже блок с аттрибутами, при этом сделайте так, чтобы цвет аттрибутов отличался от желтого. Вставьте в стандартный модуль приведенный ниже код и отредактируйте процедуру TEST_ColorAttributes, заменив имя блока TestBlkName на имя созданного Вами блока. Теперь, если запустить процедуру TEST_ColorAttributes, то цвет аттрибутов в блоке будет изменен на желтый, и если вставить блок после запуска процедуры TEST_ColorAttributes, блок будет "обновленным", с аттрибутами желтого цвета.

Option Explicit

Public Sub ColorAttributes(sBlockName As String, _
iColor As Integer)
  Dim objBlks As AcadBlocks
  Dim objBlk As AcadBlock
  Dim objEnt As AcadEntity
  Set objBlks = ThisDrawing.Blocks
  Set objBlk = objBlks(sBlockName)
  If Not objBlk.IsLayout And Not _
  objBlk.IsXRef Then
    For Each objEnt In objBlk
      If TypeOf objEnt Is AcadAttribute Then
        objEnt.Color = iColor
      End If
    Next objEnt
  End If
  Set objBlks = Nothing
End Sub

Public Sub TEST_ColorAttributes()
  Dim strBlockName As String
  Dim intColor As Integer
  
  ' Замените имя блока "TestBlkName" на любое, определенное
  ' в чертеже имя блока с аттрибутами
  strBlockName = "TestBlkName"
  ' Изменяем цвет аттрибутов на желтый
  intColor = 2
  ColorAttributes strBlockName, intColor
End Sub
 

Теперь попробуем изменить цвет аттрибутов уже у вставленных блоков. Добавьте в стандартный модуль следующий код и отредактируйте процедуру ColorMeBlue, заменив имя блока TestBlkName на имя созданного Вами блока. Теперь, если запустить процедуру ColorMeBlue, то у всех вставленных блоков с заданным именем цвет аттрибутов будет заменен на синий. К стати, в этом коде есть не плохой пример очень полезной функции, возвращающей набор объектов, состоящий только из аттрибутов, входящих в состав всех вставленных блоков с заданным именем.

Option Explicit

Public Function GetAttributeReferences(sBlockName As String) As Variant
  Dim objSelSet As AcadSelectionSet
  Dim objSelCol As AcadSelectionSets
  Dim objBlkRef As AcadBlockReference
  Dim objAttRef As AcadAttributeReference
  Dim objCat As AcadAttribute
  Dim intCnt As Integer
  Dim varAtts As Variant
  Dim varCatts
  Dim varData(1) As Variant
  Dim intType(1) As Integer
  Dim intKeepCnt As Integer
  Dim objAtts() As Object
  Dim varRet As Variant
  On Error GoTo Err_Control
  'Check to see if the name we are going to use for the
  'Selection set has been used before (we ran this process)
  'If it is, remove it.
  Set objSelCol = ThisDrawing.SelectionSets
    For Each objSelSet In objSelCol
      If objSelSet.Name = "vbdblkrefset" Then
        objSelSet.Delete
        Exit For
      End If
    Next
  'It is now safe to Set the selection set into the collection
  Set objSelSet = objSelCol.Add("vbdblkrefset")
  'Build the filter
  intType(0) = 0
  varData(0) = "INSERT"
  intType(1) = 2
  varData(1) = sBlockName
  'Get the blocks
  objSelSet.Select Mode:=acSelectionSetAll, filtertype:=intType, _
  filterdata:=varData
  'Do the search
  For Each objBlkRef In objSelSet
    If objBlkRef.HasAttributes Then
      varAtts = objBlkRef.GetAttributes
      For intCnt = LBound(varAtts) To UBound(varAtts)
        Set objAttRef = varAtts(intCnt)
        ReDim Preserve objAtts(intKeepCnt)
        Set objAtts(intKeepCnt) = objAttRef
        intKeepCnt = intKeepCnt + 1
      Next intCnt
      'Get Any constant Attributes
      varCatts = objBlkRef.GetConstantAttributes
      'Test varCatts, is it an array?
      If VarType(varCatts) And vbArray = vbArray Then
        For intCnt = LBound(varCatts) To UBound(varCatts)
          Set objCat = varCatts(intCnt)
          ReDim Preserve objAtts(intKeepCnt)
          Set objAtts(intKeepCnt) = objCat
          intKeepCnt = intKeepCnt + 1
        Next intCnt
      End If
    End If
  Next objBlkRef
  varRet = objAtts
  GetAttributeReferences = varRet
Exit_Here:
  Exit Function
Err_Control:
  Select Case Err.Number
  'Add your Case selections here
    Case Else
    MsgBox Err.Description
    Resume Exit_Here
  End Select
End Function

Public Sub ColorMeBlue()
  Dim varAttRefs As Variant
  Dim intCnt As Integer
  On Error GoTo Err_Control
  ' Замените имя блока "TestBlkName" на любое, определенное
  ' в чертеже имя блока с аттрибутами
  varAttRefs = GetAttributeReferences("TestBlkName")
  If VarType(varAttRefs) And vbArray = vbArray Then
    For intCnt = LBound(varAttRefs) To UBound(varAttRefs)
      varAttRefs(intCnt).Color = 5
    Next intCnt
  End If
  If MsgBox("About to regen, Ok to proceed?", _
  vbOKCancel) = vbOK Then
    ThisDrawing.Regen acAllViewports
  End If
Exit_Here:
  Exit Sub
Err_Control:
  Select Case Err.Number
  'Add your Case selections here
    Case Else
    MsgBox Err.Description
    Resume Exit_Here
  End Select
End Sub
 

Проверка значения аттрибута перед закрытием файла

Если Вы поместите в модуле ThisDrawing текущего чертежа следующий код и создадите в чертеже блок с именем TitleBlock, в котором определите аттрибут с именем Draftsman, затем вставите этот блок в чертеж, то при закрытии этого чертежа произойдет следующее: Функция IsValidName проверит значение аттрибута Draftsman, и, если оно не равно "Code", то будет отображено окно с запросом кодового слова. Этот запрос будет отображаться и файл не будет закрыт до тех пор ,пока пользователь не введет слово "Code". Если же в момент закрытия чертежа значение аттрибута сразу равно "Code", то никаких запросов кодового слова не производится и файл сразу закрывается.
Option Explicit

Private Sub AcadDocument_BeginClose()
  Dim blnCloseAllowed As Boolean
  blnCloseAllowed = IsValidName
  Do Until blnCloseAllowed
    blnCloseAllowed = IsValidName(InputBox("Enter Your Code"))
  Loop
End Sub
 
Public Function IsValidName(Optional strName As Variant) As Boolean
  Dim objBlkRef As AcadBlockReference
  Dim objSelSet As AcadSelectionSet
  Dim objAllSets As AcadSelectionSets
  Dim intType(1) As Integer
  Dim varData(1) As Variant
  Dim strUser As String
  Dim strCurVal As String
  Dim varAtts As Variant
  Dim intCnt As Integer

  strUser = "Code"

  Set objAllSets = ThisDrawing.SelectionSets
  For Each objSelSet In objAllSets
    If objSelSet.Name = "validate" Then
      objSelSet.Delete
      Exit For
    End If
  Next objSelSet
  Set objSelSet = objAllSets.Add("validate")
  intType(0) = 0
  intType(1) = 2
  varData(0) = "INSERT"
  varData(1) = "TITLEBLOCK"
  'This should return only one instance!
  objSelSet.Select acSelectionSetAll, _
  filtertype:=intType, filterdata:=varData
  Set objBlkRef = objSelSet.Item(0)
  varAtts = objBlkRef.GetAttributes
  For intCnt = LBound(varAtts) To UBound(varAtts)
    If varAtts(intCnt).TagString = "DRAFTSMAN" Then
      If IsMissing(strName) Then
        strCurVal = varAtts(intCnt).TextString
        0080">If strCurVal = strUser Then
          IsValidName = True
        Exit For
        End If
      Else
        If strName = strUser Then
          varAtts(intCnt).TextString = strName
          ThisDrawing.Save
          IsValidName = True
          Exit For
        End If
      End If
    End If
  Next intCnt
End Function
 

Функции для операций над аттрибутами и текстом

ApplyDate - присваивает значению выбранного текстового объекта (Text, MText или аттрибут блока) текущую дату
MoveAttribute - процедура, перемещающая выбранный аттрибут блока, оставляя блок на месте
ChangeCase - функция для изменения регистра символов любого текстового объекта (Text, MText или аттрибут блока) . Для демонстрации работы функции запустите процедуру TEST_ChangeCase
TransferTextValue - процедура запрашивает 2 любых текстовых объекта (Text, MText или аттрибут блока) , а затем присваивает значение первого выбранного объекта второму. Эта функция не корректно работает с объектами Mtext, содержащими символы Кирилицы
VBDEdit - процедура для редактирования значения любого текстового объекта (Text, MText или аттрибут блока) . Эта функция не корректно работает с объектами Mtext, содержащими символы Кирилицы
ClearAllKeyPress - вспомогательная функция, очищающая буфер клавиатуры

Option Explicit

'Win32API Constants for CheckKey
Public Const VK_ESCAPE = &H1B
Public Const VK_RETURN = &HD
Public Const VK_RBUTTON = &H2
Public Const VK_LBUTTON = &H1

'Win32API Constants for ClearAllKeyPress
Public Const WM_LBUTTONDOWN = &H201
Public Const WM_LBUTTONUP = &H202
Public Const PM_REMOVE = &H1

'Win32API Declare for CheckKey
Public Declare Function GetAsyncKeyState Lib "user32" _
(ByVal vKey As Long) As Integer

'Win32API Declare for ClearAllKeyPress
Public Declare Function PeekMessage Lib "user32" Alias "PeekMessageA" _
(lpMsg As MSG, ByVal hwnd As Long, ByVal wMsgFilterMin As Long, _
ByValwMsgFilterMax As Long, ByVal wRemoveMsg As Long) As Long

'This is for AutoCAD R14 users that do not have the Hwnd property
'In clear all key press, change:
'lngHwnd = ThisDrawing.hwnd
'To
'lngHwnd = FindWindow(vbNullString, Application.Caption)
Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long

'Win32API Types
Public Type POINTAPI
       x As Long
       y As Long
End Type

Public Type MSG
   hwnd As Long
   message As Long
   wParam As Long
   lParam As Long
   Time As Long
   pt As POINTAPI
End Type

'@~~~~~~~~~~ TransferTextValue ~~~~~~~~~~~~~~~@
' Pick any attribute, text, or Mtext to set
' The transfer value. Next select the target
' Attribute, MText, or Text object. The transfer
' Value is applied to the targets Text string
'@~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~@
Public Sub TransferTextValue()
  Dim objSource As AcadEntity
  Dim objTarget As AcadEntity
  Dim varPnt As Variant
  Dim varPntN As Variant
  Dim varSubIDs As Variant
  Dim varsubID2 As Variant
  Dim varMatrix As Variant
  Dim strPrompt As String
  Dim varValue As Variant

Pick_One:
  On Error GoTo Err_Control
  ClearAllKeyPress
  strPrompt = "Pick the source object (MText, Text, or Attribute): "
  ThisDrawing.Utility.GetSubEntity objSource, varPnt, _
  varMatrix, varSubIDs, strPrompt
  varValue = objSource.TextString

Pick_Two:
  ClearAllKeyPress
  strPrompt = "Pick the target object (MText, Text, or Attribute): "
  ThisDrawing.Utility.GetSubEntity objTarget, varPntN, _
  varMatrix, varsubID2, strPrompt
  objTarget.TextString = varValue

Exit_Here:
  Exit Sub

Err_Control:
  If Err.Number = 438 Then
    If varValue = "" Then
      Resume Pick_One
    Else
      Resume Pick_Two
    End If
  ElseIf Err.Number = -2147352567 Then
  'Did the user miss or are they trying to exit?
    If checkkey(VK_LBUTTON) Then
    'left click? oops they missed
      If objSource Is Nothing Then
      ' But what pick ?
        Resume Pick_One
      Else
        Resume Pick_Two
      End If
    Else
      Resume Exit_Here
    End If
  Else
    ThisDrawing.Utility.Prompt Err.Description
    Resume Exit_Here
  End If
End Sub

'///////////// Function and Sample Call //////////
'@~~~~~~~~~~~~~ Change Case ~~~~~~~~~~~~~~~~~~~@
' Convert the Case of any textual entity. the
' Argument "intCase" can be:
' 1 = Uppercase
' 2 = Lowercase
' 3 = Propercase
' You could also include the other constants
' For general string conversion(vbWide, vbNarrow,
' Etc..)
'@~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~@
Public Function ChangeCase(intCase As Integer) As Boolean
  Dim objEnt As AcadEntity
  Dim varPnt As Variant
  Dim varSubIDs As Variant
  Dim varMatrix As Variant
  Dim strVal As String
  Dim strPrompt As String
  
  On Error GoTo Err_Control
  If intCase > 0 And intCase < 4 Then
    strPrompt = "Pick the textual object for case change: "
    ThisDrawing.Utility.GetSubEntity objEnt, varPnt, _
    varMatrix, varSubIDs, strPrompt
    strVal = objEnt.TextString
    objEnt.TextString = StrConv(strVal, intCase)
    ChangeCase = True
  End If

Exit_Here:
  Exit Function
Err_Control:
  If Err.Number = 438 Then
    ThisDrawing.Utility.Prompt "Selected Entity does not have a text value."
  ElseIf Err.Number = -2147352567 Then
    ThisDrawing.Utility.Prompt "No entity selected."
  Else
    ThisDrawing.Utility.Prompt Err.Description
  End If
  Resume Exit_Here
End Function

Public Sub TEST_ChangeCase()
  Call ChangeCase(1)
  Call ChangeCase(2)
  Call ChangeCase(3)
End Sub

'//////////// End combined code ////////////////
'@~~~~~~~~~~~~~~~~~~~ VBDEdit ~~~~~~~~~~~~~~~~~@
' Like DDEDIT, except it works on attributes and
' Text or MText.
'@~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~@
Public Sub VBDEdit()
  Dim objEnt As AcadEntity
  Dim varPnt As Variant
  Dim varSubIDs As Variant
  Dim varMatrix As Variant
  Dim strVal As String
  Dim strNew As String
  Dim strPrompt As String

Do_Retry:
  On Error GoTo Err_Control
  Do
    ClearAllKeyPress
    strPrompt = "Pick the textual object for string modification: "
    ThisDrawing.Utility.GetSubEntity objEnt, varPnt, _
    varMatrix, varSubIDs, strPrompt
    strVal = objEnt.TextString
    strNew = InputBox(Prompt:="New Value", Default:=strVal)
    If Len(strNew) > 0 Then
      objEnt.TextString = strNew
    End If
  Loop

Exit_Here:
  Exit Sub

Err_Control:
  If Err.Number = 438 Then
    Resume Do_Retry
    'This is the error generated by Nothing picked:
  ElseIf Err.Number = -2147352567 Then
    'We are in a loop, so we check to see if the user wants out
    'or if they missed their pick.
    If checkkey(VK_LBUTTON) Then
    'left click? oops they missed
      Resume Do_Retry
    Else
      'Anything else means they want out!
      Resume Exit_Here
    End If
  Else
    ThisDrawing.Utility.Prompt Err.Description
    Resume Exit_Here
  End If
End Sub

Public Sub MoveAttribute()
  Dim objEnt As AcadEntity
  Dim varPnt As Variant
  Dim varBase As Variant
  Dim varDisp As Variant
  Dim varSubIDs As Variant
  Dim varMatrix As Variant
  Dim strVal As String
  Dim strKeys As String
  Dim strPrompt As String
  
  On Error GoTo Err_Control
  strKeys = "Insert"
  strPrompt = "Pick Attribute to move: "

Do_Retry:
    ThisDrawing.Utility.GetSubEntity objEnt, varPnt, _
    varMatrix, varSubIDs, strPrompt
    'Force an attribute selection by keeping the loop
    'Until an attribute reference is returned.
    'Of course an error will move to the error handler
    'which is good, because we can use to detect an
    'escape.
    If TypeOf objEnt Is AcadAttributeReference Then
      strPrompt = "Select base point for move [Insert]: "
      ThisDrawing.Utility.InitializeUserInput 32, strKeys
      On Error Resume Next
      varBase = ThisDrawing.Utility.GetPoint(Prompt:=strPrompt)
      If Err Then
        If Err.Description = "User input is a keyword" Then
          varBase = objEnt.InsertionPoint
          Err.Clear
        Else
          GoTo Err_Control
        End If
      End If
      On Error GoTo Err_Control
      strPrompt = "Select displacement point: "
      varDisp = ThisDrawing.Utility.GetPoint(varBase, strPrompt)
      objEnt.Move varBase, varDisp
    Else
      GoTo Do_Retry
    End If
Exit_Here:
  Exit Sub
Err_Control:
  If Err.Number = -2147352567 Then
    'We are in a loop, so we check to see if the user wants out
    'or if they missed their pick.
    If checkkey(VK_ESCAPE) Then
    'They really want out
      Resume Exit_Here
    ElseIf checkkey(VK_LBUTTON) Then
    'left click? oops they missed
      Resume Do_Retry
    ElseIf checkkey(VK_RBUTTON) Then
    'another exit key (right click)
      Resume Exit_Here
    End If
  Else
    ThisDrawing.Utility.Prompt "Function canceled"
  End If
  Resume Exit_Here
End Sub

'@~~~~~~~~~~~~~~~ ApplyDate ~~~~~~~~~~~~~~~@
' Apply the current date to any attribute
' or (M)Text
'@~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~@
Public Sub ApplyDate()
  Dim objEnt As AcadEntity
  Dim varPnt As Variant
  Dim varSubIDs As Variant
  Dim varMatrix As Variant
  Dim strVal As String
  Dim strPrompt As String
  Dim varDate As Variant

Do_Retry:
  On Error GoTo Err_Control
    strPrompt = "Pick annotation to modify: "
    ThisDrawing.Utility.GetSubEntity objEnt, varPnt, _
    varMatrix, varSubIDs, strPrompt
    'Use the format function to change the format of the date
    objEnt.TextString = Date 'this returns mm/dd/yyyy
Exit_Here:
  Exit Sub
Err_Control:
  If Err.Number = 438 Then
    Resume Do_Retry
  ElseIf Err.Number = -2147352567 Then
  'We are in a loop, so we check to see if the user wants out
  'or if they missed their pick.
    If checkkey(VK_ESCAPE) Then
    'They really want out
      Resume Exit_Here
    ElseIf checkkey(VK_LBUTTON) Then
    'left click? oops they missed
      Resume Do_Retry
    ElseIf checkkey(VK_RBUTTON) Then
    'another exit key (right click)
      Resume Exit_Here
    End If
  Else
    ThisDrawing.Utility.Prompt Err.Description
  End If
  Resume Exit_Here
End Sub

']---[ ]---[ ]---[ ]---[ ]---[ ]---[ ]---[
' Utility functions for the module
']---[ ]---[ ]---[ ]---[ ]---[ ]---[ ]---[
'@~~~~~~~~~~~~~~ CheckKey ~~~~~~~~~~~~~~~~~@
' Check to see if a particular key has been
' pressed. lngKey is provided by the Const
' in the general declararions.
'@~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~@
Function checkkey(lngKey As Long) As Boolean
  If GetAsyncKeyState(lngKey) Then
    checkkey = True
  Else
    checkkey = False
  End If
End Function

'@~~~~~~~~~~~~~~~ ClearAllKeyPress ~~~~~~~~~~~~~~~~~~~~~~~~@
' Used to clear the mouse clicks (can be used for key press
' You will just need to use different constants) so CheckKey
' Can get a clear read.
'@~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~@
Public Sub ClearAllKeyPress()
  Dim lngHwnd As Long
  Dim ThisMSG As MSG
  
  lngHwnd = ThisDrawing.hwnd
  Do While PeekMessage(ThisMSG, lngHwnd, WM_LBUTTONDOWN, _
  WM_LBUTTONUP, PM_REMOVE) <> 0
  Loop
End Sub
 



Copyright © Сайт поддержки пользователей САПР by Victor Tkachenko