Создание поля счётчика листов в dwg-файле


На ряде форумов заметил наличие одного и того же вопроса, который задавали разные люди: Как создать поле, которое было бы динамически связано со значением количества листов в dwg-файле, дабы можно было его использовать в штампах? 
Были предложены разные варианты решения данной проблемы, однако они не имели одной очень важной детали - динамической синхронизации значений счетчика листов с реальным их количеством. Т.е. предложенные варианты не реализовывали автоматическое обновление значения счётчика при создании/удалении/копировании листа в файле.


Кроме того, данный счётчик не должен при подсчёте учитывать листы черновиков (т.е. те, которые являются лишь вспомогательными для нас и не будут включены в общий состав листов проекта). Для того, чтобы однозначно определять лист как черновой - условимся, что имена таких листов будут начинаться с символа "_" (подчёркивания).
Данный вопрос заинтересовал меня, тем более, что с ним я и сам регулярно сталкивался, но решить его грамотно - все руки не доходили. Решил исправить эту ситуацию, тем более, что решение очевидно и элементарно: нужно написать код обработчиков событий.

Внимание:
Для того, чтобы вы могли использовать библиотеку, которая предоставлена в конце данной статьи, у вас на компьютере должна быть установлена бесплатная библиотека .Net Framework 2.0, а так же AutoCAD версии не ниже 2007.

Перед нами стоит 2 задачи:
1. Написать собственно код, выполняющий нужные нам действия.
2. Подключить полученную библиотеку (dll-файл) к AutoCAD таким образом, 
чтобы код загружался самостоятельно тогда, когда это нужно, дабы нам не
производить каждый раз это подключение вручную.

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

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

