OdDbViewportTableRecord (モデル空間ビューポート) および OdDbViewport (ペーパー空間ビューポート) オブジェクトは、現在の内部グラフィックスデバイスのOdGsViewポインタを格納します。これらのポインタは、以下のメソッドを使用してアクセスできます。
OdGsView* OdDbViewportTableRecord::gsView() const;
および
OdGsView* OdDbViewport::gsView() const
OdGsViewポインタは、現在のグラフィックスデバイス内のビューポートの現在のランタイム表現を表します (存在する場合)。
しかし、アプリケーションが単一のデータベースに対して複数のデバイスを呼び出す場合、これらのポインタをどうすればよいでしょうか?オブジェクトにはポインタが1つしかなく、複数のデバイスのポインタを格納することはできません。
問題のあるケースの例
これらのOdGsViewポインタは、この例のように、レイアウトヘルパーの構築中にデータベースビューポートオブジェクトにインストールされます。
OdGsModulePtr pGs = ::odrxDynamicLinker()->loadModule(OdWinGDIModuleName);
OdGsDevicePtr pDevice = pGs->createDevice();
pDwgContext->setDatabase(pDatabase);
pDevice = OdDbGsManager::setupActiveLayoutViews(pDevice, pDwgContext);
この例のOdDbGsManager::setupActiveLayoutViews呼び出しは、レイアウトヘルパーオブジェクトを作成し、それを返します。この呼び出しの後、この例のように、データベースビューポートオブジェクトから直接、またはOdDbAbstractViewportDataヘルパークラスを使用して、関連するOdGsViewオブジェクトにアクセスできます。
OdDbObjectPtr pViewportObject = pDatabase->activeViewportId().safeOpenObject();
OdDbAbstractViewportDataPtr pVpData(pViewportObject);
OdGsView *pGsView = pVpData->gsView(pViewportObject);
pGsViewは、以前に構築されたグラフィックスデバイス内の実際のランタイムビューポートデータ表現を指します。
たとえば、アプリケーションは現在、このグラフィックスデバイスを使用して画面にグラフィックスを描画しています。しかし、これらのグラフィックスをプリンターに送信したり、別のグラフィックスデバイスを使用して印刷プレビューを描画したりする必要がある場合はどうでしょうか。
OdGsDevicePtr pPrintDevice = pGs->createDevice();
pPrintDwgContext->setDatabase(pDatabase);
pPrintDevice = OdDbGsManager::setupActiveLayoutViews(pPrintDevice, pPrintDwgContext);
この2回目のOdDbGsManager::setupActiveLayoutViews呼び出しの後、データベースビューポートオブジェクト内のOdGsViewポインタは、新しい (印刷) デバイスポインタに切り替わります。
たとえば、印刷が完了した後、印刷デバイスを破棄できます。しかし、データベースビューポートオブジェクトには印刷デバイスビューへのポインタがまだ含まれている可能性があるため、返されたポインタがnullであるかどうかを正しくチェックしたとしても、以下のコードはアプリケーションクラッシュを引き起こす可能性があります。
OdDbObjectPtr pViewportObject = pDatabase->activeViewportId().safeOpenObject();
OdDbAbstractViewportDataPtr pVpData(pViewportObject);
OdGsView *pGsView = pVpData->gsView(pViewportObject);
if (pGsView != NULL)
pGsView->zoomExtents(OdGePoint3d(-10.0, -10.0, -10.0), OdGePoint3d(-10.0, -10.0, -10.0)); // <-- potential crash
もちろん、削除時には、デバイスは呼び出されたポインタを安全にゼロに設定しますが、これらのポインタはセカンダリデバイスの使用後にはアプリケーションにとって実際のものではありません。
解決策
この問題は、実際のグラフィックデバイスのためにデータベースビューポートオブジェクト内のOdGsViewポインタを復元する特別なレイアウトヘルパーメソッドを使用することで解決できます。
virtual void OdGsLayoutHelper::restoreGsViewDbLinkState() = 0;
別のデバイス(例えば印刷)での作業を完了し、以前のデバイスの使用に戻った場合、データベース内のすべてのOdGsViewリンクを更新するだけで済みます。
OdGsLayoutHelper::cast(pDevice)->restoreGsViewDbLinkState();
最終的な解決策は非常にシンプルで明確です。これらの手順の最後の項目を忘れないでください。
- セカンダリデバイスを構築します。
- セカンダリデバイスで作業します。
- セカンダリデバイスでの作業を完了します。
- メインデバイスに切り替え、OdGsViewデータベースリンクを更新します。
いつでも1つのグラフィックデバイスから他のグラフィックデバイスに切り替えることができますが、データベースの状態を一貫性があり安全に保つために、それらを使用する前に常にOdGsViewリンクを更新してください。