Сообщество программистов Autodesk в СНГ

ADN Club => AutoCAD .NET API => Тема начата: JohnJ от 06-10-2014, 07:25:19

Название: Сделать текущим лист при работе в фоновом режиме
Отправлено: JohnJ от 06-10-2014, 07:25:19
Добрый день. Работаю с файлом в фоновом режиме (т.е. загружаю файл в Database без открытия документа в Автокаде). В процессе работы создаётся вкладка листа, в пространстве листа выводятся некоторые объекты, затем документ сохраняется.
Вопрос 1: как сделать, что бы нужный лист стал активным? LayoutManager в данном случае не доступен, а свойство layout.TabSelected = true выделяет лист, но не делает его активным. Свойство Database.CurrentSpaceId закрыто для изменения.
Вопрос 2: как сделать адекватным отображение листа? При открытии вышеописанного сохранённого документа в Автокаде и выборе листа (хотя он должен быть уже активным, см. вопрос 1), отображается только его небольшая часть (левый нижний угол), и масштабирование вращением колёсика мышки не позволяет увидеть лист целиком, только двойной щелчок колёсиком мыши спасает.
Название: Re: Сделать текущим лист при работе в фоновом режиме
Отправлено: bargool от 06-10-2014, 10:44:39
Сразу вопрос в тему: а удается ли в фоне настроить лист? Формат там, плоттер и проч.? У меня в свое время не получилось..
Название: Re: Сделать текущим лист при работе в фоновом режиме
Отправлено: JohnJ от 06-10-2014, 10:49:53
да, это удаётся. У меня есть заранее заготовленный PlotSettings, который я потом указываю листу:
Код - C# [Выбрать]
  1. using (var layout = tr.GetObject(paper_space.LayoutId, OpenMode.ForWrite) as Layout) {
  2. layout.CopyFrom(ps);
  3. }
Название: Re: Сделать текущим лист при работе в фоновом режиме
Отправлено: bargool от 06-10-2014, 11:00:01
Я про вот эту тему: http://forum.dwg.ru/showthread.php?t=83750, там же есть ссылка на гитхаб с кодом
У меня там тоже есть работа с заранее подготовленными PlotSettings
Я тоже пробовал сделать layout.CopyFrom без захода на лист с помощью LayoutManager, но проблема была такова, что некоторые настройки в итоге сбрасывались при заходе на лист пользователем. Сбрасывались в некое значение "по-умолчанию". Насколько я помню, это касалось области печати, и может чего ещё.
Причём мне казалось, что всё работает, но просто у меня желаемые настройки совпадали с этими самыми "по-умолчанию"... обнаружилось только при экспериментах. Если у вас всё в порядке с этим, отпишитесь, пожалуйста, я тогда ещё поковыряю, где я там накосячил.
Название: Re: Сделать текущим лист при работе в фоновом режиме
Отправлено: JohnJ от 06-10-2014, 11:29:12
Интересно, что некоторое время назад я тоже написал схожую программу - из модели в листы. Но там я использовал LayoutManager. В разрабатываемой сейчас программе он не используется, и я пока не знаю - возможно тоже будут схожие с вашими проблемы. Посмотрим. Было бы лучше, если бы вы конкретно указали, какое свойство на что меняется. Я бы смог проверить тогда сразу.
Название: Re: Сделать текущим лист при работе в фоновом режиме
Отправлено: JohnJ от 06-10-2014, 14:19:51
Второй вопрос разрешился, благодаря тому, что полазал в исходниках программы Bargool. Там есть такие строки
Код - C# [Выбрать]
  1. int vpCount = layout.GetViewports().Count;
  2.                         if (vpCount == 0)
  3.                         {
  4.                                 throw new System.Exception(String.Format("Layout {0} не инициализирован", layout.LayoutName));
  5.                         }
