• 技术文章 >后端开发 >C#.Net教程

    C#开发实例-订制屏幕截图工具(六)添加配置管理功能详解(图文)

    黄舟黄舟2017-03-14 13:33:57原创1428

    添加设置窗口

    在解决方案资源管理器窗口中,右键单击项目名称,在弹出的菜单中选择:添加》Windows窗体:

    php入门到就业线上直播课:进入学习


    输入窗体名称“frmSetup”:


    设置窗体的Text属性为“设置”,设置窗体的Size为“472, 276”,StartPosition属性为“CenterScreen”。

    添加设置标签页

    左侧工具箱》窗器:双击“TabControl”


    设置的Dock属性为“Top”,Size属性为“456, 200”;

    添加标签页:


    添加三个标签页,Text分别设置为“基本设置,自动上传,自动保存”


    添加确定和取消按钮

    基本设置标签页:


    从工具箱中添加两个GroupBox,分别为“热键、截图选项”;

    添加两个RadioButton,用于热键选择;

    添加四个CheckBox用于截图选项;

    添加两个TextBox用于设置放大镜的尺寸;

    添加两个PictureBox用于显示X和锁的图片

    添加图片资源:

    双击Properties中的“Resources.resx”


    切换到图像视图


    将图片复制,粘贴到这里,分别命名为“Lock,X”;

    设置PictureBox的Image属性为对应的资源:


    自动上传标签页:


    自动保存标签页:


    其中文件名称需要使用两个ComboBox,Items集合分别设置为:



    编写代码:

    双击设置窗体,切换到代码视图,添加私有变量

            /// <summary>
            /// 保存Form1的句柄
            /// </summary>
            private IntPtr frm1Handle = IntPtr.Zero;

    修改构造函数

            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="frm1_Handle"></param>
            public frmSetup(IntPtr frm1_Handle)
            {
                InitializeComponent();
                this.frm1Handle = frm1_Handle;
            }

    为托盘菜单中的设置添加事件处理

    打开主窗体Form1的设计视图,选中“contextMenuStrip1”


    修改设置菜单的Name为“tsmi_Set”,双击设置菜单,添加代码:

            /// <summary>
            /// 托盘菜单设置事件处理程序
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void tsmi_Set_Click(object sender, EventArgs e)
            {
                frmSetup frm = new frmSetup(this.Handle);
                frm.ShowDialog();
            }

    编译,调试一下,通过托盘图标的右键菜单》设置 可以打开刚刚添加的设置窗口了。

    添加项目引用

    主窗体添加相关配置项变量:

            #region 基本设置参数
            /// <summary>
            /// 截图时是否显示截图信息栏
            /// </summary>
            public bool InfoBoxVisible = true;
            /// <summary>
            /// 截图时是否显示编辑工具栏
            /// </summary>
            public bool ToolBoxVisible = true;
            /// <summary>
            /// 截图中是否包含鼠标指针形状
            /// </summary>
            public bool IsCutCursor = true;
            /// <summary>
            /// 截图时是否显示放大镜
            /// </summary>
            public bool ZoomBoxVisible = true;
            /// <summary>
            /// 放大镜的尺寸——宽度
            /// </summary>
            public int ZoomBoxWidth = 120;
            /// <summary>
            /// 放大镜的尺寸——高度
            /// </summary>
            public int ZoomBoxHeight = 100;
            #endregion
    
            #region 图片上传参数
            public string PicDescFieldName = "pictitle";
            public string ImageFieldName = "upfile";
            public string PicDesc = "cutImage";
            public string UploadUrl = "http://";
            public bool DoUpload = false;
            #endregion
    
            #region 自动保存参数
            /// <summary>
            /// 是否自动保存到硬盘
            /// </summary>
            public bool AutoSaveToDisk = false;
            /// <summary>
            /// 自动保存目录
            /// </summary>
            public string AutoSaveDirectory = string.Empty;
            /// <summary>
            /// 是否启用日期格式“2013_02_22”的子目录
            /// </summary>
            public bool AutoSaveSubDir = false;
            /// <summary>
            /// 自动保存文件名前缀
            /// </summary>
            public string AutoSaveFileName1 = "屏幕截图";
            /// <summary>
            /// 自动文件名规则:日期时间,日期_序号,序号
            /// </summary>
            public string AutoSaveFileName2 = "日期时间";
            /// <summary>
            /// 自动保存文件格式:.png, .jpg, .jpeg, .gif, .bmp
            /// </summary>
            public string AutoSaveFileName3 = ".png";
            /// <summary>
            /// 自动保存文件名序号
            /// </summary>
            public int autoSaveFileIndex = 0;
            #endregion 自动保存参数

    添加“AppSettingKeys”类:

        /// <summary>
        /// 提供配置文件中AppSettings节中对应的Key名称
        /// </summary>
        public static class AppSettingKeys
        {
            //基本设置
            public static string HotKeyMode = "HotKeyMode";
            public static string InfoBoxVisible = "InfoBoxVisible";
            public static string ToolBoxVisible = "ToolBoxVisible";
            public static string ZoomBoxVisible = "ZoomBoxVisible";
            public static string ZoomBoxWidth = "ZoomBoxWidth";
            public static string ZoomBoxHeight = "ZoomBoxHeight";
            public static string IsCutCursor = "IsCutCursor";
            //图片上传
            public static string PicDescFieldName = "PicDescFieldName";
            public static string ImageFieldName = "ImageFieldName";
            public static string PicDesc = "PicDesc";
            public static string UploadUrl = "UploadUrl";
            public static string DoUpload = "DoUpload";
            //自动保存
            public static string AutoSaveToDisk = "AutoSaveToDisk";
            public static string AutoSaveSubDir = "AutoSaveSubDir";
            public static string AutoSaveDirectory = "AutoSaveDirectory";
            public static string AutoSaveFileName1 = "AutoSaveFileName1";
            public static string AutoSaveFileName2 = "AutoSaveFileName2";
            public static string AutoSaveFileName3 = "AutoSaveFileName3";
    
        }

    Program.cs文件添加枚举类型:

        /// <summary>
        /// 控制键的类型
        /// </summary>
        public enum KeyModifiers : uint
        {
            None = 0,
            Alt = 1,
            Control = 2,
            Shift = 4,
            Windows = 8
        }

    警告:由于xxx是引用封送类的字段,访问上面的成员可能导致运行时异常

    设置窗口完整代码:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    
    namespace Screenshot
    {
        public partial class frmSetup : Form
        {
            /// <summary>
            /// 保存Form1的句柄
            /// </summary>
            private IntPtr frm1Handle = IntPtr.Zero;
    
            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="frm1_Handle"></param>
            public frmSetup(IntPtr frm1_Handle)
            {
                InitializeComponent();
                this.frm1Handle = frm1_Handle;
            }
    
            /// <summary>
            /// 确定按钮单击事件处理程序
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void button_ok_Click(object sender, EventArgs e)
            {
                if (checkBox_autoSave.Checked && textBox_saveDir.Text.Trim().Length == 0)
                {
                    MessageBox.Show("您选择了“自动保存屏幕截图到磁盘”\n但还没有设置存储目录!");
                    return;
                }
                if (checkBox_autoSave.Checked && textBox_saveDir.Text.Trim().Length > 0)
                {
                    if (!System.Text.RegularExpressions.Regex.IsMatch(textBox_saveDir.Text.Trim(), "^[a-zA-Z]:\\\\[^/:\\*\\?\"<>\\|]*$", 
                    System.Text.RegularExpressions.RegexOptions.IgnoreCase))
                    {
                        MessageBox.Show("您选择了“自动保存屏幕截图到磁盘”\n但设置的存储目录不是有效的目录!");
                        return;
                    }
                    if (!System.IO.Directory.Exists(textBox_saveDir.Text.Trim()))
                    {
                        MessageBox.Show("您选择了“自动保存屏幕截图到磁盘”\n但设置的存储目录不存在!");
                        return;
                    }
                }
                Form1 frm = (Form1)Form.FromHandle(frm1Handle);
                if (frm != null)
                {
                    //基本设置
                    if (radioButton1.Checked) // && frm.HotKeyMode != 0 无论是否改变都重新注册热键,解决有时热键失效的问题
                    {
                        Form1.UnregisterHotKey(frm1Handle, frm.hotKeyId);
                        Form1.RegisterHotKey(frm1Handle, frm.hotKeyId, (uint)KeyModifiers.Control | (uint)KeyModifiers.Alt, Keys.A);
                        frm.HotKeyMode = 0;
                    }
    
                    if (radioButton2.Checked) // && frm.HotKeyMode != 1 无论是否改变都重新注册热键,解决有时热键失效的问题
                    {
                        Form1.UnregisterHotKey(frm1Handle, frm.hotKeyId);
                        Form1.RegisterHotKey(frm1Handle, frm.hotKeyId, (uint)KeyModifiers.Control | (uint)KeyModifiers.Shift, Keys.A);
                        frm.HotKeyMode = 1;
                    }
    
                    frm.InfoBoxVisible = ckb_InfoBox.Checked;
                    frm.ToolBoxVisible = ckb_ToolBox.Checked;
                    frm.IsCutCursor = ckb_CutCursor.Checked;
                    frm.ZoomBoxVisible = ckb_ZoomBox.Checked;
    
    
                    frm.ZoomBoxWidth1 = Convert.ToInt32(tb_zoomBoxWidth.Text);
                    frm.ZoomBoxHeight1 = Convert.ToInt32(tb_zoomBoxHeight.Text);
    
                    if (frm.ZoomBoxWidth1 < 120)
                    {
                        frm.ZoomBoxWidth1 = 120;
                        tb_zoomBoxWidth.Text = frm.ZoomBoxWidth1.ToString();
                    }
                    if (frm.ZoomBoxHeight1 < 100)
                    {
                        frm.ZoomBoxHeight1 = 100;
                        tb_zoomBoxHeight.Text = frm.ZoomBoxHeight1.ToString();
                    }
    
                    //图片上传
                    frm.PicDescFieldName = textBox_fieldDesc.Text;
                    frm.ImageFieldName = textBox_fieldFile.Text;
                    frm.PicDesc = textBox_desc.Text;
                    frm.UploadUrl = textBox_uploadUrl.Text;
                    frm.DoUpload = checkBox_upload.Checked;
    
                    //自动保存
                    frm.AutoSaveToDisk = checkBox_autoSave.Checked;
                    frm.AutoSaveSubDir = chb_subDir.Checked;
                    frm.AutoSaveDirectory = textBox_saveDir.Text;
    
                    frm.AutoSaveFileName1 = textBox_fileName1.Text;
                    if (comboBox_fileName2.SelectedItem != null)
                    {
                        frm.AutoSaveFileName2 = comboBox_fileName2.Text;
                    }
                    else
                    {
                        frm.AutoSaveFileName2 = "日期时间";
                    }
                    if (comboBox_Extn.SelectedItem != null)
                    {
                        frm.AutoSaveFileName3 = comboBox_Extn.Text;
                    }
                    else
                    {
                        frm.AutoSaveFileName3 = ".png";
                    }
                }
    
                SaveConfiguration();
    
                this.Close();
            }
    
            /// <summary>
            /// 保存配置信息到配置文件
            /// </summary>
            private void SaveConfiguration()
            {
                System.Configuration.Configuration config = System.Configuration.ConfigurationManager.OpenExeConfiguration(null);
    
                //基本设置
                SetConfigAppSetting(ref config, AppSettingKeys.HotKeyMode, radioButton1.Checked ? "1" : "0");
                SetConfigAppSetting(ref config, AppSettingKeys.InfoBoxVisible, ckb_InfoBox.Checked ? "1" : "0");
                SetConfigAppSetting(ref config, AppSettingKeys.ToolBoxVisible, ckb_ToolBox.Checked ? "1" : "0");
                SetConfigAppSetting(ref config, AppSettingKeys.IsCutCursor, ckb_CutCursor.Checked ? "1" : "0");
                SetConfigAppSetting(ref config, AppSettingKeys.ZoomBoxVisible, ckb_ZoomBox.Checked ? "1" : "0");
                SetConfigAppSetting(ref config, AppSettingKeys.ZoomBoxWidth, tb_zoomBoxWidth.Text);
                SetConfigAppSetting(ref config, AppSettingKeys.ZoomBoxHeight, tb_zoomBoxHeight.Text);
    
                //图片上传
                SetConfigAppSetting(ref config, AppSettingKeys.PicDescFieldName, textBox_fieldDesc.Text.Trim());
                SetConfigAppSetting(ref config, AppSettingKeys.ImageFieldName, textBox_fieldFile.Text.Trim());
                SetConfigAppSetting(ref config, AppSettingKeys.PicDesc, textBox_desc.Text.Trim());
                SetConfigAppSetting(ref config, AppSettingKeys.UploadUrl, textBox_uploadUrl.Text.Trim());
                SetConfigAppSetting(ref config, AppSettingKeys.DoUpload, checkBox_upload.Checked ? "1" : "0");
    
                //自动保存
                SetConfigAppSetting(ref config, AppSettingKeys.AutoSaveToDisk, checkBox_autoSave.Checked ? "1" : "0");
                SetConfigAppSetting(ref config, AppSettingKeys.AutoSaveSubDir, chb_subDir.Checked ? "1" : "0");
                SetConfigAppSetting(ref config, AppSettingKeys.AutoSaveDirectory, textBox_saveDir.Text.Trim());
                SetConfigAppSetting(ref config, AppSettingKeys.AutoSaveFileName1, textBox_fileName1.Text.Trim());
                if (comboBox_fileName2.SelectedItem != null)
                {
                    SetConfigAppSetting(ref config, AppSettingKeys.AutoSaveFileName2, comboBox_fileName2.Text);
                }
                else
                {
                    SetConfigAppSetting(ref config, AppSettingKeys.AutoSaveFileName2, "日期时间");
                }
                if (comboBox_Extn.SelectedItem != null)
                {
                    SetConfigAppSetting(ref config, AppSettingKeys.AutoSaveFileName3, comboBox_Extn.Text);
                }
                else
                {
                    SetConfigAppSetting(ref config, AppSettingKeys.AutoSaveFileName3, ".png");
                }
    
                config.Save(System.Configuration.ConfigurationSaveMode.Modified);
            }
    
            /// <summary>
            /// 设置配置信息
            /// </summary>
            /// <param name="config"></param>
            /// <param name="key"></param>
            /// <param name="value"></param>
            /// <returns></returns>
            private bool SetConfigAppSetting(ref System.Configuration.Configuration config, string key, string value)
            {
                try
                {
                    if (config.AppSettings.Settings[key] != null)
                    {
                        config.AppSettings.Settings[key].Value = value;
                    }
                    else
                    {
                        config.AppSettings.Settings.Add(key, value);
                    }
                    return true;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message + ex.Source + ex.StackTrace);
                    return false;
                }
            }
    
            /// <summary>
            /// 获取配置信息
            /// </summary>
            /// <param name="config"></param>
            /// <param name="key"></param>
            /// <returns></returns>
            private string GetConfigAppSetting(ref System.Configuration.Configuration config, string key)
            {
                try
                {
                    if (config.AppSettings.Settings[key] != null)
                    {
                        return config.AppSettings.Settings[key].Value;
                    }
    
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message + ex.Source + ex.StackTrace);
                }
                return string.Empty;
            }
    
            /// <summary>
            /// 取消按钮单击事件处理程序
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void button_cancel_Click(object sender, EventArgs e)
            {
                this.Close();
            }
            /// <summary>
            /// 窗口加载事件处理程序
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void frmSetup_Load(object sender, EventArgs e)
            {
                chb_subDir.Text = "启用(按日期命名,格式:" + DateTime.Now.Date.ToString("yyyy_MM_dd") + ")";
    
                Form1 frm = (Form1)Form.FromHandle(frm1Handle);
                if (frm != null)
                {
                    //基本设置
                    if (frm.HotKeyMode == 0)
                    {
                        radioButton1.Checked = true;
                        radioButton2.Checked = false;
                    }
                    else
                    {
                        radioButton1.Checked = false;
                        radioButton2.Checked = true;
                    }
    
                    ckb_InfoBox.Checked = frm.InfoBoxVisible;
                    ckb_ToolBox.Checked = frm.ToolBoxVisible;
                    ckb_CutCursor.Checked = frm.IsCutCursor;
                    ckb_ZoomBox.Checked = frm.ZoomBoxVisible;
    
                    //图片上传
                    textBox_fieldDesc.Text = frm.PicDescFieldName;
                    textBox_fieldFile.Text = frm.ImageFieldName;
                    textBox_desc.Text = frm.PicDesc;
                    textBox_uploadUrl.Text = frm.UploadUrl;
                    checkBox_upload.Checked = frm.DoUpload;
    
                    //自动保存
                    checkBox_autoSave.Checked = frm.AutoSaveToDisk;
                    chb_subDir.Checked = frm.AutoSaveSubDir;
                    textBox_saveDir.Text = frm.AutoSaveDirectory;
                    textBox_fileName1.Text = frm.AutoSaveFileName1;
                    comboBox_fileName2.SelectedItem = frm.AutoSaveFileName2;
                    comboBox_Extn.SelectedItem = frm.AutoSaveFileName3;
    
    
                }
            }
            /// <summary>
            /// 浏览按钮事件处理程序
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void button_browse_Click(object sender, EventArgs e)
            {
                FolderBrowserDialog fbd = new FolderBrowserDialog();
                fbd.Description = "请选择屏幕截图的保存目录:";
                fbd.ShowNewFolderButton = true;
                fbd.RootFolder = Environment.SpecialFolder.MyComputer;
                fbd.SelectedPath = textBox_saveDir.Text;
                if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    textBox_saveDir.Text = fbd.SelectedPath;
                }
            }
            /// <summary>
            /// 更新自动保存文件名称示例
            /// </summary>
            private void UpdateFileNameExmple()
            {
                string AutoSaveFileName2 = string.Empty;
                if (comboBox_fileName2.SelectedItem != null)
                {
                    AutoSaveFileName2 = comboBox_fileName2.Text;
                }
                string AutoSaveFileName3 = ".png";
                if (comboBox_Extn.SelectedItem != null)
                {
                    AutoSaveFileName3 = comboBox_Extn.Text;
                }
    
                switch (AutoSaveFileName2)
                {
                    case "日期_序号":
                        textBox_exmple.Text = textBox_fileName1.Text + DateTime.Now.ToString("yyyy-MM-dd_") + "0001" + AutoSaveFileName3;
                        break;
                    case "序号":
                        textBox_exmple.Text = textBox_fileName1.Text + "0001" + AutoSaveFileName3;
                        break;
                    default:
                        textBox_exmple.Text = textBox_fileName1.Text + DateTime.Now.ToString("yyyy-MM-dd_HHmmss") + AutoSaveFileName3;
                        break;
                }
            }
    
            private void comboBox_fileName2_SelectedIndexChanged(object sender, EventArgs e)
            {
                UpdateFileNameExmple();
            }
    
            private void comboBox_Extn_SelectedIndexChanged(object sender, EventArgs e)
            {
                UpdateFileNameExmple();
            }
    
            private void textBox_fileName1_TextChanged(object sender, EventArgs e)
            {
                UpdateFileNameExmple();
            }
    
            // Boolean flag used to determine when a character other than a number is entered.
            private bool nonNumberEntered = false;
    
            private void tb_zoomBoxWidth_KeyDown(object sender, KeyEventArgs e)
            {
                // Initialize the flag to false.
                nonNumberEntered = false;
    
                // Determine whether the keystroke is a number from the top of the keyboard.
                if (e.KeyCode < Keys.D0 || e.KeyCode > Keys.D9)
                {
                    // Determine whether the keystroke is a number from the keypad.
                    if (e.KeyCode < Keys.NumPad0 || e.KeyCode > Keys.NumPad9)
                    {
                        // Determine whether the keystroke is a backspace.
                        if (e.KeyCode != Keys.Back)
                        {
                            // A non-numerical keystroke was pressed.
                            // Set the flag to true and evaluate in KeyPress event.
                            nonNumberEntered = true;
                        }
                    }
                }
                //If shift key was pressed, it's not a number.
                if (Control.ModifierKeys == Keys.Shift)
                {
                    nonNumberEntered = true;
                }
            }
    
            private void tb_zoomBoxHeight_KeyDown(object sender, KeyEventArgs e)
            {
                // Initialize the flag to false.
                nonNumberEntered = false;
    
                // Determine whether the keystroke is a number from the top of the keyboard.
                if (e.KeyCode < Keys.D0 || e.KeyCode > Keys.D9)
                {
                    // Determine whether the keystroke is a number from the keypad.
                    if (e.KeyCode < Keys.NumPad0 || e.KeyCode > Keys.NumPad9)
                    {
                        // Determine whether the keystroke is a backspace.
                        if (e.KeyCode != Keys.Back)
                        {
                            // A non-numerical keystroke was pressed.
                            // Set the flag to true and evaluate in KeyPress event.
                            nonNumberEntered = true;
                        }
                    }
                }
                //If shift key was pressed, it's not a number.
                if (Control.ModifierKeys == Keys.Shift)
                {
                    nonNumberEntered = true;
                }
            }
    
            private void tb_zoomBoxWidth_KeyPress(object sender, KeyPressEventArgs e)
            {
    
                // Check for the flag being set in the KeyDown event.
                if (nonNumberEntered == true)
                {
                    // Stop the character from being entered into the control since it is non-numerical.
                    e.Handled = true;
                }
            }
    
    
            private void tb_zoomBoxHeight_KeyPress(object sender, KeyPressEventArgs e)
            {
                // Check for the flag being set in the KeyDown event.
                if (nonNumberEntered == true)
                {
                    // Stop the character from being entered into the control since it is non-numerical.
                    e.Handled = true;
                }
            }
    
            /// <summary>
            /// 放大镜宽度改变事件处理
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void tb_zoomBoxWidth_TextChanged(object sender, EventArgs e)
            {
                int zoomWidth = Convert.ToInt32(tb_zoomBoxWidth.Text);
                if (zoomWidth < 120) { zoomWidth = 120; }
    
                tb_zoomBoxHeight.Text = ((int)(zoomWidth * 100 / 120)).ToString();
            }
    
            /// <summary>
            /// 放大镜高度改变事件处理
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void tb_zoomBoxHeight_TextChanged(object sender, EventArgs e)
            {
                int zoomHeight = Convert.ToInt32(tb_zoomBoxHeight.Text);
                if (zoomHeight < 100) { zoomHeight = 100; }
    
                tb_zoomBoxWidth.Text = ((int)(zoomHeight * 120 / 100)).ToString();
            }
        }
    }

    以上就是C#开发实例-订制屏幕截图工具(六)添加配置管理功能详解(图文)的详细内容,更多请关注php中文网其它相关文章!

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。

    前端(VUE)零基础到就业课程:点击学习

    清晰的学习路线+老师随时辅导答疑

    快捷开发Web应用及小程序:点击使用

    支持亿级表,高并发,自动生成可视化后台。

    上一篇:C#开发实例-订制屏幕截图工具(五)针对拖拽时闪烁卡顿的优化 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • ❤️‍🔥共22门课程,总价3725元,会员免费学• ❤️‍🔥接口自动化测试不想写代码?• 解决asp.net中“从客户端中检测到有潜在危险的Request.Form值”的错误• asp.net 图片验证码的HtmlHelper• ASP.NET使用Ajax如何返回Json对象的方法具体介绍• SUNWEN教程之----C#进阶(二)• SUNWEN教程之----C#进阶(三)
    1/1

    PHP中文网