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

Автор Тема: Изменение текстовых значений внутри блока  (Прочитано 7377 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Тема содержит сообщение с Решением. Нажмите здесь чтобы посмотреть его.

Оффлайн qstАвтор темы

  • ADN OPEN
  • Сообщений: 17
  • Карма: 0
Всем доброго времени суток


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

Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Runtime;
  5.  
  6. namespace BAC
  7. {
  8.     public class CommandClass
  9.     {
  10.         [CommandMethod("VJUH")]
  11.         public void RunCommand()
  12.         {
  13.             Document adoc = Application.DocumentManager.MdiActiveDocument;
  14.  
  15.             if (adoc == null)
  16.                 return;
  17.  
  18.             Editor ed = adoc.Editor;
  19.  
  20.             Database db = adoc.Database;
  21.  
  22.  
  23.  
  24.             using (Transaction tr = db.TransactionManager.StartTransaction())
  25.             {
  26.  
  27.                 BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
  28.  
  29.                 if (bt.Has("A3FRAME_1"))
  30.                     return;
  31.  
  32.                 BlockTableRecord btr = tr.GetObject(bt["A3_FRAME"], OpenMode.ForRead) as BlockTableRecord;
  33.                 foreach (ObjectId Id in btr)
  34.                 {
  35.                     // DBText changing
  36.                     if (Id.ObjectClass == RXObject.GetClass(typeof(DBText)))
  37.                     {
  38.  
  39.                         DBText text = tr.GetObject(Id, OpenMode.ForRead) as DBText;
  40.                         if (text.TextString == "Дата")
  41.                         {
  42.                             tr.GetObject(Id, OpenMode.ForWrite);
  43.                             text.TextString = "DATE";
  44.                             break;
  45.                         }
  46.                     }
  47.                 }
  48.                 tr.Commit();
  49.                
  50.             }
  51.         }      
  52.     }
  53. }

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
qst,
Приветствую на форуме!
Во время запуска команды в автокаде происходит ошибка.
Какая (текст ошибки или картинка)?  У тебя в коде нет проверок на ошибки.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Во тут написана полная ерунда:
Код - C# [Выбрать]
  1. DBText text = tr.GetObject(Id, OpenMode.ForRead) as DBText;
  2. if (text.TextString == "Дата")
  3. {
  4.     tr.GetObject(Id, OpenMode.ForWrite);
  5.     text.TextString = "DATE";
  6.     break;
  7. }
Сам подумай и исправь.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Подсказка. После этого кода:
Код - C# [Выбрать]
  1. tr.GetObject(Id, OpenMode.ForWrite);
переменная text не меняется и она как была открыта "для чтения", так и остаётся такой же. И соответственно попытка изменить её значение приводит к исключению в строке:
Код - C# [Выбрать]
  1. text.TextString = "DATE";
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн qstАвтор темы

  • ADN OPEN
  • Сообщений: 17
  • Карма: 0
Александр Ривилис,

Спасибо за подсказку.
Сделал так, ошибка в автокаде пропала, но текстовое значение все равно не поменялось. Я двигаюсь в нужном направлении?

Код - C# [Выбрать]
  1. DBText text = tr.GetObject(Id, OpenMode.ForRead) as DBText;
  2.                         if (text.TextString == "Дата")
  3.                         {
  4.                             text.UpgradeOpen();
  5.                             text.TextString = "DATE";
  6.                             break;
  7.                         }

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
После завершения транзакции добавь ed.Regen()
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн qstАвтор темы

  • ADN OPEN
  • Сообщений: 17
  • Карма: 0
Не помогло. В приложении файл на котором пробую


Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Runtime;
  5.  
  6. namespace BAC
  7. {
  8.     public class CommandClass
  9.     {
  10.         [CommandMethod("VJUH")]
  11.         public void RunCommand()
  12.         {
  13.             Document adoc = Application.DocumentManager.MdiActiveDocument;
  14.  
  15.             if (adoc == null)
  16.                return;
  17.  
  18.             Editor ed = adoc.Editor;
  19.             Database db = adoc.Database;
  20.            
  21.             using (Transaction tr = db.TransactionManager.StartTransaction())
  22.             {
  23.                 BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
  24.  
  25.                 if (bt.Has("1"))
  26.                     return;
  27.  
  28.                 BlockTableRecord btr = tr.GetObject(bt["1"], OpenMode.ForRead) as BlockTableRecord;
  29.                 foreach (ObjectId Id in btr)
  30.                 {
  31.                     // DBText changing
  32.                     if (Id.ObjectClass == RXObject.GetClass(typeof(DBText)))
  33.                     {
  34.                         DBText text = tr.GetObject(Id, OpenMode.ForRead) as DBText;
  35.                         if (text.TextString == "Дата")
  36.                         {
  37.                             text.UpgradeOpen();
  38.                             text.TextString = "DATE";
  39.                             break;
  40.                         }
  41.                     }
  42.                 }
  43.                 tr.Commit();
  44.                 ed.Regen();
  45.             }
  46.         }      
  47.     }
  48. }

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Это как?
Код - C# [Выбрать]
  1.         if (bt.Has("1"))
  2.           return;
  3.  
Т.е. ты проверил, что блок есть и вместо того, чтобы его обработать выходишь из команды?
Кроме того из транзакции так выходить нельзя - необходимо вызвать сначала её Commit(), иначе происходит откат до начала транзакции.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Отмечено как Решение qst 06-08-2018, 15:45:06

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Вот так работает:
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Runtime;
  5.  
  6. namespace BAC
  7. {
  8.   public class CommandClass
  9.   {
  10.     [CommandMethod("VJUH")]
  11.     public void RunCommand()
  12.     {
  13.       Document adoc = Application.DocumentManager.MdiActiveDocument;
  14.  
  15.       if (adoc == null)
  16.         return;
  17.  
  18.       Editor ed = adoc.Editor;
  19.       Database db = adoc.Database;
  20.  
  21.       using (Transaction tr = db.TransactionManager.StartTransaction())
  22.       {
  23.         BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
  24.  
  25.         if (!bt.Has("1"))
  26.         {
  27.           tr.Commit();
  28.           return;
  29.         }
  30.  
  31.         BlockTableRecord btr = tr.GetObject(bt["1"], OpenMode.ForRead) as BlockTableRecord;
  32.         foreach (ObjectId Id in btr)
  33.         {
  34.           // DBText changing
  35.           if (Id.ObjectClass == RXObject.GetClass(typeof(DBText)))
  36.           {
  37.             DBText text = tr.GetObject(Id, OpenMode.ForRead) as DBText;
  38.             if (text.TextString == "Дата")
  39.             {
  40.               text = tr.GetObject(Id, OpenMode.ForWrite) as DBText;
  41.               text.TextString = "DATE";
  42.               break;
  43.             }
  44.           }
  45.         }
  46.         tr.Commit();
  47.       }
  48.       ed.Regen();
  49.     }
  50.   }
  51. }




Следует учесть, что так будет работать только для нединамических блоков - для динамических нужно найти все анонимные блоки, соотвествующие динамическому блоку и внутри каждого из этих анонимных блоков проделать эту операцию.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн qstАвтор темы

  • ADN OPEN
  • Сообщений: 17
  • Карма: 0
Александр Ривилис,


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

Хочу добавить в исходную конструкцию запись в еще одно текстовое поле внутри этого же блока, но отрабатывается сценарий только для первого текстового поля.
Для записи в каждый новый BTR нужно создавать отдельную транзакцию?

Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Runtime;
  5.  
  6. namespace BAC
  7. {
  8.     public class CommandClass
  9.     {
  10.         [CommandMethod("VJUH")]
  11.         public void RunCommand()
  12.         {
  13.             Document adoc = Application.DocumentManager.MdiActiveDocument;
  14.  
  15.             if (adoc == null)
  16.                return;
  17.  
  18.             Editor ed = adoc.Editor;
  19.             Database db = adoc.Database;
  20.            
  21.             using (Transaction tr = db.TransactionManager.StartTransaction())
  22.             {
  23.                 BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
  24.  
  25.                 if (!bt.Has("A3FRAME_1"))
  26.                 {
  27.                     tr.Commit();
  28.                     return;
  29.                 }
  30.  
  31.                 BlockTableRecord btr = tr.GetObject(bt["A3FRAME_1"], OpenMode.ForRead) as BlockTableRecord;
  32.                 foreach (ObjectId Id in btr)
  33.                 {
  34.                     // DBText changing
  35.                     if (Id.ObjectClass == RXObject.GetClass(typeof(DBText)))
  36.                     {
  37.                         DBText text = tr.GetObject(Id, OpenMode.ForRead) as DBText;
  38.                         if (text.TextString == "Дата")                          
  39.                         {
  40.                             text.UpgradeOpen();
  41.                             text.TextString = "DATE";
  42.                             break;
  43.                         }
  44.                                              
  45.                         DBText text1 = tr.GetObject(Id, OpenMode.ForRead) as DBText;
  46.                         if (text1.TextString == "Черт.")
  47.                         {
  48.                             text1.UpgradeOpen();
  49.                             text1.TextString = "DRN";
  50.                             break;
  51.                         }                                            
  52.                     }
  53.                 }
  54.                 tr.Commit();
  55.             }
  56.             ed.Regen();
  57.         }      
  58.     }
  59. }
       



Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Для записи в каждый новый BTR нужно создавать отдельную транзакцию?
Зачем?
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Runtime;
  5.  
  6. namespace BAC
  7. {
  8.   public class CommandClass
  9.   {
  10.     [CommandMethod("VJUH")]
  11.     public void RunCommand()
  12.     {
  13.       Document adoc = Application.DocumentManager.MdiActiveDocument;
  14.  
  15.       if (adoc == null)
  16.         return;
  17.  
  18.       Editor ed = adoc.Editor;
  19.       Database db = adoc.Database;
  20.  
  21.       using (Transaction tr = db.TransactionManager.StartTransaction())
  22.       {
  23.         BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
  24.  
  25.         if (!bt.Has("A3FRAME_1"))
  26.         {
  27.           tr.Commit();
  28.           return;
  29.         }
  30.  
  31.         BlockTableRecord btr = tr.GetObject(bt["A3FRAME_1"], OpenMode.ForRead) as BlockTableRecord;
  32.         foreach (ObjectId Id in btr)
  33.         {
  34.           // DBText changing
  35.           if (Id.ObjectClass == RXObject.GetClass(typeof(DBText)))
  36.           {
  37.             DBText text = tr.GetObject(Id, OpenMode.ForRead) as DBText;
  38.             if (text.TextString == "Дата")
  39.             {
  40.               text = tr.GetObject(Id, OpenMode.ForWrite) as DBText;
  41.               text.TextString = "DATE";
  42.             } else if (text.TextString == "Черт.")
  43.             {
  44.               text = tr.GetObject(Id, OpenMode.ForWrite) as DBText;
  45.               text.TextString = "DRN";
  46.             }
  47.           }
  48.         }
  49.         tr.Commit();
  50.       }
  51.       ed.Regen();
  52.     }
  53.   }
  54. }
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Ну а если таких строк много, то конечно пользоваться if не следует. Следует воспользоваться словарём:
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Runtime;
  5. using System.Collections.Generic;
  6.  
  7. namespace BAC
  8. {
  9.   public class CommandClass
  10.   {
  11.     /// <summary>
  12.     ///  Таблица перекодировки текстов
  13.     /// </summary>
  14.     static Dictionary<string, string> tabTrans = new Dictionary<string, string>()
  15.     {
  16.       { "Дата",         "DATE" },
  17.       { "Черт.",        "DRN"},
  18.       { "РуссТекст1",    "EngText1"},
  19.       { "РуссТекст2",    "EngText2"},
  20.       { "РуссТекст3",    "EngText3"}
  21.     };
  22.     [CommandMethod("VJUH")]
  23.     public void RunCommand()
  24.     {
  25.       Document adoc = Application.DocumentManager.MdiActiveDocument;
  26.  
  27.       if (adoc == null)
  28.         return;
  29.  
  30.       Editor ed = adoc.Editor;
  31.       Database db = adoc.Database;
  32.  
  33.       using (Transaction tr = db.TransactionManager.StartTransaction())
  34.       {
  35.         BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
  36.  
  37.         if (!bt.Has("A3FRAME_1"))
  38.         {
  39.           tr.Commit();
  40.           return;
  41.         }
  42.  
  43.         BlockTableRecord btr = tr.GetObject(bt["A3FRAME_1"], OpenMode.ForRead) as BlockTableRecord;
  44.         foreach (ObjectId Id in btr)
  45.         {
  46.           // DBText changing
  47.           if (Id.ObjectClass == RXObject.GetClass(typeof(DBText)))
  48.           {
  49.             DBText text = tr.GetObject(Id, OpenMode.ForRead) as DBText;
  50.             // Ищем соотвествие текста по таблице
  51.             string engText = null;
  52.             if (tabTrans.TryGetValue(text.TextString, out engText))
  53.             {
  54.               // Если соотвествующий текст нашли - заменяем
  55.               text = tr.GetObject(Id, OpenMode.ForWrite) as DBText;
  56.               text.TextString = engText;
  57.             }
  58.           }
  59.         }
  60.         tr.Commit();
  61.       }
  62.       ed.Regen();
  63.     }
  64.   }
  65. }

Здесь таблица tabTrans закодирована явно, но правильнее её будет откуда-то прочитать. Это может быть и ini-файл, и xml-файл, и файл Excel или какая-то база данных.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн qstАвтор темы

  • ADN OPEN
  • Сообщений: 17
  • Карма: 0
Александр Ривилис,


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