И действительно, я ведь в данном случае не создавал лист, а использовал один из двух существующих, которые создавались сами при создании БД (а в предыстории к вопросам описал совсем другую ситуацию, виноват). И лист был просто не проинициализирован, видимо. Вызов layout.Initialize() разрешил эту проблему.
Название: Re: Сделать текущим лист при работе в фоновом режиме
Отправлено: Александр Ривилис от 06-10-2014, 14:55:56
Вопрос 1: как сделать, что бы нужный лист стал активным? LayoutManager в данном случае не доступен, а свойство layout.TabSelected = true выделяет лист, но не делает его активным. Свойство Database.CurrentSpaceId закрыто для изменения.
Насколько мне известно этого сделать нельзя. Но так как на 100% не уверен - отправлю этот вопрос в ADN DevHelp.
Вопрос 2: как сделать адекватным отображение листа? При открытии вышеописанного сохранённого документа в Автокаде и выборе листа (хотя он должен быть уже активным, см. вопрос 1), отображается только его небольшая часть (левый нижний угол), и масштабирование вращением колёсика мышки не позволяет увидеть лист целиком, только двойной щелчок колёсиком мыши спасает.
Ну вообще-то для этой цели нужно вид настроить. У текущего Layout получаешь Layout.GetViewports и настраиваешь первый из полученных Viewport
Название: Re: Сделать текущим лист при работе в фоновом режиме
Отправлено: JohnJ от 07-10-2014, 04:56:50
Насколько мне известно этого сделать нельзя. Но так как на 100% не уверен - отправлю этот вопрос в ADN DevHelp.
Спасибо! Есть надежда, что возможно через подключение какой-либо dll, как в случае с экспортом листа в модель: там подключается AcExportLayout.dll
По подсказке KEAN WALMSLEY удалось частично решить вопрос: Database.TileMode установил в false. В текущей задаче этого достаточно, меня устраивает. Но как указать конкретный layout - желание знать остаётся.

Ну вообще-то для этой цели нужно вид настроить. У текущего Layout получаешь Layout.GetViewports и настраиваешь первый из полученных Viewport
У того layout метод GetViewports возвращал 0, пока я не вызвал layout.Initialize(). Но после вызова метода инициализации основной видовой экран листа настраивать и не пришлось - он стал нормально отображаться сам.
Название: Re: Сделать текущим лист при работе в фоновом режиме
Отправлено: Александр Ривилис от 07-10-2014, 09:06:15
Но как указать конкретный layout - желание знать остаётся.
Ждем ответ от ADN DevHelp. Хотя я подозреваю, что он будет отрицательный. Точно помню, что где-то в открытых источниках это уже было, но где именно сейчас не нашел. Тут еще есть такой нюанс, что в ObjectARX есть значительно больше возможностей у LayoutManager, чем в .NET (например, метод AcDbLayoutManager::setCurrentLayoutId устанавливает активный Layout по его ObjectId) и возможно именно этой функциональности не хватает.
Название: Re: Сделать текущим лист при работе в фоновом режиме
Отправлено: JohnJ от 07-10-2014, 13:15:57
в ObjectARX есть значительно больше возможностей у LayoutManager

Это, опять же, LayoutManager...
Название: Re: Сделать текущим лист при работе в фоновом режиме
Отправлено: Александр Ривилис от 07-10-2014, 14:03:54
Это, опять же, LayoutManager...
В ObjectARX с ним всё хитрее. Во всяком случае в документации на метод setCurrentLayoutId говорится, что он переключает текущий Layout для активной базы данных. А активная в данном случае в ObjectARX может быть переключена. Я на досуге поэкспериментирую с тем работает ли это в ObjectARX или нет.
Название: Re: Сделать текущим лист при работе в фоновом режиме
Отправлено: JohnJ от 07-10-2014, 14:05:10
хмм. Спасибо, интересно!
Название: Re: Сделать текущим лист при работе в фоновом режиме
Отправлено: Александр Ривилис от 07-10-2014, 15:23:30
хмм. Спасибо, интересно!
Ну что же. Моя интуиция не подвела. Этот код на ObjectARX работает (т.е. правильно устанавливает активный Layout в чертеже, который не загружен в редактор AutoCAD). Во всяком случае в AutoCAD 2012, на котором я проверял.
Код - C++ [Выбрать]
  1. static Acad::ErrorStatus SetCurLayout(ACHAR *fileName, ACHAR *layoutName)
  2. {
  3.   Acad::ErrorStatus es = Acad::eOk;
  4.   AcApDocManager *pDocMan = acDocManagerPtr();
  5.   AcDbDatabase *db = new AcDbDatabase(false,false);
  6.   if ((es = db->readDwgFile(fileName)) != Acad::eOk) {
  7.     acutPrintf(_T("\nОшибка открытия файла! %s"),acadErrorStatusText(es));
  8.     delete db; return es;
  9.   }
  10.   if ((es = db->closeInput(true)) != Acad::eOk) {
  11.     acutPrintf(_T("\nОшибка closeInput! %s"), acadErrorStatusText(es));
  12.     delete db; return es;
  13.   }
  14.   AcApDocument *pDoc = pDocMan->document(db);
  15.   if (!pDoc) {
  16.     acutPrintf(_T("\nНе найден документ!"));
  17.     delete db; return es;
  18.   }
  19.   AcDbObjectId idLayout;
  20.   {
  21.     AcDbDictionaryPointer pDict(db->layoutDictionaryId(),AcDb::kForRead);
  22.     if (pDict.openStatus() == Acad::eOk) {
  23.       es = pDict->getAt(layoutName, idLayout);
  24.       if (es != Acad::eOk) {
  25.         acutPrintf(_T("\nНе найден лист \'%s\'!"), layoutName);
  26.         delete db; return es;
  27.       }
  28.     }
  29.   }
  30.   if (!idLayout.isNull()) {
  31.     AcApDocument *pOldDoc = pDocMan->curDocument();
  32.     if ((es = pDocMan->setCurDocument(pDoc)) != Acad::eOk) {
  33.         acutPrintf(_T("\nОшибка pDocMan->setCurDocument(pDoc)! %s"),acadErrorStatusText(es));
  34.         delete db; return es;        
  35.     }
  36.     AcDbHostApplicationServices *pHost = acdbHostApplicationServices();
  37.     AcDbLayoutManager *pLayMan = pHost->layoutManager();
  38.     es = pLayMan->setCurrentLayoutId(idLayout);
  39.     es = pDocMan->setCurDocument(pOldDoc);
  40.     es = db->saveAs(layoutName);
  41.     delete db;
  42.   } else {
  43.     delete db;
  44.   }
  45.   return es;
  46. }
