using OpenVinoSharp.Extensions;
|
using Sunny.UI;
|
using System;
|
using System.Collections.Generic;
|
using System.ComponentModel;
|
using System.Data;
|
using System.Diagnostics;
|
using System.Drawing;
|
using System.Linq;
|
using System.Reflection.Emit;
|
using System.Text;
|
using System.Threading.Tasks;
|
using System.Windows.Forms;
|
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Button;
|
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Window;
|
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
|
using MyCameras;
|
using System.Collections.Concurrent;
|
using MyVision.Forms.Pages;
|
using MyVision.Forms;
|
using MyProcesses;
|
using MyProcesses.Communicators;
|
using Newtonsoft.Json;
|
using SharpCompress.Common;
|
using OpenVinoSharp;
|
using System.Text.RegularExpressions;
|
using HalconDotNet;
|
using MyProcesses.Alogrithms.Halcon;
|
using MyCommunicators;
|
|
namespace MyVision
|
{
|
/// <summary>
|
/// Windows10、Windows11 建议用UIForm2,更接近原生窗体使用体验,用UIForm也可以
|
/// WindowsXP、Windows7 建议使用UIForm
|
/// </summary>
|
public partial class MainForm : UIForm2
|
{
|
ICamera camera = new MindCamera();
|
/// <summary>
|
/// 相机集合(Key:相机SN,Value:相机句柄)
|
/// </summary>
|
ConcurrentDictionary<string, BaseCamera> dicCameras = new ConcurrentDictionary<string, BaseCamera>();
|
int CamerasPageIndex = 2000;
|
|
/// <summary>
|
/// 流程集合(Key:相机SN,Value:object为IProcess时,string为ID,object为ICamera时,string为SN)
|
/// </summary>
|
ConcurrentDictionary<string, List<object>> dicProcesses = new ConcurrentDictionary<string, List<object>>();
|
int ProcessesPageIndex = 3000;
|
|
/// <summary>
|
/// 通讯集合(Key:通讯名,Value:通讯句柄)
|
/// </summary>
|
ConcurrentDictionary<string, BaseCommunicator> dicCommunicator = new ConcurrentDictionary<string, BaseCommunicator>();
|
ConcurrentDictionary<string, string> allCommunicatorsConnectionString = new ConcurrentDictionary<string, string>();
|
string allCommunicatorsConnectionStringPath = ".\\CommunicatorsConnection.json";
|
|
public MainForm()
|
{
|
InitializeComponent();
|
|
//关联窗体承载多页面框架的容器UITabControl
|
//窗体上如果只有一个UITabControl,也会自动关联,超过一个需要手动关联
|
this.MainTabControl = uiTabControl1;
|
uiNavBar1.TabControl = uiTabControl1;
|
uiNavMenu1.TabControl = uiTabControl1;
|
|
//uiNavBar1设置节点,也可以在Nodes属性里配置
|
uiNavBar1.Nodes.Add("测试");
|
uiNavBar1.Nodes.Add("相机");
|
uiNavBar1.Nodes.Add("流程");
|
uiNavBar1.Nodes.Add("通讯");
|
uiNavBar1.Nodes.Add("设置");
|
uiNavBar1.Nodes.Add("主题");
|
|
//设置初始页面索引(关联页面,唯一不重复即可)
|
int pageIndex = 1000;
|
uiNavBar1.SetNodePageIndex(uiNavBar1.Nodes[0], pageIndex);
|
uiNavBar1.SetNodeSymbol(uiNavBar1.Nodes[0], 61764);
|
|
TreeNode parent = uiNavMenu1.CreateNode("测试", 61764, 24, pageIndex);
|
//通过设置GUID关联,节点字体图标和大小由UIPage设置
|
uiNavMenu1.CreateChildNode(parent, AddPage(new UIPage(), Guid.NewGuid()));
|
//uiNavMenu1.CreateChildNode(parent, AddPage(new FDialogs(), Guid.NewGuid()));
|
//uiNavMenu1.CreateChildNode(parent, AddPage(new FEditor(), Guid.NewGuid()));
|
//uiNavMenu1.CreateChildNode(parent, AddPage(new FFrames(), Guid.NewGuid()));
|
|
pageIndex = 2000;
|
uiNavBar1.SetNodePageIndex(uiNavBar1.Nodes[1], pageIndex);
|
uiNavBar1.SetNodeSymbol(uiNavBar1.Nodes[1], 61501);
|
parent = uiNavMenu1.CreateNode("相机", 61501, 24, pageIndex);
|
CamerasPageIndex = pageIndex;
|
|
//通过设置PageIndex关联,节点文字、图标由相应的Page的Text、Symbol提供
|
int iCameraCount = 0;
|
foreach (var item in ((MindCamera)camera).GetListEnum())
|
{
|
MindCamera camera = new MindCamera();
|
if (camera.InitDevice(item.ToString(), this.Handle))
|
{
|
dicCameras.TryAdd(camera.SN, camera);
|
dicProcesses.TryAdd(camera.SN, new List<object>());
|
uiNavMenu1.CreateChildNode(parent, AddPage(new CameraPage(dicCameras[camera.SN]), ++pageIndex));
|
//设置相机连接成功的小绿点提示
|
uiNavMenu1.SetNodeTipsText(parent.Nodes[iCameraCount], " ", Color.Green, Color.White);
|
}
|
iCameraCount++;
|
}
|
|
//设置相机连接的个数显示
|
uiNavMenu1.ShowTips = true;
|
uiNavMenu1.SetNodeTipsText(uiNavMenu1.Nodes[1], iCameraCount.ToString(), iCameraCount == 0 ? Color.Red : Color.Green, Color.White);
|
|
pageIndex = 3000;
|
uiNavBar1.SetNodePageIndex(uiNavBar1.Nodes[2], pageIndex);
|
uiNavBar1.SetNodeSymbol(uiNavBar1.Nodes[2], 61451);
|
parent = uiNavMenu1.CreateNode("流程", 61451, 24, pageIndex);
|
ProcessesPageIndex = pageIndex;
|
//从数据库中读取流程
|
ProcessDatabasePage processDatabasePage = new ProcessDatabasePage(dicCameras, dicProcesses);
|
uiNavMenu1.CreateChildNode(parent, AddPage(processDatabasePage, ++pageIndex));
|
//直接关联(默认自动生成GUID)
|
foreach (var item in dicCameras.Values)
|
{
|
uiNavMenu1.CreateChildNode(parent, AddPage(new ProcessPage(item, processDatabasePage.dicProcesses[((BaseCamera)item).SN], dicCameras, dicCommunicator), ++pageIndex));
|
}
|
|
//uiNavMenu1.CreateChildNode(parent, AddPage(new FBarChart()));
|
//uiNavMenu1.CreateChildNode(parent, AddPage(new FDoughnutChart()));
|
//uiNavMenu1.CreateChildNode(parent, AddPage(new FLineChart()));
|
//uiNavMenu1.CreateChildNode(parent, AddPage(new FPieChart()));
|
|
pageIndex = 4000;
|
uiNavBar1.SetNodePageIndex(uiNavBar1.Nodes[3], pageIndex);
|
uiNavBar1.SetNodeSymbol(uiNavBar1.Nodes[3], 61971);
|
parent = uiNavMenu1.CreateNode("通讯", 61971, 24, pageIndex);
|
//直接关联(默认自动生成GUID)
|
LoadAllCommunicator();
|
uiNavMenu1.CreateChildNode(parent, AddPage(new CommunicatorsPage(dicCommunicator), ++pageIndex));
|
//uiNavMenu1.CreateChildNode(parent, AddPage(CreateInstance<UIPage>("Sunny.UI.Demo.FPipe")));
|
//uiNavMenu1.CreateChildNode(parent, AddPage(CreateInstance<UIPage>("Sunny.UI.Demo.FMeter")));
|
//uiNavMenu1.CreateChildNode(parent, AddPage(CreateInstance<UIPage>("Sunny.UI.Demo.FLed")));
|
//uiNavMenu1.CreateChildNode(parent, AddPage(CreateInstance<UIPage>("Sunny.UI.Demo.FLight")));
|
//uiNavMenu1.CreateChildNode(parent, AddPage(CreateInstance<UIPage>("Sunny.UI.Demo.FSwitch")));
|
|
pageIndex = 5000;
|
uiNavBar1.SetNodePageIndex(uiNavBar1.Nodes[4], pageIndex);
|
uiNavBar1.SetNodeSymbol(uiNavBar1.Nodes[4], 61459);
|
parent = uiNavMenu1.CreateNode("设置", 61459, 24, pageIndex);
|
//直接关联(默认自动生成GUID)
|
uiNavMenu1.CreateChildNode(parent, AddPage(new UIPage(), ++pageIndex));
|
|
uiNavBar1.SetNodeSymbol(uiNavBar1.Nodes[5], 61502);
|
var styles = UIStyles.PopularStyles();
|
foreach (UIStyle style in styles)
|
{
|
uiNavBar1.CreateChildNode(uiNavBar1.Nodes[5], style.DisplayText(), style.Value());
|
}
|
|
//var node = uiNavBar1.CreateChildNode(uiNavBar1.Nodes[4], "字体图标", 99999);
|
//uiNavBar1.SetNodeSymbol(node, 558426);
|
//node = uiNavBar1.CreateChildNode(uiNavBar1.Nodes[5], "多彩主题", UIStyle.Colorful.Value());
|
//uiNavBar1.SetNodeSymbol(node, 558295);
|
//左侧导航主节点关联页面
|
//uiNavMenu1.CreateNode(AddPage(new UIPage(), 99999));
|
//uiNavMenu1.CreateNode(AddPage(new FSymbols(), 99999));
|
//uiNavMenu1.CreateNode(AddPage(new FColorful(), UIStyle.Colorful.Value()));
|
|
//直接增加一个页面,不在左侧列表显示
|
//AddPage(new FCommon());
|
|
//选中第1001个节点("测试节点下的第一个节点")
|
uiNavMenu1.SelectPage(1001);
|
|
uiPanel2.Text = Text = Version;
|
RegisterHotKey(Sunny.UI.ModifierKeys.Shift, Keys.F8);
|
|
//根据页面类型获取页面
|
//FButton page = GetPage<FButton>();
|
//if (page != null)
|
// page.Text.WriteConsole();
|
|
//根据页面索引获取页面
|
UIPage page1 = GetPage(1001);
|
if (page1 != null)
|
page1.Text.WriteConsole();
|
|
timer1.Start();
|
timer60.Start();
|
}
|
|
public bool LoadAllCommunicator()
|
{
|
if (!File.Exists(allCommunicatorsConnectionStringPath))
|
{
|
Console.WriteLine("文件不存在创建空文件");
|
// 获取不带文件名的目录路径
|
string directoryPath = Path.GetDirectoryName(allCommunicatorsConnectionStringPath);
|
SaveAllCommunicator();
|
return true;
|
}
|
string strJson = string.Empty;
|
using (StreamReader streamReader = new StreamReader(allCommunicatorsConnectionStringPath, Encoding.UTF8))
|
{
|
strJson = streamReader.ReadToEnd();
|
streamReader.Close();
|
}
|
|
allCommunicatorsConnectionString = JsonConvert.DeserializeObject<ConcurrentDictionary<string, string>>(strJson);
|
if (allCommunicatorsConnectionString == null)
|
{
|
UIMessageBox.ShowError("通讯端口加载失败");
|
return false;
|
}
|
|
foreach (var CommunicatorConnectionString in allCommunicatorsConnectionString)
|
{
|
string CommunicatorName = CommunicatorConnectionString.Key;
|
string CommunicatorAddress = CommunicatorConnectionString.Value;
|
|
// 定义正则表达式以提取协议、IP 地址和端口
|
//1. \((.*?)\):\(和 \) 是用于匹配括号的转义字符。
|
// (.*?) 是一个非贪婪的匹配,用来匹配类名(MyProcesses.Communicators.TCPServer 或 MyProcesses.Communicators.UARTPort)。
|
//2. ([^:] +):匹配冒号之前的部分,即地址(127.0.0.1 或 COM5)。这里使用了[^:] 来匹配除了冒号之外的任意字符。
|
//3. (\d +) :匹配端口号,确保它匹配一个或多个数字。
|
|
var regex = new Regex(@"\((.*?)\)([^:]+):(\d+)");
|
var match = regex.Match(CommunicatorAddress);
|
|
if (match.Success)
|
{
|
string ClassName = match.Groups[1].Value; // "TCP"
|
string IP = match.Groups[2].Value; // "127.0.0.1"
|
string PORT = match.Groups[3].Value; // "1111"
|
|
if (string.IsNullOrEmpty(ClassName) || string.IsNullOrEmpty(IP) || string.IsNullOrEmpty(PORT))
|
break;
|
|
//利用反射创建实例
|
Type type = ICommunicator.GetExecutingAssembly().GetType(ClassName);
|
if (type == null)
|
{
|
Console.WriteLine("Class not found.");
|
return false;
|
}
|
var Communicator = Activator.CreateInstance(type) as BaseCommunicator;
|
|
if (Communicator == null)
|
{
|
Console.WriteLine("BaseCommunicator not found.");
|
return false;
|
}
|
|
Communicator.CommunicatorConnections.Add("名称", CommunicatorName);
|
Communicator.CommunicatorConnections.Add("地址", IP);
|
Communicator.CommunicatorConnections.Add("端口", PORT);
|
if (!Communicator.Connect())
|
UIMessageBox.ShowError(Communicator.strMsg);
|
|
dicCommunicator.TryAdd(CommunicatorName, Communicator);
|
}
|
else
|
{
|
Console.WriteLine("No match found.");
|
}
|
|
}
|
return true;
|
}
|
|
public bool SaveAllCommunicator()
|
{
|
try
|
{
|
string strJson = string.Empty;
|
allCommunicatorsConnectionString = new ConcurrentDictionary<string, string>();
|
|
foreach (var item in dicCommunicator)
|
{
|
string ClassName = item.Value.GetType().FullName;// "TCP"
|
string IP = item.Value.CommunicatorConnections["地址"].ToString();//"127.0.0.1"
|
string PORT = item.Value.CommunicatorConnections["端口"].ToString();//"1111"
|
|
if (string.IsNullOrEmpty(ClassName) || string.IsNullOrEmpty(IP) || string.IsNullOrEmpty(PORT))
|
break;
|
|
string CommunicatorConnectionString = $"({ClassName}){IP}:{PORT}";
|
allCommunicatorsConnectionString.TryAdd(item.Key, CommunicatorConnectionString);
|
}
|
|
strJson = JsonConvert.SerializeObject(allCommunicatorsConnectionString);
|
BaseCommunicator.JsonFormatting(ref strJson);
|
//判断文件夹是否存在,防呆输入为文件名称
|
string directoryPath = Path.GetDirectoryName(allCommunicatorsConnectionStringPath);
|
if (!Directory.Exists(directoryPath))
|
{
|
try
|
{
|
Directory.CreateDirectory(directoryPath);
|
}
|
catch (Exception)
|
{ }
|
}
|
File.WriteAllText(allCommunicatorsConnectionStringPath, strJson, Encoding.UTF8);
|
return true;
|
}
|
catch { return false; }
|
}
|
/// <summary>
|
/// 创建对象实例
|
/// </summary>
|
/// <typeparam name="T"></typeparam>
|
/// <param name="fullName">命名空间.类型名</param>
|
/// <returns></returns>
|
public static T CreateInstance<T>(string fullName)
|
{
|
Type o = Type.GetType(fullName);
|
dynamic obj = Activator.CreateInstance(o, true);
|
return (T)obj;//类型转换并返回
|
}
|
|
|
int lastMenuIndex = 0;
|
private void uiNavBar1_MenuItemClick(string itemText, int menuIndex, int pageIndex)
|
{
|
switch (lastMenuIndex)
|
{
|
//第一个节点是相机
|
//上一个节点是相机的话需要取消显示回调
|
case 1:
|
for (int i = CamerasPageIndex + 1; ; i++)
|
{
|
//根据页面索引获取页面
|
object page1 = GetPage(i);
|
if (page1 == null)
|
break;
|
if (page1 is CameraPage)
|
{
|
((CameraPage)page1).Unsubscribe();
|
((CameraPage)page1).StopContinueGrabbing();
|
}
|
}
|
break;
|
default:
|
break;
|
}
|
|
switch (menuIndex)
|
{
|
//第一个节点是相机
|
//当前选择的节点是相机的话需要重新加载显示回调
|
case 1:
|
//根据页面索引获取页面
|
object page1 = GetPage(pageIndex);
|
if (page1 == null)
|
break;
|
if (page1 is CameraPage)
|
((CameraPage)page1).Subscribe();
|
break;
|
|
//第五个节点是切换语言
|
case 5:
|
UIStyle style = (UIStyle)pageIndex;
|
if (pageIndex < UIStyle.Colorful.Value())
|
StyleManager.Style = style;
|
else
|
uiNavMenu1.SelectPage(pageIndex);
|
break;
|
default:
|
uiNavMenu1.SelectPage(pageIndex);
|
break;
|
}
|
lastMenuIndex = menuIndex;
|
}
|
|
int lastPageIndex = 0;
|
private void uiNavMenu1_MenuItemClick(TreeNode node, NavMenuItem item, int pageIndex)
|
{
|
//上一个节点是相机的话需要取消显示回调
|
if (lastPageIndex >= 2000 && lastPageIndex < 3000)
|
{
|
//根据页面索引获取页面
|
object page1 = GetPage(lastPageIndex);
|
if (page1 == null)
|
return;
|
if (page1 is CameraPage)
|
{
|
((CameraPage)page1).Unsubscribe();
|
((CameraPage)page1).StopContinueGrabbing();
|
}
|
}
|
|
//上一个节点是相机的话需要取消显示回调
|
if (lastPageIndex >= 3000 && lastPageIndex < 4000)
|
{
|
//根据页面索引获取页面
|
object page1 = GetPage(lastPageIndex);
|
if (page1 == null)
|
return;
|
if (page1 is ProcessPage)
|
{
|
((ProcessPage)page1).Unsubscribe();
|
}
|
}
|
|
//当前选择的节点是相机的话需要重新加载显示回调
|
if (pageIndex >= 2000 && pageIndex < 3000)
|
{
|
//根据页面索引获取页面
|
object page1 = GetPage(pageIndex);
|
if (page1 == null)
|
return;
|
if (page1 is CameraPage)
|
((CameraPage)page1).Subscribe();
|
}
|
lastPageIndex = pageIndex;
|
}
|
private void Form1_PageSelected(object sender, UIPageEventArgs e)
|
{
|
if (e.Page != null)
|
Console.WriteLine(e.Page.Text);
|
}
|
|
private void 关于ToolStripMenuItem1_Click(object sender, EventArgs e)
|
{
|
UIMessageBox.Show(Version, "关于", Style, UIMessageBoxButtons.OK, false);
|
}
|
|
private void 关于ToolStripMenuItem_Click(object sender, EventArgs e)
|
{
|
Process.Start("https://gitee.com/yhuse/SunnyUI");
|
}
|
|
private void Form1_HotKeyEventHandler(object sender, HotKeyEventArgs e)
|
{
|
if (e.hotKey.ModifierKey == Sunny.UI.ModifierKeys.Shift && e.hotKey.Key == Keys.F8)
|
{
|
this.ShowInfoTip("您按下了全局系统热键 Shift+F8");
|
}
|
}
|
|
private void Form1_ReceiveParams(object sender, UIPageParamsArgs e)
|
{
|
Text = e.Value.ToString();
|
SendParamToPage(1001, "传值给页面");
|
}
|
|
private void timer1_Tick(object sender, EventArgs e)
|
{
|
uiPanel3.Text = DateTime.Now.ToString();
|
}
|
|
private void timer60_Tick(object sender, EventArgs e)
|
{
|
bLogin = false;
|
}
|
|
private void NZhCN_Click(object sender, EventArgs e)
|
{
|
UIStyles.CultureInfo = CultureInfos.zh_CN;
|
}
|
|
private void NZhTW_Click(object sender, EventArgs e)
|
{
|
UIStyles.CultureInfo = CultureInfos.zh_TW;
|
}
|
|
private void NEnUS_Click(object sender, EventArgs e)
|
{
|
UIStyles.CultureInfo = CultureInfos.en_US;
|
}
|
|
/// <summary>
|
/// 重载多语翻译
|
/// </summary>
|
public override void Translate()
|
{
|
//必须保留
|
base.Translate();
|
//读取翻译代码中的多语资源
|
CodeTranslator.Load(this);
|
|
//设置多语资源
|
//this.CloseAskString = CodeTranslator.Current.CloseAskString;
|
//this.uiNavMenu1.Nodes[0].Text = this.uiNavBar1.Nodes[0].Text = CodeTranslator.Current.Controls;
|
//this.uiNavMenu1.Nodes[1].Text = this.uiNavBar1.Nodes[1].Text = CodeTranslator.Current.Forms;
|
//this.uiNavMenu1.Nodes[2].Text = this.uiNavBar1.Nodes[2].Text = CodeTranslator.Current.Charts;
|
//this.uiNavMenu1.Nodes[3].Text = this.uiNavBar1.Nodes[3].Text = CodeTranslator.Current.Industrial;
|
//this.uiNavBar1.Nodes[4].Text = CodeTranslator.Current.Theme;
|
//this.uiNavMenu1.Nodes[4].Text = CodeTranslator.Current.Symbols;
|
//this.uiNavMenu1.Nodes[5].Text = CodeTranslator.Current.Colorful;
|
|
this.uiNavBar1.Invalidate();
|
this.uiNavMenu1.Invalidate();
|
}
|
|
private class CodeTranslator : IniCodeTranslator<CodeTranslator>
|
{
|
public string CloseAskString { get; set; } = "您确认要退出程序吗?";
|
public string Controls { get; set; } = "相机";
|
public string Forms { get; set; } = "窗体";
|
public string Charts { get; set; } = "图表";
|
public string Industrial { get; set; } = "工控";
|
public string Theme { get; set; } = "主题";
|
public string Symbols { get; set; } = "字体图标";
|
public string Colorful { get; set; } = "多彩主题";
|
}
|
|
bool bLogin = false;
|
private void uiAvatar1_DoubleClick(object sender, EventArgs e)
|
{
|
LoginForm loginForm = new LoginForm();
|
loginForm.ShowDialog();
|
bLogin = loginForm.IsLogin;
|
}
|
|
private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
|
{
|
foreach (ICamera camera in dicCameras.Values)
|
{
|
camera.Dispose();
|
}
|
|
SaveAllCommunicator();
|
foreach (BaseCommunicator communicator in dicCommunicator.Values)
|
{
|
//communicator.Dispose();
|
communicator.Disconnect();
|
}
|
}
|
}
|
}
|