Merge branch 'feature/nmNum-postprocessing-analysis-20261008' into develop

# Conflicts:
#	Bin/Config/Lang/cn/nmNum_cn.qm
develop
lh 1 day ago
commit 8faee3ea24

Binary file not shown.

@ -3346,6 +3346,11 @@ No valid error was returned; keep the last accepted result and reduce the step.<
</context>
<context>
<name>nmWxPebiResultControlBar</name>
<message><source>Display</source><translation>显示</translation></message>
<message><source>Point</source><translation>点</translation></message>
<message><source>Wireframe</source><translation>线框</translation></message>
<message><source>Surface</source><translation>表面</translation></message>
<message><source>Contour</source><translation>轮廓</translation></message>
<message><source>Property</source><translation>属性</translation></message>
<message><source>Display property</source><translation>显示属性</translation></message>
<message><source>Color settings</source><translation>颜色设置</translation></message>
@ -3400,7 +3405,6 @@ No valid error was returned; keep the last accepted result and reduce the step.<
<message><source>Well Names</source><translation>井名</translation></message>
<message><source>Unable to display the latest result.</source><translation>无法显示最新结果。</translation></message>
<message><source>Unable to display the latest result: %1</source><translation>无法显示最新结果:%1</translation></message>
<message><source>Current inputs have changed. Showing the last successful result.</source><translation>当前输入已修改,正在显示上一次成功求解的结果。</translation></message>
<message><source>Export Animation</source><translation>导出动画</translation></message>
<message><source>Another result animation export is already in progress.</source><translation>已有结果动画正在导出。</translation></message>
<message><source>Unable to read the result animation timeline.</source><translation>无法读取结果动画时间轴。</translation></message>
@ -3415,6 +3419,11 @@ No valid error was returned; keep the last accepted result and reduce the step.<
</context>
<context>
<name>nmWxPebiGridViewWidget</name>
<message><source>Display</source><translation>显示</translation></message>
<message><source>Point</source><translation>点</translation></message>
<message><source>Wireframe</source><translation>线框</translation></message>
<message><source>Surface</source><translation>表面</translation></message>
<message><source>Contour</source><translation>轮廓</translation></message>
<message><source>No grid data.</source><translation>暂无网格数据。</translation></message>
<message><source>Scale Grid</source><translation>比例网格</translation></message>
<message><source>The grid preview data is invalid.</source><translation>网格预览数据无效。</translation></message>

@ -25,7 +25,9 @@ public:
enum DisplayMode
{
DisplayMode_Surface = 0, ///< 只显示填充表面。
DisplayMode_SurfaceWithEdges ///< 同时显示表面和单元边线。
DisplayMode_SurfaceWithEdges = 1, ///< 同时显示表面和单元边线。
DisplayMode_Point = 2, ///< 显示 Mapper 实际可渲染的原始顶点。
DisplayMode_Wireframe = 3 ///< 以线框方式显示网格单元。
};
enum ScalarAssociation
@ -75,7 +77,9 @@ public:
/** @brief 返回当前直接数据或管线输出数据集的非所有权指针。 */
vtkDataSet* getDataSet() const;
/** @brief 设置表面或表面加边线显示模式。 */
/** @brief 判断枚举值是否为受支持的网格显示模式。 */
static bool isValidDisplayMode(DisplayMode eMode);
/** @brief 设置点、线框、表面或表面加边线显示模式。 */
void setDisplayMode(DisplayMode eMode);
/** @brief 返回当前显示模式。 */
DisplayMode getDisplayMode() const;

@ -2,6 +2,7 @@
#define NMPEBIGRIDSCENECONTROLLER_H
#include "nmSubWxs_global.h"
#include "nmVTKMeshLayer.h"
#include <QString>
@ -29,6 +30,11 @@ public:
/** @brief 解除网格引用并隐藏图层,不销毁 Scene 或 Renderer。 */
void clear();
/** @brief 设置本窗口网格显示模式;无有效数据时只保存偏好。 */
void setMeshDisplayMode(nmVTKMeshLayer::DisplayMode eMode);
/** @brief 返回本窗口网格显示模式偏好。 */
nmVTKMeshLayer::DisplayMode getMeshDisplayMode() const;
/** @brief 切换 XY 坐标比例网格。 */
void setBoundsGridVisible(bool bVisible);

@ -4,6 +4,7 @@
#include "nmSubWxs_global.h"
#include "nmPebiResultAnimationExportSettings.h"
#include "nmPebiResultDisplaySettings.h"
#include "nmVTKMeshLayer.h"
#include <QObject>
#include <QSharedPointer>
@ -60,6 +61,8 @@ public:
bool m_bGradientBackground;
/** @brief 当前屏幕相机的深拷贝,导出器不会修改屏幕相机。 */
vtkSmartPointer<vtkCamera> m_pCamera;
/** @brief 开始导出前冻结的网格显示模式。 */
nmVTKMeshLayer::DisplayMode m_eMeshDisplayMode;
};
/** @param pParent Qt父对象,不参与VTK资源所有权。 */

