C3032
2026-03-18 e90b36a0fb76d9319390b5984a21a83e4748a3b3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
using HalconDotNet;
using LB_SmartVision.Tool;
using System.Data;
using System.Runtime.InteropServices;
using System.Xml.Linq;
 
namespace LB_SmartVision.Forms.Pages.ProcessPage
{
    public partial class AllProcessesPage : TabPage
    {
        public ObservableConcurrentDictionary<string, ProcessControl> dicProcessControls = new ObservableConcurrentDictionary<string, ProcessControl>();
        // 保存控件原始布局(尺寸+位置),用于恢复矩阵布局
        private Dictionary<string, (Size Size, Point Location)> _originalControlLayouts = new Dictionary<string, (Size, Point)>();
        // 标记是否处于全屏状态
        private bool _isFullScreen = false;
        // 记录当前全屏的控件标题
        private string _fullScreenControlTitle = string.Empty;
        /// <summary>
        /// 实例化流程界面
        /// </summary>
        /// <param name="dicProcesses"></param>
        public AllProcessesPage()
        {
            InitializeComponent();
 
            Name = "AllProcessesPage";
            Text = "主界面";
            //this.Font = new Font("Microsoft YaHei UI", 16F, FontStyle.Regular, GraphicsUnit.Point, 0);
            this.BackColor = Color.FromArgb(32, 41, 50);
 
            InitVisionUI();
            this.Invalidated += AllProcessesPage_Invalidated;
        }
 
        private void AllProcessesPage_Invalidated(object? sender, InvalidateEventArgs e) => InitVisionUI();
 
