Тема: Как сделать документ активным?

Уважаемые коллеги!
Открыл новый документ одним из известных способов.
После зтого пытаюсь вставить wblock, но нахожу его
в предыдущем документе. Похоже что новый документ
не активен. Как его сделать активным? Моет быть есть
другое решение?
Спасибо

Re: Как сделать документ активным?

Копать здесь - в классе AcApDocumentManager
Вот пара функций из него

acDocManager->activateDocument()
virtual Acad::ErrorStatus activateDocument(
    AcApDocument* pAcTargetDocument,
    boolbPassScript = Adesk::kFalse) = 0;

pAcTargetDocument    Input pointer to the target document to switch to
bPassScript    Input Boolean indicating whether to continue scripts when switching to another document
This function will switch from the current document to another document. The function will NOT suspend execution of the code running under the application context. The caller is suspended if it is a normal or nomadic context. If the bPassScript is Adesk::kTrue, then the script that has called the command that is performing a document change will continue to run. This argument allows a script to continue running across documents.
----------------------------

acDocManager->mdiActiveDocument()
virtual AcApDocument* mdiActiveDocument() const = 0;

This function returns the MDI active document. The associated function, curDocument(), returns the document having current context. curDocument() and mdiActiveDocument() can be different. You can call curDocument() to make a document "current"  without actually activating it. After finish your AcDbDatabase operation under the temporary current document, call setCurDocument(acDocManager->mdiActiveDocument()) to reset the MDI active document as the current document.

Re: Как сделать документ активным?

Я, конечно, пробовал. Не получается.
Может где-то в коде ошибка?

char sDocName[_MAX_PATH];
char sTmpDocName[_MAX_PATH];
 AcApDocument *pDoc, *pTmpDoc;
 pDoc = acDocManager->curDocument();
//Здесь выясняю о каком документе идет речь
 strcpy(sDocName, pDoc->fileName());
 pTmpDoc = acDocManager->mdiActiveDocument();
//Здесь снова выясняю имя документа, и выясняется
//что это то, что мне нужно
strcpy(sTmpDocName, pTmpDoc->fileName());
//Здесь при попытке сделать его активным все зависает
//и, если я убираю его нажав на Х, выполнение продолжается
//и блок вставляется снова в предыдущий документ
 acDocManager->activateDocument(pTmpDoc, Adesk::kTrue);
 wbInsert();

Спасибо

Re: Как сделать документ активным?

Попробуй сделать текущим тот документ, в который тебе надо вставить блок

Re: Как сделать документ активным?

Не особо вдумываясь.
А какая AcDbDatabase активна во время wbInsert()?

Re: Как сделать документ активным?

> VVV
Ничего не получается.
Простая задача. Требуется создать новый документ во время выполнения программы или сразу после ввода команды. Дальше работа с этим документом, вставка блока например. Сделал два варианта. Создал команду в Application context. Открыл новый документ(для краткости не описываю как). Пока все ОК. Теперь надо что-то делать в документе, но я то в Application context. Надо как-то переключиться в Document context  насколько я знаю. Но как?
Во втором варианте создал команду в Document context и открыл новый документ. Никакие ухищрения не помогаЮт. Блок вставляется только в предыдущий документ.
Вообще в форуме мало дискусий на эту тему. Либо всем все ясно, либо... Сколько же надо накидать кода чтобы решить такуЮ простуЮ задачу?
Наверное в Autodesk что-то не учли.Простейшие операции:
Открыть, закрыть, переклЮчится, сделать активным, несмотря
на то что существуЮт, воспользовться ими Это головная боль
>>Michael
В этом вся загвозка что предыдущего документа

Re: Как сделать документ активным?

> BSH
Cоздание программ, работающих в многодокументном режиме, задача не очень простая. Поэтому и публикаций никаких и в документации не очень много прописано.
Я протестировал приведенный код под R16: до wbInsert() ? все нормально? даже,  несмотря на то, что зачем-то активизируется уже и без того активный документ. Может быть,  вся проблема в реализации wbInsert()?

Re: Как сделать документ активным?

> BSH
Скажу честно, не проверял в рассматриваемом контексте, но помоему так :

acdbHostApplicationServices()->setWorkingDatabase(acDocManager->curDocument()->database());

Re: Как сделать документ активным?