@ -3,6 +3,7 @@
#include "nmSubWxs_global.h"
#include "nmPebiResultDisplaySettings.h"
#include "nmVTKMeshLayer.h"
#include <QSharedPointer>
#include <QString>
@ -71,6 +72,11 @@ public:
const nmPebiResultDisplaySettings& oSettings,
QString* pError = nullptr);
/** @brief 设置本窗口网格显示模式;无有效快照时只保存偏好。 */
void setMeshDisplayMode(nmVTKMeshLayer::DisplayMode eMode);
/** @brief 返回本窗口网格显示模式偏好。 */
nmVTKMeshLayer::DisplayMode getMeshDisplayMode() const;
/** @brief 设置色标显隐;默认显示,偏好跨快照保留。 */
void setScalarBarVisible(bool bVisible);
/** @brief 设置平面比例网格显隐;偏好跨快照保留。 */

@ -6,6 +6,7 @@
#include <QWidget>
class QAction;
class QComboBox;
class QLabel;
class QMenu;
class QToolBar;
@ -17,7 +18,7 @@ class nmWxVTKRenderContainerWidget;
/**
* @brief 二维 PEBI 网格预览业务组合控件。
*
* 本类定位为网格几何检查窗口,只显示固定灰色表面、黑色单元边线和
* 本类定位为网格几何检查窗口,支持点、线框、表面和轮廓四种模式及
* 可选的 XY 比例网格,不解释输入数据中的历史属性数组。右侧工具栏和
* 右键菜单复用同一批 QAction;通用导航、旋转中心、截图和打印能力由
* 内部 nmRender 容器提供,不继承业务视图基类。
@ -48,6 +49,8 @@ public:
bool hasViewData() const;
private slots:
/** @brief 从 itemData 读取并提交当前窗口的网格显示模式。 */
void onDisplayModeIndexChanged(int nIndex);
/** @brief 切换世界坐标中的 XY 比例网格,不改变相机。 */
void onBoundsGridToggled(bool bVisible);
/** @brief 向通用右键菜单追加本窗口独占的比例网格动作。 */
@ -60,6 +63,8 @@ private:
void createUi();
/** @brief 恢复无数据时的比例网格偏好和底栏文字。 */
void resetControls();
/** @brief 从 SceneController 镜像显示模式,且不触发用户选择槽。 */
void synchronizeDisplayModeFromScene();
/** @brief 统一启停依赖有效网格的业务动作。 */
void setControlsEnabled(bool bEnabled);
@ -67,6 +72,7 @@ private:
nmPebiGridSceneController* m_pSceneController; ///< 本类独占,必须先于容器销毁。
QToolBar* m_pToolBar; ///< Qt 父对象拥有的右侧竖向工具栏。
QAction* m_pBoundsGridAction; ///< 工具栏和右键菜单共享的比例网格动作。
QComboBox* m_pDisplayModeCombo; ///< 显示模式框,itemData 保存 DisplayMode 枚举值。
QLabel* m_pGridInfoLabel; ///< 底栏左侧的网格类型、单元数和平面信息。
QLabel* m_pStatusLabel; ///< 建网失败且保留旧网格时使用的黄色提示栏。
bool m_bHasViewData; ///< 与场景控制器的成功数据状态保持同步。

@ -56,6 +56,8 @@ signals:
void exportAnimationRequested();
private slots:
/** @brief 用户选择显示模式时提交 itemData 中的 DisplayMode 枚举值。 */
void onDisplayModeIndexChanged(int nIndex);
/** @brief 用户选择属性时提交稳定属性 ID。 */
void onPropertyIndexChanged(int nIndex);
/** @brief 用户选择时间时提交 itemData 中的零基帧。 */
@ -100,6 +102,8 @@ private:
nmPebiResultPlaybackController* m_pPlaybackController;
/** @brief 已渲染属性、帧和显示设置的唯一真源;本控件不拥有。 */
nmPebiResultSceneController* m_pSceneController;
/** @brief 显示模式选择框,条目数据保存 DisplayMode 枚举值。 */
QComboBox* m_pDisplayModeCombo;
/** @brief 属性选择框,条目数据保存稳定英文属性 ID。 */
QComboBox* m_pPropertyCombo;
/** @brief 使用固定色带图标打开颜色设置对话框。 */

@ -58,9 +58,9 @@ private slots:
void onDataManagerDestroyed(QObject* pObject);
/** @brief 将业务显隐 QAction 追加到通用右键菜单。 */
void appendContextMenuActions(QMenu* pMenu);
/** @brief 转发非阻塞操作错误,但不覆盖绑定失败或过期提示。 */
/** @brief 转发非阻塞操作错误,但不覆盖绑定失败提示。 */
void onControlOperationFailed(const QString& sError);
/** @brief 明确操作成功后清除旧普通错误,不影响绑定失败或过期状态。 */
/** @brief 明确操作成功后清除旧普通错误,不影响绑定失败状态。 */
void onControlOperationSucceeded();
/** @brief 将 QVTK 视口尺寸同步给结果场景,不主动触发额外渲染。 */
void onViewportSizeChanged(int nWidth, int nHeight);
@ -90,7 +90,7 @@ private:
bool bCurrent);
/** @brief 从 SceneController 镜像三个业务 QAction 的勾选和可用状态。 */
void synchronizeBusinessActions();
/** @brief 根据“绑定失败、过期、操作错误”的固定优先级刷新提示栏。 */
/** @brief 按绑定失败、操作错误的优先级刷新提示栏,无错误时隐藏。 */
void refreshStatusBar();
/** @brief 断开当前 Manager 的两个连接,不访问已经析构的对象。 */
void disconnectDataManager();
@ -100,7 +100,7 @@ private:
nmPebiResultSceneController* m_pSceneController; ///< 唯一结果场景控制器。
nmWxPebiResultControlBar* m_pControlBar; ///< 独占回放控制器和 Timer 的底栏。
QToolBar* m_pToolBar; ///< Qt 父对象拥有的右侧竖向工具栏。
QLabel* m_pStatusLabel; ///< 过期或错误的非阻塞提示栏。
QLabel* m_pStatusLabel; ///< 绑定失败或操作错误的非阻塞提示栏。
QAction* m_pScalarBarAction; ///< 色标显隐动作。
QAction* m_pScaleGridAction; ///< 比例网格显隐动作。

