初步可以运行,未严格调试
This commit is contained in:
@@ -9,6 +9,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Configuration;
|
||||
using HkVisionPro.App.Automation;
|
||||
using ReaLTaiizor.Enum.Poison;
|
||||
using ReaLTaiizor.Forms;
|
||||
using ReaLTaiizor.Manager;
|
||||
@@ -86,30 +87,30 @@ namespace HkVisionPro.App
|
||||
/// </summary>
|
||||
private bool _isClosingResourcesReleased;
|
||||
|
||||
/// <summary>
|
||||
/// 流程字符串输出名称(支持配置,默认 out)。
|
||||
/// </summary>
|
||||
private readonly string _procedureOutputCodeName;
|
||||
|
||||
/// <summary>
|
||||
/// 流程整数输出名称(支持配置,默认 out0)。
|
||||
/// </summary>
|
||||
private readonly string _procedureOutputNumberName;
|
||||
|
||||
/// <summary>
|
||||
/// 渲染图像输出名称(支持配置,默认 Image)。
|
||||
/// </summary>
|
||||
private readonly string _renderImageOutputName;
|
||||
|
||||
/// <summary>
|
||||
/// 渲染 ROI 输出名称(支持配置,默认 ROI)。
|
||||
/// 渲染主 ROI 输出名称(支持配置,默认 InputR1)。
|
||||
/// </summary>
|
||||
private readonly string _renderRoiOutputName;
|
||||
private readonly string _renderRoiOutputName1;
|
||||
|
||||
/// <summary>
|
||||
/// 渲染文本输出名称(支持配置,默认 code)。
|
||||
/// 渲染次 ROI 输出名称(支持配置,默认 InputR2)。
|
||||
/// </summary>
|
||||
private readonly string _renderCodeOutputName;
|
||||
private readonly string _renderRoiOutputName2;
|
||||
|
||||
/// <summary>
|
||||
/// 渲染判定结果1整型输出名称(支持配置,默认 Result1)。
|
||||
/// </summary>
|
||||
private readonly string _renderResultIntOutputName1;
|
||||
|
||||
/// <summary>
|
||||
/// 渲染判定结果2整型输出名称(支持配置,默认 Result2)。
|
||||
/// </summary>
|
||||
private readonly string _renderResultIntOutputName2;
|
||||
|
||||
/// <summary>
|
||||
/// VisionMaster: 方案正在加载中的错误码(IMVS_EC_SOLUTION_LOADING)。
|
||||
@@ -121,6 +122,21 @@ namespace HkVisionPro.App
|
||||
/// </summary>
|
||||
private const int VmErrorCodeModuleContinueExecute = -536870127;
|
||||
|
||||
/// <summary>
|
||||
/// 自动装配状态机配置。
|
||||
/// </summary>
|
||||
private readonly AutoAssemblyOptions _autoAssemblyOptions;
|
||||
|
||||
/// <summary>
|
||||
/// 自动装配流程控制器(Stateless 状态机)。
|
||||
/// </summary>
|
||||
private readonly AutoAssemblyWorkflowController _autoAssemblyController;
|
||||
|
||||
/// <summary>
|
||||
/// 方案加载完成后是否自动启动自动装配流程。
|
||||
/// </summary>
|
||||
private readonly bool _autoRunEnabledAfterSolutionLoaded;
|
||||
|
||||
/// <summary>
|
||||
/// ReaLTaiizor Poison 样式管理器(用于统一暗色主题风格元数据)。
|
||||
/// </summary>
|
||||
@@ -171,11 +187,20 @@ namespace HkVisionPro.App
|
||||
InitializeComponent();
|
||||
_poisonStyleManager = components == null ? new PoisonStyleManager() : new PoisonStyleManager(components);
|
||||
_solutionManager = new SolutionManager();
|
||||
_procedureOutputCodeName = GetAppSettingOrDefault("ProcedureOutputCodeName", "out");
|
||||
_procedureOutputNumberName = GetAppSettingOrDefault("ProcedureOutputNumberName", "out0");
|
||||
_renderImageOutputName = GetAppSettingOrDefault("RenderImageOutputName", "Image");
|
||||
_renderRoiOutputName = GetAppSettingOrDefault("RenderRoiOutputName", "ROI");
|
||||
_renderCodeOutputName = GetAppSettingOrDefault("RenderCodeOutputName", "code");
|
||||
_renderImageOutputName = GetAppSettingOrDefault("RenderImageOutputName", "ImageData0");
|
||||
_renderRoiOutputName1 = GetAppSettingOrDefault("RenderRoiOutputName", "InputR1");
|
||||
_renderRoiOutputName2 = GetAppSettingOrDefault("RenderRoiOutputName2", "InputR2");
|
||||
_renderResultIntOutputName1 = GetAppSettingOrDefault("RenderResultIntOutputName1", "Result1");
|
||||
_renderResultIntOutputName2 = GetAppSettingOrDefault("RenderResultIntOutputName2", "Result2");
|
||||
_autoAssemblyOptions = BuildAutoAssemblyOptions();
|
||||
_autoRunEnabledAfterSolutionLoaded = GetAppSettingBoolOrDefault("AutoRunEnabledAfterSolutionLoaded", true);
|
||||
|
||||
_autoAssemblyController = new AutoAssemblyWorkflowController(
|
||||
_autoAssemblyOptions,
|
||||
WriteLog,
|
||||
(procedure, triggerSource) => RenderProcedureResultToPictureBox(procedure, triggerSource));
|
||||
|
||||
_autoAssemblyController.StatusChanged += AutoAssemblyController_StatusChanged;
|
||||
RegisterSolutionCallbacks();
|
||||
RegisterVmSolutionCallbacks();
|
||||
|
||||
@@ -187,11 +212,276 @@ namespace HkVisionPro.App
|
||||
pictureBox1.BackColor = Color.Black;
|
||||
|
||||
InitializeDarkTheme();
|
||||
InitializeAutoRunStatusPanel();
|
||||
|
||||
UpdateUiState(false);
|
||||
txtSolutionAddress.Text = string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化自动运行结果显示面板。
|
||||
/// </summary>
|
||||
private void InitializeAutoRunStatusPanel()
|
||||
{
|
||||
lblRunState.AutoSize = false;
|
||||
lblRunState.Dock = DockStyle.Fill;
|
||||
lblRunState.TextAlign = ContentAlignment.MiddleCenter;
|
||||
|
||||
var initMessage = _autoRunEnabledAfterSolutionLoaded
|
||||
? "自动流程待启动(等待方案加载)"
|
||||
: "自动流程已禁用(配置开关关闭)";
|
||||
|
||||
UpdateAutoRunResultDisplay(AutoAssemblyState.Idle, initMessage, 0, string.Empty, 0, _autoAssemblyOptions.StableOkMilliseconds);
|
||||
SyncAutoRunButtonState();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自动装配状态变化事件:刷新“自动运行结果”显示。
|
||||
/// </summary>
|
||||
/// <param name="sender">事件源对象。</param>
|
||||
/// <param name="e">状态变化参数。</param>
|
||||
private void AutoAssemblyController_StatusChanged(object sender, AutoAssemblyStatusChangedEventArgs e)
|
||||
{
|
||||
if (e == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SyncAutoRunButtonState();
|
||||
|
||||
UpdateAutoRunResultDisplay(
|
||||
e.State,
|
||||
e.Message,
|
||||
e.ProductIndex,
|
||||
e.ActiveProcedureName,
|
||||
e.StableElapsedMilliseconds,
|
||||
e.StableTargetMilliseconds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新自动运行结果显示控件(线程安全)。
|
||||
/// </summary>
|
||||
/// <param name="state">自动流程状态。</param>
|
||||
/// <param name="message">状态描述。</param>
|
||||
/// <param name="productIndex">当前产品序号(从 1 开始)。</param>
|
||||
/// <param name="activeProcedureName">当前流程名。</param>
|
||||
/// <param name="stableElapsedMilliseconds">稳定计时已累计毫秒数。</param>
|
||||
/// <param name="stableTargetMilliseconds">稳定计时目标毫秒数。</param>
|
||||
private void UpdateAutoRunResultDisplay(
|
||||
AutoAssemblyState state,
|
||||
string message,
|
||||
int productIndex,
|
||||
string activeProcedureName,
|
||||
int stableElapsedMilliseconds,
|
||||
int stableTargetMilliseconds)
|
||||
{
|
||||
if (!IsHandleCreated || IsDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void UpdateAction()
|
||||
{
|
||||
lblRunState.ForeColor = GetAutoRunStateColor(state);
|
||||
lblRunState.Text = BuildAutoRunDisplayText(
|
||||
state,
|
||||
message,
|
||||
productIndex,
|
||||
activeProcedureName,
|
||||
stableElapsedMilliseconds,
|
||||
stableTargetMilliseconds);
|
||||
}
|
||||
|
||||
if (lblRunState.InvokeRequired)
|
||||
{
|
||||
lblRunState.BeginInvoke(new Action(UpdateAction));
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateAction();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造自动运行结果展示文本。
|
||||
/// </summary>
|
||||
/// <param name="state">自动流程状态。</param>
|
||||
/// <param name="message">状态描述。</param>
|
||||
/// <param name="productIndex">当前产品序号。</param>
|
||||
/// <param name="activeProcedureName">当前流程名。</param>
|
||||
/// <param name="stableElapsedMilliseconds">稳定计时累计毫秒数。</param>
|
||||
/// <param name="stableTargetMilliseconds">稳定计时目标毫秒数。</param>
|
||||
/// <returns>用于显示的多行文本。</returns>
|
||||
private static string BuildAutoRunDisplayText(
|
||||
AutoAssemblyState state,
|
||||
string message,
|
||||
int productIndex,
|
||||
string activeProcedureName,
|
||||
int stableElapsedMilliseconds,
|
||||
int stableTargetMilliseconds)
|
||||
{
|
||||
var displayProductIndex = productIndex <= 0 ? 1 : productIndex;
|
||||
var displayProcedure = string.IsNullOrWhiteSpace(activeProcedureName) ? "-" : activeProcedureName;
|
||||
var elapsed = Math.Max(0, stableElapsedMilliseconds);
|
||||
var target = Math.Max(0, stableTargetMilliseconds);
|
||||
if (target > 0)
|
||||
{
|
||||
elapsed = Math.Min(elapsed, target);
|
||||
}
|
||||
|
||||
return $"{GetAutoRunStateTitle(state)}\r\n产品序号:#{displayProductIndex}\r\n当前流程:{displayProcedure}\r\n稳定计时:{elapsed}/{target} ms\r\n状态描述:{message}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取自动状态标题文本。
|
||||
/// </summary>
|
||||
/// <param name="state">自动流程状态。</param>
|
||||
/// <returns>状态标题。</returns>
|
||||
private static string GetAutoRunStateTitle(AutoAssemblyState state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case AutoAssemblyState.LayerAInspecting:
|
||||
return "A层检测中";
|
||||
case AutoAssemblyState.LayerBInspecting:
|
||||
return "B层检测中";
|
||||
case AutoAssemblyState.LayerCInspecting:
|
||||
return "C层检测中";
|
||||
case AutoAssemblyState.ProductCompleted:
|
||||
return "整机检测OK";
|
||||
case AutoAssemblyState.Faulted:
|
||||
return "自动流程异常";
|
||||
case AutoAssemblyState.Stopped:
|
||||
return "自动流程已停止";
|
||||
default:
|
||||
return "自动流程空闲";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取自动状态标题颜色。
|
||||
/// </summary>
|
||||
/// <param name="state">自动流程状态。</param>
|
||||
/// <returns>状态颜色。</returns>
|
||||
private static Color GetAutoRunStateColor(AutoAssemblyState state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case AutoAssemblyState.LayerAInspecting:
|
||||
return Color.FromArgb(64, 196, 255);
|
||||
case AutoAssemblyState.LayerBInspecting:
|
||||
return Color.FromArgb(255, 179, 71);
|
||||
case AutoAssemblyState.LayerCInspecting:
|
||||
return Color.FromArgb(170, 132, 255);
|
||||
case AutoAssemblyState.ProductCompleted:
|
||||
return Color.FromArgb(120, 220, 130);
|
||||
case AutoAssemblyState.Faulted:
|
||||
return Color.FromArgb(255, 99, 99);
|
||||
case AutoAssemblyState.Stopped:
|
||||
return Color.FromArgb(200, 200, 200);
|
||||
default:
|
||||
return DarkThemeForeColor;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按配置构建自动装配流程参数。
|
||||
/// </summary>
|
||||
/// <returns>自动流程配置对象。</returns>
|
||||
private AutoAssemblyOptions BuildAutoAssemblyOptions()
|
||||
{
|
||||
return new AutoAssemblyOptions
|
||||
{
|
||||
ProcedureAName = GetAppSettingOrDefault("AutoRunProcedureAName", "A"),
|
||||
ProcedureBName = GetAppSettingOrDefault("AutoRunProcedureBName", "B"),
|
||||
ProcedureCName = GetAppSettingOrDefault("AutoRunProcedureCName", "C"),
|
||||
OkIntOutputName = GetAppSettingOrDefault("AutoRunOkIntOutputName", _renderResultIntOutputName1),
|
||||
OkIntOutputName2 = GetAppSettingOrDefault("AutoRunOkIntOutputName2", _renderResultIntOutputName2),
|
||||
OkIntValue = GetAppSettingIntOrDefault("AutoRunOkIntValue", 1),
|
||||
StableOkMilliseconds = GetAppSettingIntOrDefault("AutoRunStableMilliseconds", 2000),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 方案加载成功后按配置启动自动装配流程。
|
||||
/// </summary>
|
||||
private void StartAutoAssemblyIfConfigured()
|
||||
{
|
||||
if (!_autoRunEnabledAfterSolutionLoaded)
|
||||
{
|
||||
UpdateAutoRunResultDisplay(
|
||||
AutoAssemblyState.Idle,
|
||||
"自动流程已禁用(AutoRunEnabledAfterSolutionLoaded=false)",
|
||||
0,
|
||||
string.Empty,
|
||||
0,
|
||||
_autoAssemblyOptions.StableOkMilliseconds);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_isSolutionLoaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 切入自动模式前清理手动执行上下文,避免两套执行链路并发冲突。
|
||||
StopContinuousRunIfNeeded("切换到自动装配流程");
|
||||
UnbindProcedureWorkEndCallback();
|
||||
_currentProcedure = null;
|
||||
|
||||
_autoAssemblyController.Start();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException("启动自动装配流程", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止自动装配流程(若运行中)。
|
||||
/// </summary>
|
||||
/// <param name="reason">停止原因。</param>
|
||||
private void StopAutoAssemblyIfRunning(string reason)
|
||||
{
|
||||
try
|
||||
{
|
||||
_autoAssemblyController.Stop(reason);
|
||||
SyncAutoRunButtonState();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteLog($"停止自动装配流程异常:{ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步自动运行按钮文本(线程安全)。
|
||||
/// 运行中显示“停止自动”,未运行显示“自动运行”。
|
||||
/// </summary>
|
||||
private void SyncAutoRunButtonState()
|
||||
{
|
||||
if (!IsHandleCreated || IsDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void UpdateAction()
|
||||
{
|
||||
btnAutoRun.Text = _autoAssemblyController.IsRunning ? "停止自动" : "自动运行";
|
||||
}
|
||||
|
||||
if (btnAutoRun.InvokeRequired)
|
||||
{
|
||||
btnAutoRun.BeginInvoke(new Action(UpdateAction));
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateAction();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化 ReaLTaiizor 暗色主题,并将原生 WinForms 控件统一成暗色风格。
|
||||
/// </summary>
|
||||
@@ -635,6 +925,10 @@ namespace HkVisionPro.App
|
||||
_activeBcrTool = null;
|
||||
}
|
||||
|
||||
StopAutoAssemblyIfRunning("窗体关闭释放资源");
|
||||
_autoAssemblyController.StatusChanged -= AutoAssemblyController_StatusChanged;
|
||||
_autoAssemblyController.Dispose();
|
||||
|
||||
StopContinuousRunIfNeeded("窗体关闭释放资源");
|
||||
UnbindProcedureWorkEndCallback();
|
||||
_currentProcedure = null;
|
||||
@@ -702,6 +996,7 @@ namespace HkVisionPro.App
|
||||
_isSolutionLoaded = true;
|
||||
BindFirstModuleToRenderControl();
|
||||
UpdateProcedureList();
|
||||
StartAutoAssemblyIfConfigured();
|
||||
|
||||
WriteLog($"方案加载成功:{_currentSolutionPath}");
|
||||
MessageBox.Show(this, "方案加载成功。", "加载方案", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
@@ -709,6 +1004,7 @@ namespace HkVisionPro.App
|
||||
else
|
||||
{
|
||||
_isSolutionLoaded = false;
|
||||
StopAutoAssemblyIfRunning("方案加载失败");
|
||||
ResetProcedureAndModuleState();
|
||||
MessageBox.Show(this, $"方案加载失败,状态码:{endInfo.nStatus}", "加载方案", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
@@ -716,6 +1012,7 @@ namespace HkVisionPro.App
|
||||
catch (Exception ex)
|
||||
{
|
||||
_isSolutionLoaded = false;
|
||||
StopAutoAssemblyIfRunning("加载方案回调异常");
|
||||
ResetProcedureAndModuleState();
|
||||
HandleException("加载方案回调处理", ex);
|
||||
}
|
||||
@@ -831,23 +1128,29 @@ namespace HkVisionPro.App
|
||||
|
||||
try
|
||||
{
|
||||
// 字符串读取仅尝试字符串候选名,避免对 int 输出调用 GetOutputString 引发 SDK 内部异常。
|
||||
var code = GetProcedureOutputString(procedure, _renderCodeOutputName, _procedureOutputCodeName, "out0", "code", "Code");
|
||||
// 整型读取仅尝试整型候选名。
|
||||
var codeNum = GetProcedureOutputInt(procedure, _procedureOutputNumberName, "out");
|
||||
var bitmap = GetProcedureOutputBitmap(procedure, _renderImageOutputName, "ImageData", "Image", "image");
|
||||
var result1 = GetProcedureOutputInt(procedure, _renderResultIntOutputName1);
|
||||
var result2 = GetProcedureOutputInt(procedure, _renderResultIntOutputName2);
|
||||
var isResult1Ok = string.Equals(result1?.Trim(), "1", StringComparison.Ordinal);
|
||||
var isResult2Ok = string.Equals(result2?.Trim(), "1", StringComparison.Ordinal);
|
||||
var pairResult = isResult1Ok && isResult2Ok ? "OK" : "NG";
|
||||
var overlayText = $"R1={result1}, R2={result2}, Total={pairResult}";
|
||||
|
||||
var bitmap = GetProcedureOutputBitmap(procedure, _renderImageOutputName);
|
||||
if (bitmap == null)
|
||||
{
|
||||
WriteLog($"{triggerSource}未读取到可渲染图像,输出名候选:{_renderImageOutputName}/ImageData/Image/image");
|
||||
WriteLog($"{triggerSource}未读取到可渲染图像,固定输出名:{_renderImageOutputName}");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var roiList = GetProcedureOutputBoxList(procedure, _renderRoiOutputName, "InputROI", "rect", "outline", "ROI", "roi");
|
||||
var renderBitmap = DrawROIOnBitmap(bitmap, roiList, Color.Cyan, 2, code);
|
||||
var primaryRoiList = GetProcedureOutputBoxList(procedure, _renderRoiOutputName1);
|
||||
var secondaryRoiList = GetProcedureOutputBoxList(procedure, _renderRoiOutputName2);
|
||||
var mergedRoiList = MergeRoiLists(primaryRoiList, secondaryRoiList);
|
||||
var roiColor = pairResult == "OK" ? Color.Lime : Color.Red;
|
||||
var renderBitmap = DrawROIOnBitmap(bitmap, mergedRoiList, roiColor, 2, overlayText);
|
||||
SetPictureBoxImage(renderBitmap);
|
||||
WriteLog($"{triggerSource}渲染完成:Code={code},CodeNumber={codeNum},ROI数={roiList.Count}");
|
||||
WriteLog($"{triggerSource}渲染完成:Result1={result1},Result2={result2},Total={pairResult},ROI数={mergedRoiList.Count}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -930,6 +1233,32 @@ namespace HkVisionPro.App
|
||||
return new List<RectBox>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 合并多组 ROI 列表,避免流程多目标输出时遗漏展示。
|
||||
/// </summary>
|
||||
/// <param name="roiGroups">待合并 ROI 列表集合。</param>
|
||||
/// <returns>合并后的 ROI 列表。</returns>
|
||||
private static List<RectBox> MergeRoiLists(params List<RectBox>[] roiGroups)
|
||||
{
|
||||
var merged = new List<RectBox>();
|
||||
if (roiGroups == null || roiGroups.Length == 0)
|
||||
{
|
||||
return merged;
|
||||
}
|
||||
|
||||
foreach (var roiGroup in roiGroups)
|
||||
{
|
||||
if (roiGroup == null || roiGroup.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
merged.AddRange(roiGroup);
|
||||
}
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在图像上绘制 ROI 轮廓和识别文本。
|
||||
/// </summary>
|
||||
@@ -1148,11 +1477,13 @@ namespace HkVisionPro.App
|
||||
btnModuleBindingPar.Enabled = canOperateLoadedSolution;
|
||||
btnModuleExec.Enabled = canOperateLoadedSolution;
|
||||
btnModuleRenderResult.Enabled = canOperateLoadedSolution;
|
||||
btnAutoRun.Enabled = canOperateLoadedSolution;
|
||||
cmbProcdure.Enabled = canOperateLoadedSolution;
|
||||
cmbModule.Enabled = canOperateLoadedSolution;
|
||||
|
||||
// 保持连续执行按钮文案与状态一致。
|
||||
btnProExecAlway.Text = _isContinuousRunning ? "停止连续" : "连续执行";
|
||||
SyncAutoRunButtonState();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1301,6 +1632,54 @@ namespace HkVisionPro.App
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从 AppSettings 读取整型配置,失败时返回默认值。
|
||||
/// </summary>
|
||||
/// <param name="key">配置键名。</param>
|
||||
/// <param name="defaultValue">默认值。</param>
|
||||
/// <returns>解析后的整型值。</returns>
|
||||
private static int GetAppSettingIntOrDefault(string key, int defaultValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
var value = ConfigurationManager.AppSettings[key];
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return int.TryParse(value.Trim(), out var parsedValue) ? parsedValue : defaultValue;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从 AppSettings 读取布尔配置,失败时返回默认值。
|
||||
/// </summary>
|
||||
/// <param name="key">配置键名。</param>
|
||||
/// <param name="defaultValue">默认值。</param>
|
||||
/// <returns>解析后的布尔值。</returns>
|
||||
private static bool GetAppSettingBoolOrDefault(string key, bool defaultValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
var value = ConfigurationManager.AppSettings[key];
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return bool.TryParse(value.Trim(), out var parsedValue) ? parsedValue : defaultValue;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试获取当前选中的流程对象。
|
||||
/// </summary>
|
||||
@@ -1411,6 +1790,7 @@ namespace HkVisionPro.App
|
||||
/// </summary>
|
||||
private void ResetProcedureAndModuleState()
|
||||
{
|
||||
StopAutoAssemblyIfRunning("重置流程与模块状态");
|
||||
StopContinuousRunIfNeeded("重置流程与模块状态");
|
||||
UnbindProcedureWorkEndCallback();
|
||||
_currentProcedure = null;
|
||||
@@ -1427,40 +1807,6 @@ namespace HkVisionPro.App
|
||||
ClearPictureBoxImage();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取流程字符串输出(多候选容错读取)。
|
||||
/// </summary>
|
||||
private string GetProcedureOutputString(VmProcedure procedure, params string[] outputNames)
|
||||
{
|
||||
if (procedure == null || outputNames == null || outputNames.Length == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
foreach (var outputName in outputNames)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(outputName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var output = procedure.ModuResult.GetOutputString(outputName);
|
||||
if (output.astStringVal != null && output.astStringVal.Length > 0)
|
||||
{
|
||||
return output.astStringVal[0].strValue;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 忽略输出不存在等异常,保持流程主链路稳定。
|
||||
}
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取流程整型输出(多候选容错读取)。
|
||||
/// </summary>
|
||||
@@ -1660,6 +2006,12 @@ namespace HkVisionPro.App
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导入流程按钮事件:从外部 <c>.prc</c> 文件导入流程到当前方案,并刷新流程列表。
|
||||
/// 该方法包含完整的前置状态检查(忙碌态、方案是否已加载)与异常处理,避免 UI 重入导致的状态错乱。
|
||||
/// </summary>
|
||||
/// <param name="sender">事件源控件(导入按钮)。</param>
|
||||
/// <param name="e">标准事件参数。</param>
|
||||
private void btnProImport_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_isBusy)
|
||||
@@ -1693,6 +2045,7 @@ namespace HkVisionPro.App
|
||||
procedurePath = dialog.FileName;
|
||||
}
|
||||
|
||||
// 通过 VM SDK 加载流程文件到当前方案上下文。
|
||||
VmProcedure.Load(procedurePath);
|
||||
UpdateProcedureList();
|
||||
WriteLog($"流程导入成功:{procedurePath}");
|
||||
@@ -1708,6 +2061,11 @@ namespace HkVisionPro.App
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导出流程按钮事件:将当前选中的流程导出为独立 <c>.prc</c> 文件。
|
||||
/// </summary>
|
||||
/// <param name="sender">事件源控件(导出按钮)。</param>
|
||||
/// <param name="e">标准事件参数。</param>
|
||||
private void btnProExpo_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_isBusy)
|
||||
@@ -1739,6 +2097,7 @@ namespace HkVisionPro.App
|
||||
try
|
||||
{
|
||||
UpdateUiState(true);
|
||||
// 仅导出当前选中流程,不影响方案内其它流程。
|
||||
procedure.SaveAs(dialog.FileName);
|
||||
WriteLog($"流程导出成功:{dialog.FileName}");
|
||||
MessageBox.Show(this, "流程导出成功。", "导出流程", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
@@ -1754,6 +2113,11 @@ namespace HkVisionPro.App
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除流程按钮事件:删除当前选中的流程,并同步清理界面绑定状态(模块列表、参数面板、渲染图像)。
|
||||
/// </summary>
|
||||
/// <param name="sender">事件源控件(删除按钮)。</param>
|
||||
/// <param name="e">标准事件参数。</param>
|
||||
private void btnProDel_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_isBusy)
|
||||
@@ -1781,6 +2145,7 @@ namespace HkVisionPro.App
|
||||
try
|
||||
{
|
||||
UpdateUiState(true);
|
||||
// 从方案中删除流程,并清理当前流程回调绑定,避免悬挂引用。
|
||||
VmSolution.Instance.DeleteOneProcedure(selectedProcedureName);
|
||||
UnbindProcedureWorkEndCallback();
|
||||
_currentProcedure = null;
|
||||
@@ -1800,6 +2165,11 @@ namespace HkVisionPro.App
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行一次按钮事件:对当前选中流程执行单次运行,并在流程结束回调中刷新渲染结果。
|
||||
/// </summary>
|
||||
/// <param name="sender">事件源控件(执行一次按钮)。</param>
|
||||
/// <param name="e">标准事件参数。</param>
|
||||
private void btnProExecOnce_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_isBusy)
|
||||
@@ -1820,6 +2190,7 @@ namespace HkVisionPro.App
|
||||
try
|
||||
{
|
||||
UpdateUiState(true);
|
||||
// 执行单次前先停掉连续执行,保证流程运行模式互斥。
|
||||
StopContinuousRunIfNeeded("执行单次流程");
|
||||
UnbindProcedureWorkEndCallback();
|
||||
_currentProcedure = procedure;
|
||||
@@ -1838,6 +2209,13 @@ namespace HkVisionPro.App
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连续执行按钮事件(启停一体):
|
||||
/// - 若当前未连续运行,则启动选中流程的连续执行;
|
||||
/// - 若当前已连续运行,则先停止,再根据选择情况决定是否切换到新流程继续运行。
|
||||
/// </summary>
|
||||
/// <param name="sender">事件源控件(连续执行按钮)。</param>
|
||||
/// <param name="e">标准事件参数。</param>
|
||||
private void btnProExecAlway_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_isBusy)
|
||||
@@ -1873,6 +2251,7 @@ namespace HkVisionPro.App
|
||||
}
|
||||
}
|
||||
|
||||
// 显式开启 SDK 连续执行标记,并重新绑定流程结束回调。
|
||||
procedure.ContinuousRunEnable = true;
|
||||
UnbindProcedureWorkEndCallback();
|
||||
_currentProcedure = procedure;
|
||||
@@ -1899,6 +2278,11 @@ namespace HkVisionPro.App
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止执行按钮事件:在连续执行模式下,主动停止当前流程连续运行并同步按钮状态。
|
||||
/// </summary>
|
||||
/// <param name="sender">事件源控件(停止按钮)。</param>
|
||||
/// <param name="e">标准事件参数。</param>
|
||||
private void btnProExecStop_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_isBusy)
|
||||
@@ -1917,10 +2301,16 @@ namespace HkVisionPro.App
|
||||
return;
|
||||
}
|
||||
|
||||
// 仅处理连续执行停止,不触发新的执行请求。
|
||||
StopContinuousRunIfNeeded("用户点击停止按钮");
|
||||
UpdateUiState(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绑定参数按钮事件:将当前模块绑定到参数配置控件,供用户查看或调整模块参数。
|
||||
/// </summary>
|
||||
/// <param name="sender">事件源控件(绑定参数按钮)。</param>
|
||||
/// <param name="e">标准事件参数。</param>
|
||||
private void btnModuleBindingPar_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_isBusy)
|
||||
@@ -1940,6 +2330,7 @@ namespace HkVisionPro.App
|
||||
|
||||
try
|
||||
{
|
||||
// 将模块对象注入参数控件,参数控件内部负责参数树加载与编辑。
|
||||
vmParamsConfigControl1.ModuleSource = module;
|
||||
WriteLog($"绑定模块参数成功:{cmbProcdure.Text}.{cmbModule.Text}");
|
||||
}
|
||||
@@ -1949,6 +2340,12 @@ namespace HkVisionPro.App
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行模块按钮事件:执行当前模块,并尝试刷新流程渲染结果;
|
||||
/// 若为条码模块,则自动注册条码结果回调用于实时日志输出。
|
||||
/// </summary>
|
||||
/// <param name="sender">事件源控件(执行模块按钮)。</param>
|
||||
/// <param name="e">标准事件参数。</param>
|
||||
private void btnModuleExec_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_isBusy)
|
||||
@@ -1970,6 +2367,7 @@ namespace HkVisionPro.App
|
||||
{
|
||||
UpdateUiState(true);
|
||||
|
||||
// 先执行模块本体,再根据当前流程输出刷新界面渲染。
|
||||
module.Run();
|
||||
if (TryGetSelectedProcedure(out var procedure))
|
||||
{
|
||||
@@ -1983,6 +2381,7 @@ namespace HkVisionPro.App
|
||||
_activeBcrTool = null;
|
||||
}
|
||||
|
||||
// 若当前模块支持条码结果回调,启用回调并做去重绑定。
|
||||
var bcrTool = module as IMVSBcrModuTool;
|
||||
if (bcrTool != null)
|
||||
{
|
||||
@@ -2007,6 +2406,11 @@ namespace HkVisionPro.App
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 渲染结果按钮事件:不重新执行模块,仅根据当前流程最新输出重绘图像/ROI/识别结果。
|
||||
/// </summary>
|
||||
/// <param name="sender">事件源控件(渲染结果按钮)。</param>
|
||||
/// <param name="e">标准事件参数。</param>
|
||||
private void btnModuleRenderResult_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_isBusy)
|
||||
@@ -2068,6 +2472,11 @@ namespace HkVisionPro.App
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 模块下拉展开事件:在用户展开模块下拉框时动态刷新模块列表,确保显示与当前流程一致。
|
||||
/// </summary>
|
||||
/// <param name="sender">事件源控件(模块下拉框)。</param>
|
||||
/// <param name="e">标准事件参数。</param>
|
||||
private void cmbModule_DropDown(object sender, EventArgs e)
|
||||
{
|
||||
if (_isBusy || !_isSolutionLoaded)
|
||||
@@ -2086,6 +2495,11 @@ namespace HkVisionPro.App
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 流程下拉展开事件:在用户展开流程下拉框时动态刷新流程列表,避免旧缓存造成显示不一致。
|
||||
/// </summary>
|
||||
/// <param name="sender">事件源控件(流程下拉框)。</param>
|
||||
/// <param name="e">标准事件参数。</param>
|
||||
private void cmbProcdure_DropDown(object sender, EventArgs e)
|
||||
{
|
||||
if (_isBusy || !_isSolutionLoaded)
|
||||
@@ -2114,9 +2528,66 @@ namespace HkVisionPro.App
|
||||
ReleaseSdkResources();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 主窗体加载事件。
|
||||
/// 当前初始化逻辑已在构造函数中完成(主题、回调、UI 状态),
|
||||
/// 因此此处暂不添加额外业务处理,预留后续扩展入口。
|
||||
/// </summary>
|
||||
/// <param name="sender">事件源控件(主窗体)。</param>
|
||||
/// <param name="e">标准事件参数。</param>
|
||||
private void MainForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自动运行按钮事件。
|
||||
/// 点击后执行自动流程启停切换:
|
||||
/// - 未运行:启动自动状态机;
|
||||
/// - 运行中:停止自动状态机。
|
||||
/// </summary>
|
||||
/// <param name="sender">事件源控件(自动运行按钮)。</param>
|
||||
/// <param name="e">标准事件参数。</param>
|
||||
private void btnAutoRun_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_isBusy)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!EnsureSolutionLoaded("自动运行"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
UpdateUiState(true);
|
||||
|
||||
if (_autoAssemblyController.IsRunning)
|
||||
{
|
||||
StopAutoAssemblyIfRunning("用户点击自动运行按钮停止");
|
||||
WriteLog("自动装配流程已停止(按钮触发)。");
|
||||
return;
|
||||
}
|
||||
|
||||
// 启动自动流程前清理手动流程执行上下文,确保执行链路互斥。
|
||||
StopContinuousRunIfNeeded("点击自动运行按钮");
|
||||
UnbindProcedureWorkEndCallback();
|
||||
_currentProcedure = null;
|
||||
|
||||
_autoAssemblyController.Start();
|
||||
SyncAutoRunButtonState();
|
||||
WriteLog("自动装配流程已启动(按钮触发)。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException("自动运行按钮操作", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
UpdateUiState(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user