> VVV
разве реализация имеет значение? Скажу Вам
по секрету, что несмотря на то, что давно не пользуюсь
ADS, в данном случае я  в спешке использовал
старую функцию когда-то сделанную под ADS. Ну и что?
В ObjectARX функции ADS нормально себя ведут.
С другой стороны может быть  Michael прав, pTmpDoc
указывает на новый документ, это проверено.
Дальше получаем database, и методами ObjectARX вставляем
блок. Может так правильно?

Re: Как сделать документ активным?

> BSH
В том,  что в ObjectARX имена всех ADS функций переопределяются автоматически, уже давно нет большого секрета. Говоря о реализации,  я имел в виду не то, под чем  изготовлен этот модуль (под ObjectARX или под  ADS), а -  нет ли в нем каких-либо ошибок. Я сделал это крамольное предположение исходя из того, что при тестировании у меня (в отличие от Вашего случая) никакого зависания в процессе активизации документа не происходило. А следом за этим оператором стоит только вызов функции wbInsert();. Теперь я понял, что это старый и не раз испытанный модуль и нет никаких резонов на него грешить.
    А проверкой я занялся по той причине, что по тексту была явно видна попытка активизировать и без того уже  активный документ (интересно было посмотреть, чем это закончиться). В приведенном фрагменте кода pTmpDoc == pDoc и указывают они  на один и тот же документ (тот, который на данный момент и текущий и активный), если, конечно, где-то выше не переопределен текущий документ. Это обычная ситуация (текущий = активный), когда команда запускается из командной строки любого из открытых документов. Вообще, насколько мне помниться, чтобы добраться до  базы данных конкретного документа из ARX,  надо все же сделать этот документ (хотя бы на время) текущим (не обязательно активным) и по документу определить текущую (рабочую) базу чертежа и с ней работать. А по завершении всех манипуляций надо вернуть признак текущего документа активному.

Re: Как сделать документ активным?

> VVV
Интересная ситуация. То же самое у меня указывает
на разные документы. Но это не важно. Я сделал так как
описал выше. Все получилось. За одним исключением.
Если я открываю новый документ по технологии Automation
все нормально, ничего не висит. Как только я пытаюсь
проделать то же самое с нижеописанной функцией
она открывает новый документ, доходит до конца и при этом
висит, т.е в Debug-ере дальше выполнение не идет!
Это я вставил в команду сделанную в Document context

void openDoc(char* pData)
{
          acDocManager->executeInApplicationContex(openDocHelper, (void *)pData);
 }
void openDocHelper(void *pData)
{
           acDocManager->appContextOpenDocument((const char *)pData);
  }

Кстати, что-то похожее было у Алексея (2003-10-31)

Re: Как сделать документ активным?

> BSH
Что-то мне все перестает быть понятным: почему вдруг  то, что висло раньше, неожиданно,  получилось ?как описал выше?, а открытие документа, получавшееся до этого (для краткости не описанное), неожиданно стало? виснуть.  Что представляет из себя открывание документа по ?по технологии Automation?? В моем представлении это и есть открытие его In ApplicationContex. До какого ?конца? доходит, а потом (после открытия документа ) неожиданно виснет функция,   сделанная в Document context? А почему бы не виснуть функции appContextOpenDocument() в Document context, если про нее написано в документации ? ?It can only be called from the application context??

Re: Как сделать документ активным?

> Вы
правы. Старался быть кратким. но переборщил.
Ситуация такова:
Есть обычная программа, запускается командой определенной
в Document context. Мне нужно было, после выполнения некоторых действий, открыть новый документ и вставить
в него wblock. Всего то дел! Как ни пытался, все одно и то же,
документ открывается, а блок вставляется в предыдущий
документ. Стал искать в ADN, и в одном месте я вычитал,
что используя вышеприведенные функции, появляется
эффект незавершенности команды выполненной в предыдущем
документе, о чем AutoCAD часто сообщает(я это проверял, точно). Дальше они рекомендуют вообще в таких случаях
пользоваться COM-ActiveX interface технологией (это я имел ввиду под термином Automation). Но COM может работать только из Application context! Поэтому я сделал еще одну команду в Application context, и с помощью COM открываю новый документ. Теперь надо вставить блок. Но я  Application context! Создаю еще одну команду в Document context. И в ней
вызываю функцию wbInsert. И все ОК! Но три команды!.
Что-то здесь не то.
Почему я не могу все это проделать из одной команды?
Сделал еще одну команду в Document context. Поытался
открыть новый документ с помощью вышеприведенных
функций, а потом вставить wbInsert(). Конечно, ничего
хорошего из этого не вышло. Ну это хоть обьяснить можно.
В общем получается, насколько мне известно,  Application context ограничен, но я вынужден его использовать, а в
Document context могу делать все, кроме открытия
документа! АБСУРД какой-то.

