c#是微软提供的用于开发windows软件的开发语言,可以使用其快速的实现windows桌面软件的开发。这里基于C#开发了一款简单的绘图软件,可以用于绘制矩形、多边形的绘制(基于这些可以实现自己的数据标注软件),还实现了画笔、橡皮擦功能。开发C#软件通常使用Visual Studio软件开发,这里使用的是vs2019。

1、基本概念

使用c#实现绘图软件需要了解c#桌面软件所具备的控件(如按钮、文本框、进度条、下拉列表、图片显示控件等)和各种相关事件(如鼠标按下、鼠标拖动、控件点击、控件重绘等事件)。

1.1 相关桌面控件介绍

开发绘图软件需要用到的桌面控件有:按钮(Button)、文本框(Label)、下拉列表(ComboBox)、进度条(trackBar)、图片显示控件(PictureBox)等。博主使用以上控件实现了下图的操作界面,这里需要补充的是博主使用button来显示颜色(设置button的文本为空,然后修改了它的颜色),如果点击该按钮则会弹出颜色选择框。

除了上述的控件外,还有一些对话框,如颜色对话框(用于选择颜色),文件选择框(用于选择文件)。

创建颜色对话框

ColorDialog cl = new ColorDialog();if (cl.ShowDialog() == System.Windows.Forms.DialogResult.OK){fill_color = Color.FromArgb(cl.Color.A, cl.Color.R, cl.Color.G, cl.Color.B);btn_color.BackColor = fill_color;fill_brush = new SolidBrush(fill_color);line_color = new Pen(fill_brush);}