Название: Re: Сделать текущим лист при работе в фоновом режиме
Отправлено: Александр Ривилис от 06-11-2014, 11:10:46
Получил ответ от ADN DevHelp. В текущей реализации AutoCAD .NET API переключение листа в неактивной базе невозможно. Запросили изменение функциональности у разработчиков. Но это будет в лучшем случае в следующей версии AutoCAD.
Название: Re: Сделать текущим лист при работе в фоновом режиме
Отправлено: JohnJ от 06-11-2014, 11:14:52
Спасибо! Благо, что хоть TileMode есть :)
Название: Re: Сделать текущим лист при работе в фоновом режиме
Отправлено: Александр Ривилис от 04-12-2014, 17:50:25
Сегодня мне из ADN DevHelp прислали такой код, который по их утверждению (я еще не успел потестировать) должен работать:
Код - C# [Выбрать]
  1. [CommandMethod("TestLayout")]
  2. public void TestLayout()
  3. {
  4.   using (Database db = new Database(false, false))
  5.   {
  6.     db.ReadDwgFile(@"C:\TestDWG.dwg",
  7.        FileOpenMode.OpenForReadAndWriteNoShare, false, "");
  8.     db.CloseInput(true);
  9.     Database olddb = HostApplicationServices.WorkingDatabase;
  10.     HostApplicationServices.WorkingDatabase = db;
  11.     LayoutManager lMan = LayoutManager.Current;
  12.     lMan.CurrentLayout = "Layout1";
  13.     // set the working database back before saveas
  14.     HostApplicationServices.WorkingDatabase = olddb;
  15.     db.SaveAs(@"C:\TestDWG-new.dwg", null);
  16.   }
  17. }
Особенность его в том, что сначала идет переключение на старую рабочую базу, а уже потом сохранение. Попробуй.
Название: Re: Сделать текущим лист при работе в фоновом режиме
Отправлено: JohnJ от 05-12-2014, 07:23:54
Спасибо! Опробую.
Название: Re: Сделать текущим лист при работе в фоновом режиме
Отправлено: Александр Ривилис от 09-12-2014, 09:08:05
Спасибо! Опробую.
И как?
Название: Re: Сделать текущим лист при работе в фоновом режиме
Отправлено: JohnJ от 09-12-2014, 09:34:43
Ну, как я уже и говорил, в текущем проекте мне хватает Database.TileMode. Но на будущее очень даже пригодится. Проверял только в autocad 2014 - сначала пару раз вылетел автокад. Так и не понял - почему. Потом выполнил пошагово - всё нормально. И больше автокад не вылетал, нормально срабатывало. Так и не понял, в чём была по-началу загвоздка.
Сейчас, для интереса, проверил при fiberworld = 0 - тоже всё нормально сработало, так что рецепт - замечательный!
Название: Re: Сделать текущим лист при работе в фоновом режиме
Отправлено: Александр Ривилис от 09-12-2014, 10:50:38
тоже всё нормально сработало, так что рецепт - замечательный!
Так и запишем! :)