Re: Как сделать документ активным?

Спасибо, BSH, за подробные разъяснения. Теперь понятно, что делалось и как.
Да, в ARX все манипуляции с программным открытием документов и их закрытием из Document context делаются не очень просто. Я хоть и не имею доступа в  ADN,  но тоже встречался с рекомендациями использовать в таких случаях ActiveX interface. Но для решения описанной задачи -  три команды не очень, на мой взгляд, много. Если необходимо минимизировать количество используемых команд, то это, наверное,  можно сделать,  написав приложение полостью в Application context-те  и обойтись всего одной или двумя командами.

Re: Как сделать документ активным?

Надеюсь, это поможет. Ниже приведен фрагмент команды, создающей новый чертеж из стандартных примитивов на основе чертежа из собственных, нестандартных.
Команда вызывается из контекста документа, но передает управление в контекст приложения.
Примитивы заливаются именно туда, куда нужно. Для гарантии во все функции, отвечающие за вставку примитивов Database и BlockRecord передаются  в явном виде.

void doCreateExplodedView(void* pData)
{
    EVDATA* pEvData=(EVDATA*)pData;
    AcApDocument* pDoc=pEvData->pDoc;    
    
    acDocManagerPtr()->lockDocument(pDoc);
    
    //.....
    //Получение набора примитивов из текущего чертежа
    
    acDocManagerPtr()->unlockDocument(pDoc);    
    
    int nMax;
    
    AcDbBlockTable *pBlockTable;
    AcDbBlockTableRecord *pBlockTableRecord;
    
    Acad::ErrorStatus es=acDocManagerPtr()->appContextNewDocument(adtEnv.GetFrontTemplate());
    if(es!=Acad::eOk)
        throw es;
    
    AcApDocument* pNewDoc=acDocManagerPtr()->curDocument();    
    acDocManagerPtr()->lockDocument(pNewDoc);    
    
    es=pNewDoc->database()->getSymbolTable(pBlockTable, AcDb::kForRead);
    if(es!=Acad::eOk)
        throw es;
    
    es=pBlockTable->getAt(ACDB_MODEL_SPACE, pBlockTableRecord,AcDb::kForWrite);
    pBlockTable->close();
    if(es!=Acad::eOk)
        throw es;
    
    // Заливка примитивов в pBlockTableRecord
........................................
    updateDocName(pNewDoc->database(),model.GetDocName());
    
    // Сохранение
    CFileDialog dlgFile(FALSE, "dwg", szDocTitle, OFN_OVERWRITEPROMPT,"Файлы AutoCAD (*.dwg)|*.dwg||", CWnd::FromHandle(adsw_acadMainWnd()));
    if(dlgFile.DoModal()==IDOK)
    {
        pNewDoc->database()->saveAs(dlgFile.GetPathName());    
    }
    
    acDocManagerPtr()->unlockDocument(pNewDoc);        
    
    acDocManagerPtr()->activateDocument(pDoc);    
}
void devCreateExplodedView()
{
//.....
    acDocManagerPtr()->executeInApplicationContext(doCreateExplodedView,&EvData);    
}

Re: Как сделать документ активным?

> DiKey
от всей души благодарен за пример. Это связано
с ADT?

Re: Как сделать документ активным?

Пожалуйста :)
Но в ADT я вообще ничего не понимаю.

Re: Как сделать документ активным?

> DiKey
Откуда это:
EVDATA* pEvData=(EVDATA*)pData;
adtEnv.GetFrontTemplate());
Спасибо

Re: Как сделать документ активным?

executeInApplicationContext принимает в качестве аргумента функцию, которая, в свою очередь, имеет один аргумент типа void*. То есть, для того, чтобы передать туда собственный набор параметров, этот набор пакуется  в собственную структуру (struct), указатель на которую и передается в executeInApplicationContext.
Т.е.

EVDATA EvData;
//присвоение полей структуры
acDocManagerPtr()->executeInApplicationContext(doCreateExplodedView,&EvData);

Таким образом, Вы можете переопределить EVDATA как Вам заблагорассудится.
Остальные неясные фрагменты с непонятными названиями классов :) - это просто невычищенные остатки кода процедуры, из которой брался пример. К вопросу это отношения не имеет.

Re: Как сделать документ активным?

> DiKey
Спасибо, теперь все понятно!