@ -52,6 +52,8 @@ nmVTKMeshLayer::nmVTKMeshLayer(const QString& sLayerId)
m_pActor->SetMapper(m_pMapper);
m_pActor->GetProperty()->SetRepresentationToSurface();
m_pActor->GetProperty()->EdgeVisibilityOff();
m_pActor->GetProperty()->SetPointSize(3.0f);
m_pActor->GetProperty()->SetLineWidth(1.0f);
setRenderProp(m_pActor);
}
@ -208,6 +210,14 @@ vtkDataSet* nmVTKMeshLayer::getDataSet() const
return getInputDataSet(false);
}
bool nmVTKMeshLayer::isValidDisplayMode(DisplayMode eMode)
{
return eMode == DisplayMode_Surface ||
eMode == DisplayMode_SurfaceWithEdges ||
eMode == DisplayMode_Point ||
eMode == DisplayMode_Wireframe;
}
void nmVTKMeshLayer::setDisplayMode(DisplayMode eMode)
{
Q_ASSERT(isMeshLayerGuiThread());
@ -215,13 +225,30 @@ void nmVTKMeshLayer::setDisplayMode(DisplayMode eMode)
return;
}
// 未识别枚举值按纯表面处理,避免把无效值带入 VTK Property。
m_eDisplayMode = eMode == DisplayMode_SurfaceWithEdges
? DisplayMode_SurfaceWithEdges : DisplayMode_Surface;
// 未识别枚举值仍按纯表面处理,保持旧接口的降级语义。
m_eDisplayMode = isValidDisplayMode(eMode)
? eMode : DisplayMode_Surface;
vtkProperty* pProperty = m_pActor->GetProperty();
pProperty->SetPointSize(3.0f);
pProperty->SetLineWidth(1.0f);
pProperty->EdgeVisibilityOff();
switch(m_eDisplayMode) {
case DisplayMode_Point:
pProperty->SetRepresentationToPoints();
break;
case DisplayMode_Wireframe:
pProperty->SetRepresentationToWireframe();
break;
case DisplayMode_SurfaceWithEdges:
pProperty->SetRepresentationToSurface();
pProperty->SetEdgeVisibility(
m_eDisplayMode == DisplayMode_SurfaceWithEdges ? 1 : 0);
pProperty->EdgeVisibilityOn();
break;
case DisplayMode_Surface:
default:
pProperty->SetRepresentationToSurface();
break;
}
}
nmVTKMeshLayer::DisplayMode nmVTKMeshLayer::getDisplayMode() const