创建文件选择框

    OpenFileDialog ofd = new OpenFileDialog();ofd.Title = "请选择图片";ofd.Filter = "所有文件|*.*";ofd.InitialDirectory = @"C:\Users";ofd.Multiselect = false;if (ofd.ShowDialog() == DialogResult.OK){string image_path = ofd.FileName;bg_image = Image.FromFile(image_path);bg_image = ImgUtils.resizeImg(bg_image, pictureBox1.Width, pictureBox1.Height);//tmp_bitmap.Save("finish.bmp");pictureBox1.Image = bg_image;}

1.2 桌面控件相关事件

通过监听桌面控件的相关事件可以执行相应的代码流程,如点击打开文件,则弹出文件选择框,点击设置颜色则弹出颜色选择框,拖动进度条则改变画笔和橡皮擦的大小等等。

button点击事件

button通常是设置点击事件(Click事件),在软件设计界面双击特定按钮即可转到其点击事件的编辑代码。

上图中“载入底图”按钮是用于选择图片,并加载到绘图框中,因此实现代码如下:

private void btn_load_bg_Click(object sender, EventArgs e)
{OpenFileDialog ofd = new OpenFileDialog();ofd.Title = "请选择图片";ofd.Filter = "所有文件|*.*";ofd.InitialDirectory = @"C:\Users";ofd.Multiselect = false;if (ofd.ShowDialog() == DialogResult.OK){string image_path = ofd.FileName;bg_image = Image.FromFile(image_path);bg_image = ImgUtils.resizeImg(bg_image, pictureBox1.Width, pictureBox1.Height);//tmp_bitmap.Save("finish.bmp");pictureBox1.Image = bg_image;}
}

ComboBox选项切换事件

ComboBox选项切换事件也就是SelectedIndexChanged事件,设置这个事件需要先选择空间,然后点击图中标号为2的雷电符号(设置控件属性),找到SelectedIndexChanged然后在其空白处(图中绿色框处)双击,即可进入设置SelectedIndexChanged事件(获取ComboBox所选中的文本,然后修改相关变量);。

设置ComboBox的可选项需要先选中控件,然后单击右键,弹出选择框,接着点击“编辑项”,即可进入以下界面。这里博主设置了5个选项,分别为:矩形(填充)、矩形、多边形(填充)、多边形、画笔。

TrackBar的拖动事件

trackBar的拖动事件也就是Scroll事件,依照下图所点击的顺序,找到Scroll双击即可设置拖动事件(获取trackBar表示的数值,然后修改相关变量);

1.3 桌面控件通用事件

除了博主在上面描述的控件专用事件,针对桌面控件还有一些通用事件,如:鼠标按下(MouseDown)、鼠标移动(MouseMove)、鼠标松开(MouseUp)、控件重绘(Paint)等。在这里开发绘图软件,主要监听pictureBox的鼠标按下、鼠标移动、鼠标松开、控件重绘事件,设置这些事件同样需要在设计界面选择空间然后找到对应的事件进行双击。

其中,鼠标按下、鼠标移动、鼠标松开等事件,还可以是函数内部获取鼠标的位置、鼠标按下的按钮(鼠标左键或鼠标右键)。因为,不同的按钮按下可以不同的事件需求;此外,通过这些事件的组合,可以完成一下复杂的操作,如拖动(鼠标按下时设置press=true,鼠标移动且press=true既为拖动,鼠标松开时设置press=false);

这里有一个不一样的就是控件重绘事件,控件重绘事件无法被用户激发,只能被代码激活,如pictureBox1的重绘事件需要显性的调用pictureBox1.Invalidate()才能激发。这主要用户鼠标位置的绘制,同样也可以绘制特定形状是鼠标拖动过程中的参考线。

2、软件实现

2.1 软件布局

软件的界面设置如下所示,通过下拉框选择绘图功能,通过颜色按钮选择要绘图的颜色,通过拖动条设置橡皮擦和画笔的大小。

上面控件的定义代码如下所示

this.btn_load_bg = new System.Windows.Forms.Button();
this.btn_eraser = new System.Windows.Forms.Button();
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.comboBox1 = new System.Windows.Forms.ComboBox();
this.label1 = new System.Windows.Forms.Label();
this.btn_color = new System.Windows.Forms.Button();
this.trackBar1 = new System.Windows.Forms.TrackBar();//定义拖动条
this.label2 = new System.Windows.Forms.Label();
this.lab_line_width = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();

2.2 变量定义

这里定义了一些绘图颜色、线宽相关的变量

private int line_width = 10;//划线的宽度设置为10
private Color fill_color = Color.Black;//绘图区域的背景颜色
private SolidBrush fill_brush = new SolidBrush(Color.Black);
private Pen line_color = new Pen(new SolidBrush(Color.Black));
private SolidBrush eraser_brush = new SolidBrush(Color.Transparent);//橡皮擦颜色

这里定义了一些绘图过程需要的变量

private Graphics draw_paint, merge_paint;//中间画板
private Image tmp_bitmap;//用来保存绘图痕迹List<Point> polyPoints = null;//存储绘制多边形的点集
Rectangle rectA;//存储要用于绘图的矩形
Image bg_image;//背景图片
Point start;  //起始点
Point end;   //结束点

这里定义了一些绘图判别相关的变量

bool need_draw_tmp;   //在MouseMove事件中判断是否绘制矩形框
string action_type = "";//绘图动作类型
bool is_first_down = true;//判断是否第一次按下鼠标
bool press_move_flag = true;

2.3 事件绑定

完整的变量定义和事件绑定代码如下所示,其核心在于区分开pictureBox的鼠标按下(MouseDown)、鼠标移动(MouseMove)、鼠标松开(MouseUp)、控件重绘(Paint)事件在不同的绘图动作类型(action_type )的实现代码。所以,代码中if用的比较多。其中控件重绘(Paint)事件在绘制矩形、多边形时用于绘制对应的参考线,在画笔和橡皮擦功能时用于绘制鼠标对应的点。

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Windows.Forms;namespace 绘画识别
{public partial class Form1 : Form{private int line_width = 10;//划线的宽度设置为10private Color fill_color = Color.Black;//绘图区域的背景颜色private SolidBrush fill_brush = new SolidBrush(Color.Black);private Pen line_color = new Pen(new SolidBrush(Color.Black));private SolidBrush eraser_brush = new SolidBrush(Color.Transparent);//橡皮擦颜色private Graphics draw_paint, merge_paint;//中间画板private Image tmp_bitmap;//用来保存绘图痕迹List<Point> polyPoints = null;//存储绘制多边形的点集Rectangle rectA;//存储要用于绘图的矩形Image bg_image;//背景图片Point start;  //起始点Point end;   //结束点bool need_draw_tmp;   //在MouseMove事件中判断是否绘制矩形框string action_type = "";//绘图动作类型bool is_first_down = true;//判断是否第一次按下鼠标bool press_move_flag = false;public Form1(){InitializeComponent();comboBox1.SelectedIndex = 0;action_type = "矩形(填充)";bg_image = new Bitmap(pictureBox1.Width, pictureBox1.Height);//中间画布tmp_bitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height);//创建空白画板draw_paint = Graphics.FromImage(tmp_bitmap);}private void btn_load_bg_Click(object sender, EventArgs e){OpenFileDialog ofd = new OpenFileDialog();ofd.Title = "请选择图片";ofd.Filter = "所有文件|*.*";ofd.InitialDirectory = @"C:\Users";ofd.Multiselect = false;if (ofd.ShowDialog() == DialogResult.OK){string image_path = ofd.FileName;bg_image = Image.FromFile(image_path);bg_image = ImgUtils.resizeImg(bg_image, pictureBox1.Width, pictureBox1.Height);//tmp_bitmap.Save("finish.bmp");pictureBox1.Image = bg_image;}}private void draw_ploy(bool fill = true){//绘制矩形框 并填充//抗锯齿draw_paint.SmoothingMode = SmoothingMode.HighQuality;//填充多边形if (fill){draw_paint.FillPolygon(fill_brush, polyPoints.ToArray());}else{draw_paint.DrawPolygon(line_color, polyPoints.ToArray());}pictureBox1.Image = get_merge_bitmap();is_first_down = true;need_draw_tmp = false;polyPoints = null;}private void pictureBox1_MouseDown(object sender, MouseEventArgs e){if (action_type.IndexOf("矩形") >= 0){if (e.Button == MouseButtons.Left){start = e.Location;need_draw_tmp = true;}}else if (action_type.IndexOf("多边形") >= 0){Graphics g = pictureBox1.CreateGraphics();//绘制多边形  low版本if (is_first_down)  //首先第一次创建两个点如下(e.X, e.Y),( e.X + 1, e.Y + 1){//first point downif (e.Button == MouseButtons.Left){is_first_down = false;if (polyPoints == null) polyPoints = new List<Point>();polyPoints.Add(e.Location);//Point point = new Point(e.X + 1, e.Y + 1);//polyPoints.Add(point);need_draw_tmp = true;}}else{//add new pointif (e.Button == MouseButtons.Left){//添加新的点Point point = new Point(e.X, e.Y);polyPoints.Add(point);}else if (e.Button == MouseButtons.Right){//把当前的点填充到顶点集合中去  方便填充polyPoints.Add(e.Location);draw_ploy(action_type.IndexOf("填充") >= 0);}}}else if (action_type.IndexOf("画笔") >= 0){if (e.Button == MouseButtons.Left){press_move_flag = true;}}else if (action_type.IndexOf("橡皮擦") >= 0){if (e.Button == MouseButtons.Left){press_move_flag = true;start = e.Location;//模式转换为'CompositingMode.SourceCopy'draw_paint.CompositingMode = CompositingMode.SourceCopy;//用透明色替换指定的区域draw_paint.FillEllipse(eraser_brush, e.X - line_width / 2, e.Y - line_width / 2, line_width, line_width);//模式转换为'CompositingMode.SourceOver',这样后面可以进行绘图//draw_paint.CompositingMode = CompositingMode.SourceOver;}}end = e.Location;pictureBox1.Invalidate();}private void pictureBox1_MouseMove(object sender, MouseEventArgs e){if (action_type.IndexOf("矩形") >= 0){//绘制矩形框 并填充if (need_draw_tmp){if (e.Button != MouseButtons.Left) return;end = e.Location;pictureBox1.Invalidate();}}else if (action_type.IndexOf("多边形") >= 0){//绘制多边形if (need_draw_tmp){//if (e.Button != MouseButtons.Left) return;end = e.Location;pictureBox1.Invalidate();//此代码不可省略//Graphics g = pictureBox1.CreateGraphics();//抗锯齿}}else if (action_type.IndexOf("画笔") >= 0 ){if (press_move_flag == true && e.Button == MouseButtons.Left){end = e.Location;draw_paint.FillEllipse(fill_brush, e.X - line_width / 2, e.Y - line_width / 2, line_width, line_width);//画点(鼠标位置示意图)Graphics g = pictureBox1.CreateGraphics();g.FillEllipse(Brushes.Blue, e.X - line_width / 2, e.Y - line_width / 2, line_width, line_width);pictureBox1.Image = get_merge_bitmap();pictureBox1.Invalidate();//此代码不可省略}}else if (action_type.IndexOf("橡皮擦") >= 0){if (press_move_flag == true && e.Button == MouseButtons.Left){end = e.Location;//用透明色替换指定的区域draw_paint.FillEllipse(eraser_brush, e.X - line_width / 2, e.Y - line_width / 2, line_width, line_width);pictureBox1.Image = get_merge_bitmap();pictureBox1.Invalidate();//此代码不可省略Refresh();}}}private Bitmap get_merge_bitmap(){Bitmap tmp_bmp = (Bitmap)bg_image.Clone();merge_paint = Graphics.FromImage(tmp_bmp);merge_paint.DrawImage(tmp_bitmap, 0, 0);//将中间画布绘制的内容绘制到原始画布上merge_paint.Dispose();return tmp_bmp;}private void pictureBox1_MouseUp(object sender, MouseEventArgs e){if (action_type.IndexOf("矩形") >= 0){//绘制矩形框 并填充if (e.Button == MouseButtons.Left){end = e.Location;need_draw_tmp = false;}Graphics g = pictureBox1.CreateGraphics();if (action_type.IndexOf("填充") >= 0){draw_paint.FillRectangle(fill_brush, rectA);//填充颜色}else{draw_paint.DrawRectangle(line_color, rectA);//填充颜色}//g.DrawImage(img, 0, 0);//在目标绘图板上绘制图片pictureBox1.Image = get_merge_bitmap();g.Dispose();}else if (action_type.IndexOf("画笔") >= 0){press_move_flag = false;pictureBox1.Invalidate();//此代码不可省略}else if (action_type.IndexOf("橡皮擦") >= 0){//模式转换为'CompositingMode.SourceOver',这样后面可以进行绘图draw_paint.CompositingMode = CompositingMode.SourceOver;press_move_flag = false;pictureBox1.Invalidate();//此代码不可省略}}private void pictureBox1_Paint(object sender, PaintEventArgs e){PictureBox pic = sender as PictureBox;if (action_type.IndexOf("矩形") >= 0){//绘制矩形框 并填充Pen pen = new Pen(Color.Red, 3);pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;     //绘制线的格式//绘制矩形框 并填充if (need_draw_tmp){//此处是为了在绘制时可以由上向下绘制,也可以由下向上rectA = new Rectangle(Math.Min(start.X, end.X), Math.Min(start.Y, end.Y), Math.Abs(start.X - end.X), Math.Abs(start.Y - end.Y));e.Graphics.DrawRectangle(pen, rectA);}pen.Dispose();}else if (action_type.IndexOf("多边形") >= 0){//多边形if (polyPoints != null){if (need_draw_tmp){//抗锯齿e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;e.Graphics.DrawLine(Pens.Yellow, polyPoints.First(), end);e.Graphics.DrawLine(Pens.Red, polyPoints.Last(), end);if (polyPoints.Count > 1){for (int i = 0; i < polyPoints.Count - 1; i++){e.Graphics.DrawLine(Pens.Yellow, polyPoints[i], polyPoints[i + 1]);}}}}}else if (action_type.IndexOf("画笔") >= 00){if (press_move_flag){e.Graphics.FillEllipse(Brushes.Blue, end.X - (line_width / 2), end.Y - (line_width / 2), line_width, line_width);}}else if (action_type.IndexOf("橡皮擦") >= 0){if (press_move_flag){e.Graphics.FillEllipse(Brushes.Blue, end.X - (line_width / 2), end.Y - (line_width / 2), line_width, line_width);}}}private void comboBox1_SelectedIndexChanged(object sender, EventArgs e){action_type = comboBox1.Text;Console.WriteLine(comboBox1.Text);}private void btn_color_Click(object sender, EventArgs e){//选择颜色 进行填充ColorDialog cl = new ColorDialog();if (cl.ShowDialog() == System.Windows.Forms.DialogResult.OK){fill_color = Color.FromArgb(cl.Color.A, cl.Color.R, cl.Color.G, cl.Color.B);btn_color.BackColor = fill_color;fill_brush = new SolidBrush(fill_color);line_color = new Pen(fill_brush);}}private void trackBar1_Scroll(object sender, EventArgs e){line_width = trackBar1.Value;lab_line_width.Text = Convert.ToString(line_width);}private void btn_eraser_Click(object sender, EventArgs e){action_type = "橡皮擦";}}
}

3、软件使用

3.1 绘制矩形

绘制矩形时有两种选择,填充和不填充。每一次绘制前可以先选择颜色。

3.2 绘制多边形

绘制矩形时有两种选择,填充和不填充。每一次绘制前可以先选择颜色。

3.3 使用画笔

使用画笔前可以先拖动进度条设置画笔大小,然后再设置颜色

3.4 使用橡皮擦

点击橡皮擦即可使用橡皮擦功能,点击绘图框中的其他按钮即可退出橡皮擦选择其他绘图功能。使用橡皮擦前可以先拖动进度条设置橡皮擦的大小。

4、补充代码

上面代码中进行图像resize的时候用到了以下工具代码,可以保存为ImgUtils.cs。

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace 绘画识别
{class ImgUtils{private static char[] base64CodeArray = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z','a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z','0', '1', '2', '3', '4',  '5', '6', '7', '8', '9', '+', '/', '='};public static bool IsBase64(string base64Str){//string strRegex = "^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$";if (string.IsNullOrEmpty(base64Str))return false;else{if (base64Str.Contains(","))base64Str = base64Str.Split(',')[1];if (base64Str.Length % 4 != 0)return false;if (base64Str.Any(c => !base64CodeArray.Contains(c)))return false;}try{return true;}catch (FormatException){return false;}}public static string ConvertImageToBase64(Image bmp){try{MemoryStream ms = new MemoryStream();bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);byte[] arr = new byte[ms.Length]; ms.Position = 0;ms.Read(arr, 0, (int)ms.Length); ms.Close();return Convert.ToBase64String(arr);}catch (Exception ex){return "转换错误";}}public static Image ConvertBase64ToImage(string base64String){try{byte[] imageBytes = Convert.FromBase64String(base64String);using (MemoryStream ms = new MemoryStream(imageBytes, 0, imageBytes.Length)){ms.Write(imageBytes, 0, imageBytes.Length);return Image.FromStream(ms, true);}}catch (Exception ex){return null;}}public static Image resizeImg(Image sourceImage, int targetWidth, int targetHeight){int width;//图片最终的宽int height;//图片最终的高try{//获取图片宽度int sourceWidth = sourceImage.Width;//获取图片高度int sourceHeight = sourceImage.Height;System.Drawing.Imaging.ImageFormat format = sourceImage.RawFormat;Bitmap targetPicture = new Bitmap(targetWidth, targetHeight);Graphics g = Graphics.FromImage(targetPicture);g.Clear(Color.White);g.DrawImage(sourceImage, 0, 0, targetWidth, targetHeight);sourceImage.Dispose();return targetPicture;}catch (Exception ex){}return null;}}}

使用c#实现一个简单绘图软件(绘制矩形、多边形,画笔、橡皮擦功能)的完整教程相关推荐

  1. Java制作一个盒子程序_编写一个简单的Java程序,模拟计算器的功能。

    提问:编写一个简单的Java程序,模拟计算器的功能. 网友回答: 程序参考: import java.awt.*; import java.awt.event.ActionEvent; import ...

  2. 简单绘图软件实现mfc大作业_生产流程图怎么做?简单易上手的流程图工具

    生产流程图是什么呢?首先,生产流程指的是在生产的过程中,劳动者通过利用一定的生产设备或工具,将各种原材料.半成品投入,按照一定顺序进行加工,最终得到成品产出的整个过程.而生产流程图则是使用图表符号的形 ...

  3. 用计算机绘图软件绘制的工程图是图形,用AutoCAD快速绘制机械工程图实用的经验.doc...

    用AutoCAD快速绘制机械工程图实用的经验 用AutoCAD快速绘制机械工程图实用的经验 摘要利用AutoCAD软件绘制机械工程图对所有了解计算机绘图的人员都不是难事,但要达到快速绘制机械工程图的目 ...

  4. 移花接木—做一个简单的软件渲染器

    移花接木-根据PBRT魔改出自己的软件渲染器 本文包含以下你可能感兴趣的内容: 门外汉是如何学习computer graphic领域的 从模仿到实践:PBRT给我带来了什么? 如何自编一个软件渲染管线 ...

  5. 用Origin绘图软件绘制图表-用theme

    用Origin绘图软件制作普通图的流程: 1)打开Origin软件,在工具栏上点击New Execl,这样会在软件窗口打开excel 表格: 2)将需要绘制图表的数据拷贝到该excel表格中,并选中数 ...

  6. 使用SpringBoot一小时快速搭建一个简单后台管理(增删改查)(超详细教程)

    最近也是临近期末了,各种的期末大作业,后台管理也是很多地方需要用到的,为了方便大家能快速上手,快速搭建一个简单的后台管理,我花了两天时间整理了一下 我会从0开始介绍,从数据库的设计到前端页面的引入最后 ...

  7. ad如何绘制拼版_Altium Design PCB拼板完整教程,这样讲就明白了!

    原标题:Altium Design PCB拼板完整教程,这样讲就明白了! 一.为什么拼板 电路板设计完以后需要上SMT贴片流水线贴上元器件,每个SMT的加工工厂都会根据流水线的加工要求,规定电路板的最 ...

  8. 简单绘图软件实现mfc大作业_纸笔书写|可直播可微课可写作业可批改的手写板,快来爱“我”吧...

    线上教学进入下半场,我们需要什么? 走过线上教育的探索期,相信不少老师已经对线上教学驾轻就熟了,但对于线上教学来说,合适的教学支持工具始终是必不可少的.不论是文科教师,还是理科教师,对于真实纸笔书写都 ...

  9. Java实现的一个简单聊天软件

    介绍 这是我自己学习Socket时写的,用到了多线程,Socket的知识,还有Java的IO技术,并且做了一个Java的UI,废话不多说,先上效果图 SendThread 这个类是用来实现数据的发送的 ...

  10. 一个简单的软件需求规划书模版

    需求规格说明书 1引言 1.1编写目的 1.2背景 1.3字符定义 1.4参考资料 2任务概述 2.1目标 2.2用户特点 2.3假定和约束 3总体设计 3.1需求规定 3.2基本设计概念和处理流程 ...

最新文章

  1. 监控摄像头cad图例_一套实用的智能化弱电系统大样图,可以作为弱电项目CAD设计素材...
  2. vc获取n卡编号_电脑入门知识:通过显卡型号中字母和数字判断显卡性能
  3. Vue-Cli 学习整理【转载】
  4. 数据库建表练习(10.11作业)
  5. 从零开始springboot 第二讲
  6. 关于glusterfs-3.0.4中AFR修复的一个bug
  7. 微软从安卓那里获取的盈利比重WinPhone 7还多
  8. TCP 粘包/拆包说明 及 异常案例
  9. \opencv\build\x86下的vc6、vc7、vc8、vc9、vc10、vc11、vc12、vc14、vc15是什么意思?
  10. mysql sql优化的几种方法_sql优化常用的几种方法,19种最有效的sql优化技巧
  11. CenterOs git安装
  12. 计算机里没有硬盘 右下角有图标,电脑右下角显示硬盘图标怎么去掉<br?电脑 – 手机爱问...
  13. 贾琏欲执事(JDBC连接数据库)
  14. 怎么查看电脑开关机时间记录
  15. 【RTD】铂电阻测温原理与具体方法
  16. python barplot宽度,如何在seaborn barplot上设置宽度
  17. MySQL专题四——MySQL函数(聚合函数)
  18. 龙岩群控服务器系统,服务器群控操作
  19. IMPERVA - WAF 如何配置Imperva SNMP
  20. 隐藏代码Android,手机隐藏代码大集合 知道5个以上是大神

热门文章

  1. 平面与空间射影几何小结——空间射影几何
  2. ad走线打过孔_Altium Designer规则设计技巧过孔和焊盘
  3. 计算机换算单位 gb,gb和mb的换算-KB,MB,GB之间的换算关系
  4. 惯性系统常用坐标系_惯性坐标系与非惯性坐标系
  5. 华为交换机关闭网口_华为交换机如何关闭端口号
  6. 腾讯云短信服务详细教程
  7. 求生之路4的联机方法和秘籍
  8. ◮OpenGL-抗锯齿
  9. 51单片机实现拼音输入法
  10. Google Play镜像站