Шаг 1 (пишем код)...
Пишем код на C# :

  1.    1:  using System;
       2:  using Autodesk.AutoCAD.Runtime;
       3:  using Autodesk.AutoCAD.EditorInput;
       4:  using Autodesk.AutoCAD.ApplicationServices;
       5:  using Autodesk.AutoCAD.DatabaseServices;
       6:  using Autodesk.AutoCAD.Geometry;
       7:  using acadApp = Autodesk.AutoCAD.ApplicationServices.Application;
       8:  using System.Collections;
       9:   
      10:  [assembly: ExtensionApplication(typeof(Bushman.AutoCAD.AutoLoad))]
      11:  [assembly: CommandClass(typeof(Bushman.AutoCAD.Commands))]
      12:   
      13:  namespace Bushman.AutoCAD
      14:  {
      15:      /// <summary>
      16:      /// Данный класс содержит в себе точку входа и методы, необходимые
      17:      /// для корректной работы программы
      18:      /// </summary>
      19:      public class AutoLoad : IExtensionApplication
      20:      {
      21:          Editor ed;
      22:          Database db;
      23:          Document doc;
      24:          LayoutManager manager;
      25:   
      26:          /// <summary>
      27:          /// Метод, регистрирующий обработчики событий
      28:          /// </summary>     
      29:          void MyFunction()
      30:          {
      31:              Application.DocumentManager.DocumentActivated += new DocumentCollectionEventHandler(DocumentManager_DocumentActivated);
      32:              //Выполняем начальную инициализацию переменных
      33:              ed = acadApp.DocumentManager.MdiActiveDocument.Editor;
      34:              doc = acadApp.DocumentManager.MdiActiveDocument;
      35:              db = doc.Database;
      36:              manager = LayoutManager.Current;            
      37:              ed.WriteMessage(string.Format("\nBushman's .Net laboratory site: http://sites.google.com/site/bushmansnetlaboratory/home/managed-autocad/-net-laboratoria-autocad/sozdanie-pola-sceetcika-listov-v-dwg-fajle"));
      38:              ed.WriteMessage("\nИдет регистрация обработчиков событий для объектов 'Layout'...\n");            
      39:              manager.LayoutCreated += new LayoutEventHandler(manager_LayoutCreated);
      40:              manager.LayoutRemoved += new LayoutEventHandler(manager_LayoutRemoved);
      41:              manager.LayoutCopied += new LayoutCopiedEventHandler(manager_LayoutCopied);
      42:              manager.LayoutsReordered += new EventHandler(manager_LayoutsReordered);
      43:              manager.LayoutSwitched += new LayoutEventHandler(manager_LayoutSwitched);
      44:              manager.LayoutRenamed += new LayoutRenamedEventHandler(manager_LayoutRenamed);
      45:              db.Useri1 = manager.LayoutCount - 1;
      46:              ed.Regen();
      47:              ed.WriteMessage("\nРегистрация завершена успешно...\n");         
      48:          }
      49:   
      50:          void manager_LayoutRenamed(object sender, LayoutRenamedEventArgs e)
      51:          {
      52:              ShowMessage(string.Format("Лист переименован. \nСтарое имя: '{0}'\nНовое имя:'{1}'", e.Name, e.NewName));
      53:          }
      54:          /// <summary>
      55:          /// При инициализации документа присваиваем переменным соответствующие значения
      56:          /// </summary>
      57:          /// <param name="sender">Объект отправитель</param>
      58:          /// <param name="e">Аргумент, содержащий информацию об активируемом документе</param>
      59:          void DocumentManager_DocumentActivated(object sender, DocumentCollectionEventArgs e)
      60:          {
      61:              ed = e.Document.Editor;
      62:              doc = e.Document;
      63:              db = doc.Database;
      64:              manager = LayoutManager.Current;
      65:              ed.WriteMessage(string.Format("\nАктивирован документ {0}", doc.Name));
      66:          }
      67:   
      68:          void manager_LayoutSwitched(object sender, LayoutEventArgs e)
      69:          {
      70:              ShowMessage(string.Format("Произведено переключение листа"));
      71:          }
      72:   
      73:          void manager_LayoutsReordered(object sender, EventArgs e)
      74:          {
      75:              ShowMessage("Произведено перемещение листа");
      76:          }
      77:   
      78:          void manager_LayoutCopied(object sender, LayoutCopiedEventArgs e)
      79:          {
      80:              ShowMessage("Произведено копирование листа");
      81:          }
      82:   
      83:          void manager_LayoutRemoved(object sender, LayoutEventArgs e)
      84:          {
      85:              ShowMessage("Произведено удаление листа");
      86:          }
      87:   
      88:          void manager_LayoutCreated(object sender, LayoutEventArgs e)
      89:          {
      90:              ShowMessage("Создан новый лист");
      91:          }
      92:   
      93:          /// <summary>
      94:          /// Метод, изменяющий значение счетчика, содержащего количество нечерновых листов
      95:          /// в файле при произведении пользователем определенных действий и выводящий
      96:          /// информацию об этих изменениях. Черновым считается лист, наименование которого начинается с
      97:          /// символа "_" (подчёркивание).
      98:          /// </summary>
      99:          /// <param name="text">Текст, который должен быть показан перед числом листов</param>
     100:          private void ShowMessage(string text)
     101:          {
     102:              int layoutCount = -1;//Нам нужно исключить 'Model' из общего количества, а самих листов не может быть меньше 1.
     103:   
     104:          //Запускаю транзакцию
     105:              using (Transaction acTrans = db.TransactionManager.StartTransaction())
     106:              {
     107:                  // Открываю таблицу листов для чтения
     108:                  DBDictionary layoutDict = (DBDictionary)acTrans.GetObject(db.LayoutDictionaryId, OpenMode.ForRead);
     109:   
     110:                  foreach (DictionaryEntry id in layoutDict)
     111:                  {                    
     112:                      Layout ltr = (Layout)acTrans.GetObject((ObjectId)id.Value, OpenMode.ForRead);                 
     113:                      layoutCount = ltr.LayoutName[0] == '_' ? layoutCount : ++layoutCount;             
     114:                  }
     115:              } // завершение транзакции         
     116:              
     117:              //*********************************
     118:              db.Useri1 = layoutCount;
     119:              ed.WriteMessage(string.Format("\n{0}. Всего чистовых листов в файле: {1}\n", text, db.Useri1));
     120:              ed.Regen();//Не нравится мне эта строка кода, но что поделать - др. альтернативы пока не нашёл.
     121:          }
     122:   
     123:          #region IExtensionApplication Members
     124:          /// <summary>
     125:          /// Метод, запускающийся на исполнение в случае
     126:          /// автоматической загрузки данной библиотеки
     127:          /// </summary>
     128:          public void Initialize()
     129:          {
     130:              acadApp.DocumentManager.DocumentCreated +=
     131:                  new DocumentCollectionEventHandler(DocumentManager_DocumentCreated);
     132:              MyFunction();
     133:          }
     134:   
     135:          void DocumentManager_DocumentCreated(object sender, DocumentCollectionEventArgs e)
     136:          {
     137:              MyFunction();
     138:          }
     139:   
     140:          /// <summary>
     141:          /// Этот метод вызывается, когда происходит закрытие приложения AutoCAD
     142:          /// </summary>
     143:          public void Terminate()
     144:          {
     145:              //Нам здесь удалять нечего
     146:          }
     147:   
     148:          #endregion
     149:      }
     150:   
     151:      /// <summary>
     152:      /// В этом классе содержатся методы, которые пользователи могут вызывать
     153:      /// подобно обычным командам AutoCAD. Перед каждым методом стоит атрибут
     154:      /// CommandMethod, указывающий имя команды для вызова метода в среде
     155:      /// САПР
     156:      /// </summary>
     157:      public class Commands
     158:      {
     159:          [CommandMethod("demo")]
     160:          public void DemoCommand()
     161:          {
     162:              acadApp.DocumentManager.MdiActiveDocument.Editor.WriteMessage("Код написан под AutoCAD 2009");
     163:          }
     164:      }
     165:  }

Шаг 2 (решаем вопрос по автоматической загрузке модуля)...

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

Если вы разместили библиотеки не локально на своём компьютере, а в сети или в интернете, то вам нужно ознакомиться с
 этой 
информацией.

Внимание!
Количество листов мы сохраняем в переменной USERI1, ссылку на которую мы можем получить в нашем поле, разместив в нём такой текст: %<\AcVar USERI1>%.

Всё, задача решена. Теперь можно открывать AutoCAD и работать.

Ниже прилагается дистрибутив библиотек.

Успехов в работе!
ċ
AcadPlagins.rar
(6k)
Андрей Бушман,
10 окт. 2011 г., 07:06
Comments