@ -52,11 +52,31 @@ public:
: m_pContainer(pRenderContainer),
m_pMeshLayer(nullptr),
m_pPlanarScaleGridLayer(nullptr),
m_eMeshDisplayMode(
nmVTKMeshLayer::DisplayMode_SurfaceWithEdges),
m_bBoundsGridVisible(false),
m_bHasData(false)
{
}
/** @brief 将窗口偏好应用到现有网格 Actor,不触发渲染。 */
void applyMeshDisplayModeWithoutRender()
{
if(m_pMeshLayer == nullptr) {
return;
}
m_pMeshLayer->setDisplayMode(m_eMeshDisplayMode);
vtkProperty* pProperty = m_pMeshLayer->getActor()->GetProperty();
const bool bUseBlackColor =
m_eMeshDisplayMode == nmVTKMeshLayer::DisplayMode_Point ||
m_eMeshDisplayMode ==
nmVTKMeshLayer::DisplayMode_Wireframe;
const double dColor = bUseBlackColor ? 0.0 : 211.0 / 255.0;
pProperty->SetColor(dColor, dColor, dColor);
pProperty->SetEdgeColor(0.0, 0.0, 0.0);
}
bool ensureBaseLayers()
{
nmVTKScene* pScene = m_pContainer != nullptr
@ -76,14 +96,9 @@ public:
return false;
}
m_pMeshLayer = pLayer;
// PEBI 预览固定使用稳定灰色表面和黑色单元边线。
m_pMeshLayer->getActor()->GetProperty()->SetColor(
211.0 / 255.0, 211.0 / 255.0,
211.0 / 255.0);
m_pMeshLayer->getActor()->GetProperty()->SetEdgeColor(
0.0, 0.0, 0.0);
// 仅关闭当前 PEBI 预览 Actor 的光照,避免固定面色随视角变化。
// 关闭光照,保证各显示模式的固定黑色或灰色不随视角变化。
m_pMeshLayer->getActor()->GetProperty()->LightingOff();
applyMeshDisplayModeWithoutRender();
}
if(m_pPlanarScaleGridLayer == nullptr) {
@ -113,10 +128,9 @@ public:
m_oViewData.clear();
return false;
}
// 输入可能包含历史数组,网格预览始终关闭标量着色并显示单元边线。
// 输入可能包含历史数组,网格预览始终关闭标量着色。
m_pMeshLayer->setScalarVisibility(false);
m_pMeshLayer->setDisplayMode(
nmVTKMeshLayer::DisplayMode_SurfaceWithEdges);
applyMeshDisplayModeWithoutRender();
m_pMeshLayer->setVisible(true);
if(!m_pPlanarScaleGridLayer->setBounds(
@ -161,6 +175,7 @@ public:
nmVTKMeshLayer* m_pMeshLayer; ///< Scene 所有,控制器只观察。
nmVTKPlanarScaleGridLayer* m_pPlanarScaleGridLayer; ///< Scene 所有。
nmPebiGridViewData m_oViewData;
nmVTKMeshLayer::DisplayMode m_eMeshDisplayMode; ///< 本窗口显示偏好。
bool m_bBoundsGridVisible;
bool m_bHasData;
};
@ -253,6 +268,31 @@ void nmPebiGridSceneController::clear()
m_pPrivate->m_bBoundsGridVisible = false;
}
void nmPebiGridSceneController::setMeshDisplayMode(
nmVTKMeshLayer::DisplayMode eMode)
{
if(m_pPrivate == nullptr ||
!nmVTKMeshLayer::isValidDisplayMode(eMode) ||
m_pPrivate->m_eMeshDisplayMode == eMode) {
return;
}
m_pPrivate->m_eMeshDisplayMode = eMode;
m_pPrivate->applyMeshDisplayModeWithoutRender();
if(m_pPrivate->m_bHasData &&
m_pPrivate->m_pContainer != nullptr) {
m_pPrivate->m_pContainer->renderView();
}
}
nmVTKMeshLayer::DisplayMode
nmPebiGridSceneController::getMeshDisplayMode() const
{
return m_pPrivate != nullptr
? m_pPrivate->m_eMeshDisplayMode
: nmVTKMeshLayer::DisplayMode_SurfaceWithEdges;
}
void nmPebiGridSceneController::setBoundsGridVisible(bool bVisible)
{
if(m_pPrivate == nullptr) {
@ -264,6 +304,7 @@ void nmPebiGridSceneController::setBoundsGridVisible(bool bVisible)
bVisible && m_pPrivate->m_bHasData);
}
if(m_pPrivate->m_bHasData && m_pPrivate->m_pContainer != nullptr) {
m_pPrivate->applyMeshDisplayModeWithoutRender();
m_pPrivate->m_pContainer->renderView();
}
}