        public void InitVisionUI()
        {
            List<string> keys = dicProcessControls.Keys.ToList();
 
            foreach (var title in keys)
            {
                bool isExist = false;
                foreach (var layout in GlobalVar.dicLayout.Values)
                {
                    if (layout.Title == title)
                    {
                        isExist = true;
                        break;
                    }
                }
 
                if (!isExist)
                {
                    if (dicProcessControls.ContainsKey(title))
                    {
                        // 移除前先解绑事件,避免内存泄漏
                        var control = dicProcessControls[title];
                        control.event_MouseDoubleClick -= ProcessControl_DoubleClick;
 
                        this.controlsPanel.Controls.Remove(dicProcessControls[title]);
                        dicProcessControls.TryRemove(title, out _);
 
                        // 移除原始布局记录
                        if (_originalControlLayouts.ContainsKey(title))
                            _originalControlLayouts.Remove(title);
                    }
                }
            }
 
            int enableLayout = 0;
            foreach (var layout in GlobalVar.dicLayout.Values)
            {
                if (GlobalVar.dicProcesses.ContainsKey(layout.ProcessName))
                    enableLayout++;
            }
            //总行数,向下取整
            int matrixRows = (int)Math.Floor(Math.Sqrt(enableLayout));
            if (enableLayout == 0 || matrixRows == 0)
            {
                _originalControlLayouts.Clear();
                _isFullScreen = false;
                _fullScreenControlTitle = string.Empty;
                // 无启用布局时直接返回,避免除零错误
                return;
            }
            //总列数,向上取整
            int matrixColumns = (int)Math.Ceiling((double)enableLayout / matrixRows);
            int index = 0;
            // 计算每个ProcessControl的尺寸(按行列均分面板大小)
            int controlWidth = this.controlsPanel.Width / matrixColumns;
            int controlHeight = this.controlsPanel.Height / matrixRows;
            // 每次重构布局时清空原始记录
            _originalControlLayouts.Clear();
            for (int i = 0; i < GlobalVar.dicLayout.Count; i++)
            {
                string name = GlobalVar.dicLayout[i].ProcessName;
                string title = GlobalVar.dicLayout[i].Title;
 
                if (GlobalVar.dicProcesses.ContainsKey(name))
                {
                    // 计算当前控件的行列索引
                    int colIndex = index % matrixColumns; // 列索引(0,1,0,1...)
                    int rowIndex = index / matrixColumns; // 行索引(0,0,1,1...)
                                                          // 计算原始位置和尺寸(矩阵布局)
                    Size originalSize = new Size(controlWidth, controlHeight);
                    Point originalLocation = new Point(colIndex * controlWidth, rowIndex * controlHeight);
                    ProcessControl processControl;
                    if (dicProcessControls.ContainsKey(title))
                    {
                        // 复用已有控件,更新尺寸和位置
                        processControl = dicProcessControls[title];
                        processControl.Size = originalSize;
                        processControl.Location = originalLocation;
                        processControl.Visible = true;
                        // 解绑旧事件,避免重复绑定
                        processControl.event_MouseDoubleClick -= ProcessControl_DoubleClick;
                    }
                    else
                    {
                        // 新建控件,按矩阵布局赋值尺寸和位置
                        processControl = new ProcessControl(GlobalVar.dicLayout[i]);
                        processControl.Size = originalSize;
                        processControl.Location = originalLocation;
                        processControl.SetTitle(title);
 
                        // 添加到字典和面板
                        dicProcessControls.TryAdd(title, processControl);
                        this.controlsPanel.Controls.Add(processControl);
 
                    }
 
                    // 绑定双击事件(左键)和鼠标按下事件(右键双击)
                    processControl.event_MouseDoubleClick += ProcessControl_DoubleClick;
 
                    // 保存原始布局(矩阵状态)
                    _originalControlLayouts[title] = (originalSize, originalLocation);
 
                    // 更新图片
                    if (GlobalVar.dicProcesses[name].GetImage(GlobalVar.dicLayout[i], out _, out HObject recordImage))
                        dicProcessControls[title].ShowHoImage(recordImage);
 
                    index++; // 仅启用的布局索引递增
                }
            }
            // 如果当前是全屏状态,恢复矩阵布局后重置状态
            if (_isFullScreen)
            {
                _isFullScreen = false;
                _fullScreenControlTitle = string.Empty;
            }
        }
        #region 双击事件处理(全屏/恢复布局)
        /// <summary>
        /// 左键双击事件:全屏显示当前ProcessControl
        /// </summary>
        private void ProcessControl_DoubleClick(object sender, EventArgs e)
        {
            if (_isFullScreen)
            {
                RestoreMatrixLayout();
                return;
            }
 
            var targetControl = sender as ProcessControl;
            if (targetControl == null || string.IsNullOrEmpty(targetControl.Title)) return;
 
            // 记录全屏的控件标题
            _fullScreenControlTitle = targetControl.Title;
            _isFullScreen = true;
 
            // 隐藏所有其他ProcessControl,仅显示目标控件
            foreach (var kvp in dicProcessControls)
            {
                if (kvp.Key != _fullScreenControlTitle)
                {
                    kvp.Value.Visible = false;
                }
                else
                {
                    // 目标控件设为面板大小,位置(0,0)(全屏)
                    kvp.Value.Size = this.controlsPanel.Size;
                    kvp.Value.Location = new Point(0, 0);
                    kvp.Value.BringToFront(); // 确保在最上层
                }
            }
        }
 
        /// <summary>
        /// 恢复矩阵布局(复用InitVisionUI的核心逻辑,避免代码重复)
        /// </summary>
        private void RestoreMatrixLayout()
        {
            // 1. 重置全屏状态
            _isFullScreen = false;
            _fullScreenControlTitle = string.Empty;
 
            // 2. 恢复所有控件的原始尺寸、位置和可见性
            foreach (var kvp in dicProcessControls)
            {
                string title = kvp.Key;
                var control = kvp.Value;
 
                // 3. 从原始布局字典中恢复尺寸和位置
                if (_originalControlLayouts.TryGetValue(title, out var originalLayout))
                {
                    control.Size = originalLayout.Size;
                    control.Location = originalLayout.Location;
                }
                control.Visible = true; // 显示控件
            }
        }
        #endregion
    }
}