当前位置:   article > 正文

【C#】数字图像识别_c# 识别图片中数字

c# 识别图片中数字

这是一个用于训练BP神经网络完成数字识别任务的小程序,较为简单,可以在此基础上进行修改,完成常见的分类任务。

这个东西该怎么使用?

首先,有一点需要明确的是,这是一个训练神经网络的工具,当然,也可以实现识别,但是由于当时只是想在PC上训练一个BP神经网络,然后移植到单片机上,求出BP网络的权重文件才是该软件的目的所在,所以,就没在GUI上添加具体的识别操作的按钮。如果需要,可以参考test方法自己实现一下。

整个程序可以在这里下载到:C#实现BP神经网络数字图像识别源码,也可以在github上下载:BPNetwork

解压后会得到下面的目录,下面分别介绍一下:

  1. 测试样本:测试集,20*20的灰度图像,包含0~9;
  2. 训练样本:训练集,20*20的灰度图像,包含0~9;
  3. 训练成功后的矩阵:最终我个人训练的BP网络的权重矩阵;
  4. BPNetwork.exe:可执行程序;
  5. BPNetwork.rar:整个项目源码

具体原理:

  1. 将训练集和测试集中每一个20*20的图像拉伸为一个长度为400的数组;
  2. 利用train方法训练得到权重文件;
  3.  利用test方法测试所得到的BP神经网络的识别准确率。
  1. using System;
  2. using System.IO;
  3. using System.Text;
  4. namespace BPNetwork
  5. {
  6. /// <summary>
  7. /// BpNet 的摘要说明。
  8. /// </summary>
  9. public class BpNet
  10. {
  11. /// <summary>
  12. /// 输入节点数
  13. /// </summary>
  14. public int inNum;
  15. /// <summary>
  16. /// 隐层节点数
  17. /// </summary>
  18. int hideNum;
  19. /// <summary>
  20. /// 输出层节点数
  21. /// </summary>
  22. public int outNum;
  23. /// <summary>
  24. /// 样本总数
  25. /// </summary>
  26. public int sampleNum;
  27. Random R;
  28. /// <summary>
  29. /// 输入节点的输入(输出)数据
  30. /// </summary>
  31. double[] x;
  32. /// <summary>
  33. /// 隐层节点的输出
  34. /// </summary>
  35. double[] x1;
  36. /// <summary>
  37. /// 输出节点的输出
  38. /// </summary>
  39. double[] x2;
  40. /// <summary>
  41. /// 隐层的输入
  42. /// </summary>
  43. double[] o1;
  44. /// <summary>
  45. /// 输出层的输入
  46. /// </summary>
  47. double[] o2;
  48. /// <summary>
  49. /// 权值矩阵w
  50. /// </summary>
  51. public double[,] w;
  52. /// <summary>
  53. /// 权值矩阵V
  54. /// </summary>
  55. public double[,] v;
  56. /// <summary>
  57. /// 权值矩阵w
  58. /// </summary>
  59. public double[,] dw;
  60. /// <summary>
  61. /// 权值矩阵V
  62. /// </summary>
  63. public double[,] dv;
  64. /// <summary>
  65. /// 隐层阈值矩阵
  66. /// </summary>
  67. public double[] b1;
  68. /// <summary>
  69. /// 输出层阈值矩阵
  70. /// </summary>
  71. public double[] b2;
  72. /// <summary>
  73. /// 隐层阈值矩阵
  74. /// </summary>
  75. public double[] db1;
  76. /// <summary>
  77. /// 输出层阈值矩阵
  78. /// </summary>
  79. public double[] db2;
  80. /// <summary>
  81. /// 隐层的误差
  82. /// </summary>
  83. double[] pp;
  84. /// <summary>
  85. /// 输出层的误差
  86. /// </summary>
  87. double[] qq;
  88. /// <summary>
  89. /// 输出层的教师数据
  90. /// </summary>
  91. double[] yd;
  92. /// <summary>
  93. /// 均方误差
  94. /// </summary>
  95. public double e;
  96. /// <summary>
  97. /// 归一化比例系数
  98. /// </summary>
  99. double in_rate;
  100. /// <summary>
  101. /// 计算隐藏层节点数
  102. /// </summary>
  103. /// <param name="m">输入层节点数</param>
  104. /// <param name="n">输出层节点数</param>
  105. /// <returns></returns>
  106. public int computeHideNum(int m, int n)
  107. {
  108. double s = Math.Sqrt(0.43 * m * n + 0.12 * n * n + 2.54 * m + 0.77 * n + 0.35) + 0.51;
  109. int ss = Convert.ToInt32(s);
  110. return ((s - (double)ss) > 0.5) ? ss + 1 : ss;
  111. }
  112. /// <summary>
  113. /// 初始化神经网络
  114. /// </summary>
  115. /// <param name="innum">输入节点数</param>
  116. /// <param name="outnum">输出节点数</param>
  117. public BpNet(int innum, int outnum)
  118. {
  119. // 构造函数逻辑
  120. R = new Random();
  121. this.inNum = innum; //数组第二维大小 为 输入节点数
  122. this.outNum = outnum; //输出节点数
  123. this.hideNum = computeHideNum(inNum, outNum); //隐藏节点数
  124. x = new double[inNum];
  125. x1 = new double[hideNum];
  126. x2 = new double[outNum];
  127. o1 = new double[hideNum];
  128. o2 = new double[outNum];
  129. w = new double[inNum, hideNum];
  130. v = new double[hideNum, outNum];
  131. dw = new double[inNum, hideNum];
  132. dv = new double[hideNum, outNum];
  133. b1 = new double[hideNum];
  134. b2 = new double[outNum];
  135. db1 = new double[hideNum];
  136. db2 = new double[outNum];
  137. pp = new double[hideNum];
  138. qq = new double[outNum];
  139. yd = new double[outNum];
  140. //初始化w
  141. for (int i = 0; i < inNum; i++)
  142. {
  143. for (int j = 0; j < hideNum; j++)
  144. {
  145. w[i, j] = (R.NextDouble() * 2 - 1.0) / 2;
  146. }
  147. }
  148. //初始化v
  149. for (int i = 0; i < hideNum; i++)
  150. {
  151. for (int j = 0; j < outNum; j++)
  152. {
  153. v[i, j] = (R.NextDouble() * 2 - 1.0) / 2;
  154. }
  155. }
  156. e = 0.0;
  157. in_rate = 1.0;
  158. }
  159. /// <summary>
  160. /// 训练函数
  161. /// </summary>
  162. /// <param name="p">训练样本集合</param>
  163. /// <param name="t">训练样本结果集合</param>
  164. /// <param name="rate">学习率</param>
  165. public void train(double[,] p, double[,] t, double rate)
  166. {
  167. //获取样本数量
  168. this.sampleNum = p.GetLength(0);
  169. e = 0.0;
  170. //求p,t中的最大值
  171. double pMax = 0.0;
  172. for (int isamp = 0; isamp < sampleNum; isamp++)
  173. {
  174. for (int i = 0; i < inNum; i++)
  175. {
  176. if (Math.Abs(p[isamp, i]) > pMax)
  177. {
  178. pMax = Math.Abs(p[isamp, i]);
  179. }
  180. }
  181. for (int j = 0; j < outNum; j++)
  182. {
  183. if (Math.Abs(t[isamp, j]) > pMax)
  184. {
  185. pMax = Math.Abs(t[isamp, j]);
  186. }
  187. }
  188. in_rate = pMax;
  189. }
  190. for (int isamp = 0; isamp < sampleNum; isamp++)
  191. {
  192. //数据归一化
  193. for (int i = 0; i < inNum; i++)
  194. {
  195. x[i] = p[isamp, i] / in_rate;
  196. }
  197. for (int i = 0; i < outNum; i++)
  198. {
  199. yd[i] = t[isamp, i] / in_rate;
  200. }
  201. //计算隐层的输入和输出
  202. for (int j = 0; j < hideNum; j++)
  203. {
  204. o1[j] = 0.0;
  205. for (int i = 0; i < inNum; i++)
  206. {
  207. o1[j] += w[i, j] * x[i];
  208. }
  209. x1[j] = 1.0 / (1.0 + Math.Exp(-o1[j] - b1[j]));
  210. }
  211. //计算输出层的输入和输出
  212. for (int k = 0; k < outNum; k++)
  213. {
  214. o2[k] = 0.0;
  215. for (int j = 0; j < hideNum; j++)
  216. {
  217. o2[k] += v[j, k] * x1[j];
  218. }
  219. x2[k] = 1.0 / (1.0 + Math.Exp(-o2[k] - b2[k]));
  220. }
  221. //计算输出层误差和均方差
  222. for (int k = 0; k < outNum; k++)
  223. {
  224. qq[k] = (yd[k] - x2[k]) * x2[k] * (1.0 - x2[k]);
  225. e += (yd[k] - x2[k]) * (yd[k] - x2[k]);
  226. //更新V
  227. for (int j = 0; j < hideNum; j++)
  228. {
  229. v[j, k] += rate * qq[k] * x1[j];
  230. }
  231. }
  232. //计算隐层误差
  233. for (int j = 0; j < hideNum; j++)
  234. {
  235. pp[j] = 0.0;
  236. for (int k = 0; k < outNum; k++)
  237. {
  238. pp[j] += qq[k] * v[j, k];
  239. }
  240. pp[j] = pp[j] * x1[j] * (1 - x1[j]);
  241. //更新W
  242. for (int i = 0; i < inNum; i++)
  243. {
  244. w[i, j] += rate * pp[j] * x[i];
  245. }
  246. }
  247. //更新b2
  248. for (int k = 0; k < outNum; k++)
  249. {
  250. b2[k] += rate * qq[k];
  251. }
  252. //更新b1
  253. for (int j = 0; j < hideNum; j++)
  254. {
  255. b1[j] += rate * pp[j];
  256. }
  257. }
  258. e = Math.Sqrt(e);
  259. //adjustWV(w,dw);
  260. //adjustWV(v,dv);
  261. }
  262. /// <summary>
  263. /// 测试函数(单个数据测试)
  264. /// </summary>
  265. /// <param name="p">待测试样本</param>
  266. /// <returns>识别结果</returns>
  267. public int test(double[] p)
  268. {
  269. double[,] w = new double[inNum, hideNum];
  270. double[,] v = new double[hideNum, outNum];
  271. double[] b1 = new double[hideNum];
  272. double[] b2 = new double[outNum];
  273. //1.读取权值矩阵系数
  274. readMatrixW(w, "w.txt");
  275. readMatrixW(v, "v.txt");
  276. readMatrixB(b1, "b1.txt");
  277. readMatrixB(b2, "b2.txt");
  278. //2.数据归一化
  279. double pMax = 0.0;
  280. for (int i = 0; i < inNum; i++)
  281. {
  282. if (Math.Abs(p[i]) > pMax)
  283. {
  284. pMax = Math.Abs(p[i]);
  285. }
  286. }
  287. in_rate = pMax;//归一化系数
  288. for (int i = 0; i < inNum; i++)
  289. {
  290. x[i] = p[i] / in_rate;
  291. }
  292. //3.计算隐层的输入和输出
  293. for (int j = 0; j < hideNum; j++)
  294. {
  295. o1[j] = 0.0;
  296. for (int i = 0; i < inNum; i++)
  297. {
  298. o1[j] += w[i, j] * x[i];
  299. }
  300. x1[j] = 1.0 / (1.0 + Math.Exp(-o1[j] - b1[j]));
  301. }
  302. //4.计算输出层的输入和输出
  303. for (int k = 0; k < outNum; k++)
  304. {
  305. o2[k] = 0.0;
  306. for (int j = 0; j < hideNum; j++)
  307. {
  308. o2[k] += v[j, k] * x1[j];
  309. }
  310. x2[k] = 1.0 / (1.0 + Math.Exp(-o2[k] - b2[k]));
  311. }
  312. //5.判断是否正确
  313. double max = x2[0];
  314. int maxi = 0;
  315. for(int i = 0; i < outNum; i++)
  316. {
  317. if(x2[i] > max)
  318. {
  319. max = x2[i];
  320. maxi = i;
  321. }
  322. }
  323. return maxi;
  324. }
  325. public void adjustWV(double[,] w, double[,] dw)
  326. {
  327. for (int i = 0; i < w.GetLength(0); i++)
  328. {
  329. for (int j = 0; j < w.GetLength(1); j++)
  330. {
  331. w[i, j] += dw[i, j];
  332. }
  333. }
  334. }
  335. public void adjustWV(double[] w, double[] dw)
  336. {
  337. for (int i = 0; i < w.Length; i++)
  338. {
  339. w[i] += dw[i];
  340. }
  341. }
  342. /// <summary>
  343. /// 保存矩阵w,v
  344. /// </summary>
  345. /// <param name="w">要保存的矩阵</param>
  346. /// <param name="filename">文件名</param>
  347. public void saveMatrix(double[,] w, string filename)
  348. {
  349. StreamWriter sw = File.CreateText(filename);
  350. for (int i = 0; i < w.GetLength(1); i++)
  351. {
  352. for (int j = 0; j < w.GetLength(0); j++)
  353. {
  354. sw.Write(w[j, i].ToString("0.000000000000000") + " ");
  355. }
  356. sw.WriteLine();
  357. }
  358. sw.Close();
  359. }
  360. /// <summary>
  361. /// 保存矩阵b1,b2
  362. /// </summary>
  363. /// <param name="b">要保存的阀值矩阵</param>
  364. /// <param name="filename">文件名</param>
  365. public void saveMatrix(double[] b, string filename)
  366. {
  367. StreamWriter sw = File.CreateText(filename);
  368. for (int i = 0; i < b.Length; i++)
  369. {
  370. sw.Write(b[i] + " ");
  371. }
  372. sw.Close();
  373. }
  374. /// <summary>
  375. /// 读取矩阵W,V
  376. /// </summary>
  377. /// <param name="w">要读取到的那个矩阵</param>
  378. /// <param name="filename">文件所在位置</param>
  379. public void readMatrixW(double[,] w, string filename)
  380. {
  381. StreamReader sr;
  382. try
  383. {
  384. sr = new StreamReader(filename, Encoding.GetEncoding("gb2312"));
  385. String line;
  386. int i = 0;
  387. while ((line = sr.ReadLine()) != null)
  388. {
  389. string[] s1 = line.Trim().Split(' ');
  390. for (int j = 0; j < s1.Length; j++)
  391. {
  392. w[j, i] = Convert.ToDouble(s1[j]);
  393. }
  394. i++;
  395. }
  396. sr.Close();
  397. }
  398. catch (Exception e)
  399. {
  400. Console.WriteLine("The file could not be read:");
  401. Console.WriteLine(e.Message);
  402. }
  403. }
  404. /// <summary>
  405. /// 读取矩阵b1,b2
  406. /// </summary>
  407. /// <param name="b">要读取的阀值矩阵</param>
  408. /// <param name="filename">文件所在位置</param>
  409. public void readMatrixB(double[] b, string filename)
  410. {
  411. StreamReader sr;
  412. try
  413. {
  414. sr = new StreamReader(filename, Encoding.GetEncoding("gb2312"));
  415. String line;
  416. if ((line = sr.ReadLine()) != null)
  417. {
  418. string[] strs = line.Trim().Split(' ');
  419. for (int i = 0; i < strs.Length; i++)
  420. {
  421. b[i] = Convert.ToDouble(strs[i]);
  422. }
  423. }
  424. sr.Close();
  425. }
  426. catch (Exception e)
  427. {
  428. Console.WriteLine("The file could not be read:");
  429. Console.WriteLine(e.Message);
  430. }
  431. }
  432. }
  433. }
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Drawing.Imaging;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Text;
  10. using System.Threading.Tasks;
  11. using System.Windows.Forms;
  12. namespace BPNetwork
  13. {
  14. public partial class MainFrm : Form
  15. {
  16. public MainFrm()
  17. {
  18. InitializeComponent();
  19. this.btnTest.Enabled = false;
  20. this.btnTrain.Enabled = false;
  21. this.txtLearnRate.Text = 0.3.ToString();
  22. //窗口固定大小
  23. this.MaximizeBox = false;//最大化按钮隐藏
  24. this.MinimizeBox = false;//最小化按钮隐藏
  25. this.FormBorderStyle = FormBorderStyle.FixedSingle;//不支持鼠标拖动
  26. this.lblMessage.Text = "请先载入测试或训练样本";
  27. }
  28. /// <summary>
  29. /// 训练按钮是否已经点击过一次
  30. /// </summary>
  31. private static int flag = 0;
  32. /// <summary>
  33. /// 训练文件是否已打开
  34. /// </summary>
  35. private static int flag2 = 0;
  36. /// <summary>
  37. /// 测试文件是否已打开
  38. /// </summary>
  39. private static int flag3 = 0;
  40. private BackgroundWorker bw;
  41. private void btnTrain_Click(object sender, EventArgs e)
  42. {
  43. if (flag2 != 0)//测试文件和训练文件都已经选中
  44. {
  45. if (flag == 0)
  46. {
  47. bw = new BackgroundWorker();
  48. bw.DoWork += Bw_DoWork;
  49. bw.RunWorkerCompleted += Bw_RunWorkerCompleted;
  50. bw.WorkerSupportsCancellation = true;//1.支持取消操作
  51. bw.RunWorkerAsync();
  52. this.btnTrain.Text = "停止";
  53. flag = 1;
  54. }
  55. else
  56. {
  57. this.btnTrain.Text = "训练";
  58. bw.CancelAsync();
  59. flag = 0;
  60. }
  61. }
  62. else
  63. {
  64. MessageBox.Show("请点击文件,选择要训练文件所在的目录!", "文件未载入");
  65. flag2 = 0;
  66. }
  67. }
  68. private void Bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
  69. {
  70. this.Show();//隐藏窗体
  71. MessageBox.Show("训练成功", "提示");
  72. this.btnTrain.Text = "训练";
  73. flag = 0;
  74. }
  75. /// <summary>
  76. /// 训练样本的目录
  77. /// </summary>
  78. private static string train_path;
  79. /// <summary>
  80. /// 测试样本的目录
  81. /// </summary>
  82. private static string test_path;
  83. private void Bw_DoWork(object sender, DoWorkEventArgs e)
  84. {
  85. //定义BP神经网络类
  86. BpNet bp = new BpNet(400, 10);
  87. double[] tmp = new double[20];
  88. try
  89. {
  90. //学习率
  91. double lr = Double.Parse(this.txtLearnRate.Text.Trim());
  92. int count = 0;//计数器
  93. int study = 0;//学习(训练)次数
  94. //数据字典
  95. Dictionary<string, int> filedictionary = new Dictionary<string, int>();
  96. for (int i = 0; i < 10; i++)
  97. {
  98. string dir = train_path + @"\" + i + @"\";
  99. string[] files = Directory.GetFiles(dir);
  100. foreach (string item in files)
  101. {
  102. filedictionary.Add(item, i);
  103. }
  104. }
  105. //声明数据存储区域
  106. double[,] input = new double[filedictionary.Count, 400];
  107. double[,] output = new double[filedictionary.Count, 10];
  108. //数据装载
  109. foreach (KeyValuePair<string, int> item in filedictionary)
  110. {
  111. Bitmap bmp = new Bitmap(item.Key);
  112. for (int k = 0; k < bmp.Height; k++)
  113. {
  114. for (int l = 0; l < bmp.Width; l++)
  115. {
  116. input[count, k * bmp.Width + l] = bmp.GetPixel(l, k).R;
  117. }
  118. }
  119. //交换行,因为位图存储时,先存储最后一行,从图片的底部开始,逐渐向上扫描
  120. for (int k = 0; k < bmp.Height / 2; k++)
  121. {
  122. for (int l = 0; l < bmp.Width; l++)
  123. {
  124. tmp[l] = input[count, k * bmp.Width + l];
  125. input[count, k * bmp.Width + l] = input[count, (bmp.Height - 1 - k) * bmp.Width + l];
  126. input[count, (bmp.Height - 1 - k) * bmp.Width + l] = tmp[l];
  127. }
  128. }
  129. output[count, item.Value] = 1;//第j个图片被分为第i类
  130. count++;
  131. }
  132. do
  133. {
  134. if (!bw.CancellationPending)//2.检测用户是否取消
  135. {
  136. //训练
  137. bp.train(input, output, lr);
  138. study++;
  139. this.lblMessage.Text = "第" + study + "次训练的误差: " + bp.e;
  140. }
  141. else
  142. {
  143. break;//停止训练
  144. }
  145. } while (bp.e > 0.01 && study < 50000);
  146. }
  147. catch (Exception ex)
  148. {
  149. MessageBox.Show("出错了" + ex.Message);
  150. }
  151. finally//出错或者中途取消也会保存权值矩阵的信息
  152. {
  153. bp.saveMatrix(bp.w, "w.txt");
  154. bp.saveMatrix(bp.v, "v.txt");
  155. bp.saveMatrix(bp.b1, "b1.txt");
  156. bp.saveMatrix(bp.b2, "b2.txt");
  157. this.lblMessage.Text = "训练终止!";
  158. }
  159. }
  160. private void btnTest_Click(object sender, EventArgs e)
  161. {
  162. if (flag3 != 0 && File.Exists("w.txt") && File.Exists("v.txt") && File.Exists("b1.txt") && File.Exists("b2.txt"))
  163. {
  164. //清空已有训练结果
  165. this.lbTestResult.Items.Clear();
  166. BackgroundWorker bw1 = new BackgroundWorker();
  167. bw1.DoWork += Bw1_DoWork;
  168. bw1.RunWorkerAsync();
  169. flag3 = 1;
  170. }
  171. else
  172. {
  173. MessageBox.Show("请点击文件,选择要测试文件所在的目录!", "文件未载入");
  174. flag3 = 0;
  175. }
  176. }
  177. private void Bw1_DoWork(object sender, DoWorkEventArgs e)
  178. {
  179. try
  180. {
  181. //定义BP神经网络类
  182. BpNet bp = new BpNet(400, 10);
  183. int right_count = 0;
  184. string[] files;
  185. double[] tmp = new double[20];
  186. //读取文件
  187. for (int i = 0; i < 10; i++)
  188. {
  189. right_count = 0;
  190. string dir = test_path + @"\" + i + @"\";
  191. files = Directory.GetFiles(dir);
  192. //共files.Length个样本,每个样本数据有400个字节
  193. double[] input = new double[400];
  194. double[] output = new double[10];
  195. for (int j = 0; j < files.Length; j++)
  196. {
  197. Bitmap bmp = new Bitmap(files[j]);
  198. for (int k = 0; k < bmp.Height; k++)
  199. {
  200. for (int l = 0; l < bmp.Width; l++)
  201. {
  202. input[k * bmp.Width + l] = bmp.GetPixel(l, k).R;
  203. }
  204. }
  205. //交换行,因为位图存储时,先存储最后一行,从图片的底部开始,逐渐向上扫描
  206. for (int k = 0; k < bmp.Height / 2; k++)
  207. {
  208. for (int l = 0; l < bmp.Width; l++)
  209. {
  210. tmp[l] = input[k * bmp.Width + l];
  211. input[k * bmp.Width + l] = input[(bmp.Height - 1 - k) * bmp.Width + l];
  212. input[(bmp.Height - 1 - k) * bmp.Width + l] = tmp[l];
  213. }
  214. }
  215. if (i == bp.test(input))
  216. {
  217. right_count++;
  218. }
  219. }
  220. this.lbTestResult.Items.Add(files.Length + "个" + i + "样本识别成功率:" + (1.0 * right_count / files.Length * 100).ToString("0.00") + "%");
  221. }
  222. this.lblMessage.Text = "测试成功!";
  223. }
  224. catch (Exception ex)
  225. {
  226. MessageBox.Show("出错了" + ex.Message);
  227. }
  228. }
  229. private void menuOpenTrain_Click(object sender, EventArgs e)
  230. {
  231. FolderBrowserDialog path = new FolderBrowserDialog();
  232. path.ShowDialog();
  233. train_path = path.SelectedPath;
  234. flag2 = 1;
  235. this.btnTrain.Enabled = true;
  236. this.lblMessage.Text = "训练样本载入成功";
  237. }
  238. private void menuOpenTest_Click(object sender, EventArgs e)
  239. {
  240. FolderBrowserDialog path = new FolderBrowserDialog();
  241. path.ShowDialog();
  242. test_path = path.SelectedPath;
  243. flag3 = 1;
  244. this.btnTest.Enabled = true;
  245. this.lblMessage.Text = "测试样本载入成功";
  246. }
  247. private static int flag1 = 0;
  248. private void menuStay_Click(object sender, EventArgs e)
  249. {
  250. if (flag1 == 0)
  251. {
  252. //窗口置顶
  253. this.TopMost = true;
  254. this.menuStay.Text = "取消窗口保持在前";
  255. flag1 = 1;
  256. }
  257. else
  258. {
  259. //取消窗口置顶
  260. this.TopMost = false;
  261. this.menuStay.Text = "窗口保持在前";
  262. flag1 = 0;
  263. }
  264. }
  265. private void menuRunBackground_Click(object sender, EventArgs e)
  266. {
  267. this.Hide();//隐藏窗体
  268. }
  269. }
  270. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/347142
推荐阅读
相关标签
  

闽ICP备14008679号