@ -255,7 +255,9 @@ nmPebiResultAnimationExporter::Request::Request()
m_bScaleGridVisible(false),
m_bWellNamesVisible(true),
m_bGradientBackground(false),
m_pCamera(nullptr)
m_pCamera(nullptr),
m_eMeshDisplayMode(
nmVTKMeshLayer::DisplayMode_SurfaceWithEdges)
{
m_dBackground[0] = m_dBackground[1] = m_dBackground[2] = 0.0;
m_dBackground2[0] = m_dBackground2[1] = m_dBackground2[2] = 0.0;
@ -292,6 +294,8 @@ nmPebiResultAnimationExporter::exportAnimation(
oDescriptor.m_eTimeType != NM_PebiResultProperty_Dynamic ||
oDescriptor.m_eAssociation !=
NM_PebiResultPropertyAssociation_CellData ||
!nmVTKMeshLayer::isValidDisplayMode(
oRequest.m_eMeshDisplayMode) ||
!oRequest.m_oExportSettings.isValid(nAvailableFrameCount) ||
oRequest.m_sTargetFilePath.isEmpty() ||
oRequest.m_pCamera == nullptr) {
@ -370,8 +374,7 @@ nmPebiResultAnimationExporter::exportAnimation(
nmVTKScene oScene(pRenderer);
nmVTKMeshLayer* pMeshLayer = new nmVTKMeshLayer(
QString::fromLatin1(EXPORT_MESH_LAYER_ID));
pMeshLayer->setDisplayMode(
nmVTKMeshLayer::DisplayMode_SurfaceWithEdges);
pMeshLayer->setDisplayMode(oRequest.m_eMeshDisplayMode);
pMeshLayer->getActor()->GetProperty()->SetEdgeColor(0.0, 0.0, 0.0);
pMeshLayer->getActor()->GetProperty()->LightingOff();
if(!pMeshLayer->setInputConnection(

@ -189,6 +189,8 @@ public:
m_pScaleGridLayer(nullptr),
m_pWellLayer(nullptr),
m_pAdapter(nullptr),
m_eMeshDisplayMode(
nmVTKMeshLayer::DisplayMode_SurfaceWithEdges),
m_nCurrentFrameIndex(-1),
m_nSnapshotBindingRevision(0),
m_nViewportWidth(0),
@ -214,6 +216,18 @@ public:
return m_pContainer != nullptr ? m_pContainer->getScene() : nullptr;
}
/** @brief 将窗口偏好应用到现有结果网格,不触发渲染。 */
void applyMeshDisplayModeWithoutRender()
{
if(m_pMeshLayer == nullptr) {
return;
}
m_pMeshLayer->setDisplayMode(m_eMeshDisplayMode);
// Contour 使用黑色单元边线,其余模式关闭边线但保留该颜色偏好。
m_pMeshLayer->getActor()->GetProperty()->SetEdgeColor(
0.0, 0.0, 0.0);
}
bool synchronizeLayerPointers()
{
nmVTKScene* pScene = getScene();
@ -335,6 +349,7 @@ public:
m_pMeshLayer->getActor()->GetProperty()->SetEdgeColor(
0.0, 0.0, 0.0);
m_pMeshLayer->getActor()->GetProperty()->LightingOff();
applyMeshDisplayModeWithoutRender();
}
if(m_pScalarBarLayer == nullptr) {
@ -471,11 +486,15 @@ public:
}
// MeshLayer 在触碰旧 Mapper 前完成全部校验,失败不会破坏旧画面。
return m_pMeshLayer->setInputConnection(
if(!m_pMeshLayer->setInputConnection(
pAdapter->getOutputPort(),
pAdapter->getCurrentScalarArrayName(),
nmVTKMeshLayer::ScalarAssociation_CellData,
pLookupTable);
pLookupTable)) {
return false;
}
applyMeshDisplayModeWithoutRender();
return true;
}
void applyScalarBarLayout()
@ -513,9 +532,7 @@ public:
{
synchronizeLayerPointers();
if(m_pMeshLayer != nullptr) {
// 结果网格固定显示彩色表面和黑色单元边线,不保存可关闭的偏好。
m_pMeshLayer->setDisplayMode(
nmVTKMeshLayer::DisplayMode_SurfaceWithEdges);
applyMeshDisplayModeWithoutRender();
m_pMeshLayer->setScalarVisibility(bHasData);
// 彩色结果网格是有效快照的主内容,不提供独立隐藏状态。
m_pMeshLayer->setVisible(bHasData);
@ -677,6 +694,7 @@ public:
QString m_sCurrentPropertyId;
/** @brief 按稳定属性 ID 保存的窗口级样式;clear 不删除。 */
QMap<QString, nmPebiResultDisplaySettings> m_mapDisplaySettings;
nmVTKMeshLayer::DisplayMode m_eMeshDisplayMode; ///< 本窗口显示偏好。
int m_nCurrentFrameIndex;
/** @brief 不同快照对象完整提交成功后的单调序号,clear 和失败均不回退。 */
quint64 m_nSnapshotBindingRevision;
@ -1139,6 +1157,35 @@ bool nmPebiResultSceneController::applyCurrentDisplaySettings(
return true;
}
void nmPebiResultSceneController::setMeshDisplayMode(
nmVTKMeshLayer::DisplayMode eMode)
{
Q_ASSERT(isResultSceneGuiThread());
if(!isResultSceneGuiThread() || m_pPrivate == nullptr ||
!nmVTKMeshLayer::isValidDisplayMode(eMode)) {
return;
}
m_pPrivate->discardActiveDataIfLayersLost();
if(m_pPrivate->m_eMeshDisplayMode == eMode) {
return;
}
m_pPrivate->m_eMeshDisplayMode = eMode;
m_pPrivate->applyMeshDisplayModeWithoutRender();
if(hasSnapshot() && m_pPrivate->m_pContainer != nullptr) {
m_pPrivate->m_pContainer->renderView();
}
}
nmVTKMeshLayer::DisplayMode
nmPebiResultSceneController::getMeshDisplayMode() const
{
return m_pPrivate != nullptr
? m_pPrivate->m_eMeshDisplayMode
: nmVTKMeshLayer::DisplayMode_SurfaceWithEdges;
}
void nmPebiResultSceneController::setScalarBarVisible(bool bVisible)
{
Q_ASSERT(isResultSceneGuiThread());

@ -3,10 +3,12 @@
#include "nmPebiGridSceneController.h"
#include "nmPebiGridViewData.h"
#include "nmVTKMeshLayer.h"
#include "nmVTKViewCommandController.h"
#include "nmWxVTKRenderContainerWidget.h"
#include <QAction>
#include <QComboBox>
#include <QCoreApplication>
#include <QHBoxLayout>
#include <QIcon>
@ -14,6 +16,7 @@
#include <QMenu>
#include <QSize>
#include <QToolBar>
#include <QVariant>
#include <QVBoxLayout>
namespace {
@ -33,6 +36,7 @@ nmWxPebiGridViewWidget::nmWxPebiGridViewWidget(QWidget* pParent)
m_pSceneController(nullptr),
m_pToolBar(nullptr),
m_pBoundsGridAction(nullptr),
m_pDisplayModeCombo(nullptr),
m_pGridInfoLabel(nullptr),
m_pStatusLabel(nullptr),
m_bHasViewData(false)
@ -41,6 +45,7 @@ nmWxPebiGridViewWidget::nmWxPebiGridViewWidget(QWidget* pParent)
// 控制器必须在容器之后创建,以便使用当前实例独占的 Scene 和相机。
m_pSceneController =
new nmPebiGridSceneController(m_pRenderContainer);
synchronizeDisplayModeFromScene();
resetControls();
setControlsEnabled(false);
m_pRenderContainer->showEmptyState(tr("No grid data."));
@ -176,18 +181,47 @@ void nmWxPebiGridViewWidget::createUi()
m_pStatusLabel->hide();
pMainLayout->addWidget(m_pStatusLabel);
// 底栏只承担几何信息展示,不放置属性或渲染模式控件。
// 显示模式属于当前预览窗口,业务控件不下沉到通用渲染容器。
QWidget* pControlBar = new QWidget(this);
QHBoxLayout* pControlLayout = new QHBoxLayout(pControlBar);
pControlLayout->setContentsMargins(8, 5, 8, 5);
pControlLayout->setSpacing(6);
QLabel* pDisplayLabel = new QLabel(tr("Display"), pControlBar);
pDisplayLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
m_pDisplayModeCombo = new QComboBox(pControlBar);
m_pDisplayModeCombo->addItem(
tr("Point"),
QVariant(static_cast<int>(
nmVTKMeshLayer::DisplayMode_Point)));
m_pDisplayModeCombo->addItem(
tr("Wireframe"),
QVariant(static_cast<int>(
nmVTKMeshLayer::DisplayMode_Wireframe)));
m_pDisplayModeCombo->addItem(
tr("Surface"),
QVariant(static_cast<int>(
nmVTKMeshLayer::DisplayMode_Surface)));
m_pDisplayModeCombo->addItem(
tr("Contour"),
QVariant(static_cast<int>(
nmVTKMeshLayer::DisplayMode_SurfaceWithEdges)));
m_pDisplayModeCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents);
m_pDisplayModeCombo->setFixedHeight(24);
m_pDisplayModeCombo->setSizePolicy(
QSizePolicy::Preferred, QSizePolicy::Fixed);
m_pGridInfoLabel = new QLabel(pControlBar);
m_pGridInfoLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
pControlLayout->addWidget(pDisplayLabel, 0, Qt::AlignVCenter);
pControlLayout->addWidget(m_pDisplayModeCombo);
pControlLayout->addSpacing(2);
pControlLayout->addWidget(m_pGridInfoLabel);
pControlLayout->addStretch(1);
pMainLayout->addWidget(pControlBar);
connect(m_pDisplayModeCombo, SIGNAL(currentIndexChanged(int)),
this, SLOT(onDisplayModeIndexChanged(int)));
connect(m_pBoundsGridAction, SIGNAL(toggled(bool)),
this, SLOT(onBoundsGridToggled(bool)));
connect(m_pRenderContainer, SIGNAL(contextMenuAboutToShow(QMenu*)),
@ -218,6 +252,7 @@ bool nmWxPebiGridViewWidget::setViewData(
oViewData.getValidCellCount())));
m_pStatusLabel->hide();
m_bHasViewData = true;
synchronizeDisplayModeFromScene();
setControlsEnabled(true);
return true;
}
@ -275,6 +310,50 @@ void nmWxPebiGridViewWidget::resetControls()
void nmWxPebiGridViewWidget::setControlsEnabled(bool bEnabled)
{
m_pBoundsGridAction->setEnabled(bEnabled);
m_pDisplayModeCombo->setEnabled(bEnabled);
}
void nmWxPebiGridViewWidget::synchronizeDisplayModeFromScene()
{
if(m_pDisplayModeCombo == nullptr || m_pSceneController == nullptr) {
return;
}
const int nMode = static_cast<int>(
m_pSceneController->getMeshDisplayMode());
for(int nIndex = 0;
nIndex < m_pDisplayModeCombo->count(); ++nIndex) {
if(m_pDisplayModeCombo->itemData(nIndex).toInt() == nMode) {
const bool bBlocked =
m_pDisplayModeCombo->blockSignals(true);
m_pDisplayModeCombo->setCurrentIndex(nIndex);
m_pDisplayModeCombo->blockSignals(bBlocked);
return;
}
}
}
void nmWxPebiGridViewWidget::onDisplayModeIndexChanged(int nIndex)
{
if(m_pDisplayModeCombo == nullptr ||
!m_pDisplayModeCombo->isEnabled() ||
m_pSceneController == nullptr || !m_bHasViewData ||
!m_pSceneController->hasViewData() || nIndex < 0 ||
nIndex >= m_pDisplayModeCombo->count()) {
return;
}
bool bConverted = false;
const int nMode = m_pDisplayModeCombo->itemData(nIndex).toInt(
&bConverted);
const nmVTKMeshLayer::DisplayMode eMode =
static_cast<nmVTKMeshLayer::DisplayMode>(
nMode);
if(!bConverted || !nmVTKMeshLayer::isValidDisplayMode(eMode)) {
synchronizeDisplayModeFromScene();
return;
}
m_pSceneController->setMeshDisplayMode(eMode);
synchronizeDisplayModeFromScene();
}
void nmWxPebiGridViewWidget::onBoundsGridToggled(bool bVisible)

@ -4,6 +4,7 @@
#include "nmPebiResultPlaybackController.h"
#include "nmPebiResultPropertyDisplayText.h"
#include "nmPebiResultSceneController.h"
#include "nmVTKMeshLayer.h"
#include "nmWxPebiResultAnimationSettingsDlg.h"
#include "nmWxPebiResultColorScaleSettingsDlg.h"
@ -56,6 +57,7 @@ nmWxPebiResultControlBar::nmWxPebiResultControlBar(
: QWidget(pParent),
m_pPlaybackController(nullptr),
m_pSceneController(pSceneController),
m_pDisplayModeCombo(nullptr),
m_pPropertyCombo(nullptr),
m_pColorSettingsButton(nullptr),
m_pFirstButton(nullptr),
@ -125,6 +127,34 @@ void nmWxPebiResultControlBar::setExportInProgress(bool bInProgress)
refreshFromController();
}
void nmWxPebiResultControlBar::onDisplayModeIndexChanged(int nIndex)
{
if(m_pDisplayModeCombo == nullptr ||
!m_pDisplayModeCombo->isEnabled() ||
m_pPlaybackController == nullptr || m_pSceneController == nullptr ||
m_bExportInProgress || m_pPlaybackController->isPlaying() ||
!m_pSceneController->hasSnapshot() || nIndex < 0 ||
nIndex >= m_pDisplayModeCombo->count()) {
return;
}
bool bConverted = false;
const int nMode = m_pDisplayModeCombo->itemData(nIndex).toInt(
&bConverted);
const nmVTKMeshLayer::DisplayMode eMode =
static_cast<nmVTKMeshLayer::DisplayMode>(
nMode);
if(!bConverted || !nmVTKMeshLayer::isValidDisplayMode(eMode)) {
refreshFromController();
return;
}
if(eMode == m_pSceneController->getMeshDisplayMode()) {
return;
}
m_pSceneController->setMeshDisplayMode(eMode);
emit operationSucceeded();
}
void nmWxPebiResultControlBar::onPropertyIndexChanged(int nIndex)
{
if(m_pPlaybackController == nullptr || m_bExportInProgress ||
@ -252,6 +282,19 @@ void nmWxPebiResultControlBar::onExportAnimationTriggered()
void nmWxPebiResultControlBar::refreshFromController()
{
if(m_pDisplayModeCombo != nullptr && m_pSceneController != nullptr) {
const int nDisplayModeIndex = findItemByData(
m_pDisplayModeCombo,
QVariant(static_cast<int>(
m_pSceneController->getMeshDisplayMode())));
if(nDisplayModeIndex >= 0) {
const bool bDisplayModeBlocked =
m_pDisplayModeCombo->blockSignals(true);
m_pDisplayModeCombo->setCurrentIndex(nDisplayModeIndex);
m_pDisplayModeCombo->blockSignals(bDisplayModeBlocked);
}
}
// 控件状态严格镜像四类 Scene 状态:无快照、静态、单帧动态、多帧动态。
const bool bAvailable = m_pPlaybackController != nullptr &&
m_pPlaybackController->isAvailable();
@ -263,6 +306,7 @@ void nmWxPebiResultControlBar::refreshFromController()
m_sDisplayedSnapshotId.clear();
m_nDisplayedBindingRevision = 0;
m_listDisplayedPropertyIds.clear();
m_pDisplayModeCombo->setEnabled(false);
m_pPropertyCombo->setEnabled(false);
m_pColorSettingsButton->setEnabled(false);
m_pFirstButton->setEnabled(false);
@ -336,6 +380,7 @@ void nmWxPebiResultControlBar::refreshFromController()
nFrameCount > 1;
const bool bPlaying = m_pPlaybackController->isPlaying();
const bool bLocked = bPlaying || m_bExportInProgress;
m_pDisplayModeCombo->setEnabled(!bLocked);
m_pPropertyCombo->setEnabled(!bLocked);
m_pColorSettingsButton->setEnabled(!bLocked);
m_pTimeCombo->setEnabled(bHasTime && !bLocked);
@ -382,6 +427,37 @@ void nmWxPebiResultControlBar::createUi()
pLayout->setContentsMargins(4, 3, 4, 3);
pLayout->setSpacing(4);
QLabel* pDisplayLabel = new QLabel(tr("Display"), this);
pDisplayLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
m_pDisplayModeCombo = new QComboBox(this);
m_pDisplayModeCombo->addItem(
tr("Point"),
QVariant(static_cast<int>(
nmVTKMeshLayer::DisplayMode_Point)));
m_pDisplayModeCombo->addItem(
tr("Wireframe"),
QVariant(static_cast<int>(
nmVTKMeshLayer::DisplayMode_Wireframe)));
m_pDisplayModeCombo->addItem(
tr("Surface"),
QVariant(static_cast<int>(
nmVTKMeshLayer::DisplayMode_Surface)));
m_pDisplayModeCombo->addItem(
tr("Contour"),
QVariant(static_cast<int>(
nmVTKMeshLayer::DisplayMode_SurfaceWithEdges)));
m_pDisplayModeCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents);
m_pDisplayModeCombo->setFixedHeight(24);
m_pDisplayModeCombo->setSizePolicy(
QSizePolicy::Preferred, QSizePolicy::Fixed);
const int nInitialDisplayModeIndex = findItemByData(
m_pDisplayModeCombo,
QVariant(static_cast<int>(
m_pSceneController->getMeshDisplayMode())));
if(nInitialDisplayModeIndex >= 0) {
m_pDisplayModeCombo->setCurrentIndex(nInitialDisplayModeIndex);
}
QLabel* pPropertyLabel = new QLabel(tr("Property"), this);
pPropertyLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
@ -436,6 +512,9 @@ void nmWxPebiResultControlBar::createUi()
m_pExportButton->setIconSize(QSize(16, 16));
m_pExportButton->setDefaultAction(m_pExportAction);
pLayout->addWidget(pDisplayLabel, 0, Qt::AlignVCenter);
pLayout->addWidget(m_pDisplayModeCombo);
pLayout->addSpacing(CONTROL_GROUP_GAP);
pLayout->addWidget(pPropertyLabel, 0, Qt::AlignVCenter);
pLayout->addWidget(m_pPropertyCombo);
pLayout->addWidget(m_pColorSettingsButton);
@ -450,6 +529,8 @@ void nmWxPebiResultControlBar::createUi()
pLayout->addWidget(m_pExportButton);
pLayout->addStretch(1);
connect(m_pDisplayModeCombo, SIGNAL(currentIndexChanged(int)),
this, SLOT(onDisplayModeIndexChanged(int)));
connect(m_pPropertyCombo, SIGNAL(currentIndexChanged(int)),
this, SLOT(onPropertyIndexChanged(int)));
connect(m_pColorSettingsButton, SIGNAL(clicked()),

@ -7,6 +7,7 @@
#include "nmPebiResultPlaybackController.h"
#include "nmPebiResultSceneController.h"
#include "nmPebiResultSnapshot.h"
#include "nmVTKMeshLayer.h"
#include "nmVTKViewCommandController.h"
#include "nmWxPebiResultControlBar.h"
#include "nmWxPebiResultAnimationExportDlg.h"
@ -237,9 +238,8 @@ void nmWxPebiResultViewWidget::appendContextMenuActions(QMenu* pMenu)
void nmWxPebiResultViewWidget::onControlOperationFailed(
const QString& sError)
{
// 高优先级状态存在时丢弃普通错误,避免其在过期提示解除后突然出现。
if(!m_sBindingError.isEmpty() ||
(m_bObservedStateValid && !m_bObservedSnapshotCurrent)) {
// 绑定失败优先显示;输入修改不再提示,也不屏蔽后续真实操作错误。
if(!m_sBindingError.isEmpty()) {
return;
}
m_sOperationError = sError;
@ -251,7 +251,7 @@ void nmWxPebiResultViewWidget::onControlOperationSucceeded()
if(m_sOperationError.isEmpty()) {
return;
}
// 这里只清除最低优先级的普通操作错误;刷新函数仍优先显示绑定失败和过期。
// 这里只清除普通操作错误;刷新函数仍优先显示绑定失败。
m_sOperationError.clear();
refreshStatusBar();
}
@ -300,10 +300,13 @@ void nmWxPebiResultViewWidget::onExportAnimationRequested()
m_pSceneController->getCurrentSnapshotId();
const QString sFrozenPropertyId =
m_pSceneController->getCurrentPropertyId();
const nmVTKMeshLayer::DisplayMode eFrozenMeshDisplayMode =
m_pSceneController->getMeshDisplayMode();
const int nFrameCount = pFrozenSnapshot->getPropertyFrameCount(
sFrozenPropertyId);
if(nFrozenBindingRevision == 0 || sFrozenSnapshotId.isEmpty() ||
sFrozenPropertyId.isEmpty() || nFrameCount <= 1 ||
!nmVTKMeshLayer::isValidDisplayMode(eFrozenMeshDisplayMode) ||
!m_pSceneController->isPropertyTimeDependent(sFrozenPropertyId)) {
return;
}
@ -333,7 +336,9 @@ void nmWxPebiResultViewWidget::onExportAnimationRequested()
m_pSceneController->getSnapshotBindingRevision() !=
nFrozenBindingRevision ||
m_pSceneController->getCurrentSnapshotId() != sFrozenSnapshotId ||
m_pSceneController->getCurrentPropertyId() != sFrozenPropertyId) {
m_pSceneController->getCurrentPropertyId() != sFrozenPropertyId ||
m_pSceneController->getMeshDisplayMode() !=
eFrozenMeshDisplayMode) {
QMessageBox::warning(
this, tr("Export Animation"),
tr("The displayed result changed before export started."));
@ -354,6 +359,7 @@ void nmWxPebiResultViewWidget::onExportAnimationRequested()
oRequest.m_pSnapshot = pFrozenSnapshot;
oRequest.m_sPropertyId = sFrozenPropertyId;
oRequest.m_oDisplaySettings = oDisplaySettings;
oRequest.m_eMeshDisplayMode = eFrozenMeshDisplayMode;
oRequest.m_oExportSettings = oSettingsDialog.getSettings();
oRequest.m_sTargetFilePath = oSettingsDialog.getTargetFilePath();
oRequest.m_bScalarBarVisible =
@ -713,14 +719,6 @@ void nmWxPebiResultViewWidget::refreshStatusBar()
m_pStatusLabel->show();
return;
}
if(m_bObservedStateValid && !m_bObservedSnapshotCurrent) {
m_pStatusLabel->setStyleSheet(
"QLabel { color: #6b5200; background: #fff4bf; } ");
m_pStatusLabel->setText(tr(
"Current inputs have changed. Showing the last successful result."));
m_pStatusLabel->show();
return;
}
if(!m_sOperationError.isEmpty()) {
m_pStatusLabel->setStyleSheet(
"QLabel { color: #a32626; background: #fdecec; } ");

Loading…
Cancel
Save