• 基于C#使用winform技术的游戏平台的实现【C#课程设计】


    说明

    今天,也是刚刚答完辩,终于可以将自己写的代码放到CSDN上啦,这个是开学之前就做好的一个项目,然后就是简单的使用winform做了一个CS结构的课设,实现了基础的crud以及扩展的导入导出Excel和图表控件及高德地图天气API接口的使用。使用了一些基本的控件和特殊一点的控件就是ImageList 和 listView (因为我们课上没有学过,所以觉得比较特殊)

    项目结构

    然后下面的话,是整体项目的一个结构(简单分了一下包,DataAccess就是数据接入层dao,Entity就是对应的一些实体类,Resources是项目的一些静态资源,Utils下的话是我自己做的一些工具类,Views的是winform一些不同功能的窗体区分

    在这里插入图片描述

    项目运行截图及实现的功能

    1. 登录和注册
      在这里插入图片描述
      在这里插入图片描述
      账号的密码使用md5进行加密

    2. 登录首页
      在这里插入图片描述
      这里的话,实现了一个侧边栏的封装和自定义最小化和最大化按钮,然后中间主体是一个高德地图的天气API,具体使用我会在后面的文章列出,然后还有个底部的计时器实现时间刷新功能。

    3. 用户的个人信息修改,头像上传及重置功能
      在这里插入图片描述

    4. 游戏商城列表查看(用户端)
      在这里插入图片描述
      这里主要使用的两个控件就是listView和imageList,以及Panel布局组件(当我点选左侧的游戏时,右侧的游戏详情会进行显示,当然多条件查询也是可以的哈)

    5. 个人游戏仓库查看
      在这里插入图片描述
      这里的话和上面那个也差不多,就是自己买的游戏,用到的控件也是imageList和那个listView

    6. 管理员账号的登录(游戏管理)
      在这里插入图片描述
      管理员账号登录,右侧显示的侧边栏内容是不一样的,实现了数据的导入导出(可以将Excel中的内容导入到数据库中),然后就是一些crud操作。

    7. 用户信息管理
      在这里插入图片描述
      和上面的游戏管理功能基本差不多,就不一一赘述啦。

    8. 数据分析
      在这里插入图片描述
      这个的话,是使用了一些livecharts的图表控件来做的,算是一点点创新把。

    部分代码一些说明(个人觉得一些难点的说明)

    一、ListView ,ImageList 的综合使用

    在C#中,ListView是一个常用的控件,用于在Windows窗体应用程序中显示数据。它可以以多种方式呈现数据,包括大图标、小图标、列表和详细信息。
    在C#中,ImageList是一个用于存储图像集合的类。它提供了一种方便的方式来管理和使用一组图像,通常用于在用户界面控件中显示图像列表。

    private void DrawLvGame(DataSet ds)
    {
        // 先清空,防止计时器一直添加
        this.listViewGames.Items.Clear();
        this.imageList1.Images.Clear(); //清空图片数组
        // 渲染到listView中
        if (ds != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0)
        {
            listViewGames.View = View.LargeIcon; //设置listview为大图标模式
            listViewGames.LargeImageList = imageList1;// 设置listview的图片数组
    
    
            listViewGames.Visible = true;
            // 开始绘制控件,暂时挂起lv
            listViewGames.BeginUpdate();
    
            for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
            {
                ListViewItem lv = new ListViewItem();
                lv.ImageIndex = i;
                lv.Text = ds.Tables[0].Rows[i][0].ToString();
                // 设置图标
                this.imageList1.Images.Add(Image.FromFile(baseImageUrl + ds.Tables[0].Rows[i][1].ToString()));
                listViewGames.Items.Add(lv);
            }
            // 结束绘制
            listViewGames.EndUpdate();
        }
    }
    
    • 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

    说明:

    1. 通过 listview对象.view 的方式可以设置ListView的显示方式,其中View对象是一个枚举类,列举了可供listview选择的5种方式,我选择大图标模式(显示效果好看一点)

    在这里插入图片描述

    1. 我这里的需求是,需要将数据库的游戏信息读取出来,然后动态的去显示对应的图片,所以需要通过listViewGames.LargeImageList = imageList1 去绑定一个图片数组(imageList1 为 ImageList控件,listViewGames 为ListView控件)

    在这里插入图片描述

    1. BeginUpdate() 和 EndUpdate()两个方法,方法用于控制 ListView 的更新。它们的作用是在进行大量添加、删除或修改 ListView 中的项目时,提高性能和用户界面响应速度。
    2. ImageList 添加数据,通过ImageList对象.Images.Add(Image对象),这里有个需要注意的点,应为我们从数据库中读取的图片路径为一个字符串,所以我们需要通过这个字符串转换为Image对象,然后Image类中提供了一个方法 Image.FromFile(path),将文件路径对应的图片读取为Image对象。
    3. 综上所述,我只需要在获取到游戏列表数据时,去遍历,将图片路径添加到imageList控件的项目中,然后在ListView控件中添加ListViewItem即可。

    二、图片上传以及picturebox 图片的动态替换

    文件框选择 OpenFileDialog 完成文件上传到本地磁盘功能

    private void btnChangeAvatr_Click(object sender, EventArgs e)
    {
        OpenFileDialog fileDialog = new OpenFileDialog();
        fileDialog.Multiselect = true; fileDialog.Title = "请选择文件";
        fileDialog.Filter = "所有文件(*jpg*)|*.jpg*"; //设置要选择的文件的类型
        if (fileDialog.ShowDialog() == DialogResult.OK)
        {
            // 获取图片上传的路径
            string localFilePath = fileDialog.FileName;
    
            //格式化处理,提取文件名 数据库要存的url
            string savePath = localFilePath.Substring(localFilePath.LastIndexOf("\\") + 1);
    
            // 存储到本地目录中 如果本地不存在该图片,那么就上传
            if (!File.Exists(baseImageUrl + savePath))
            {
                File.Copy(localFilePath, baseImageUrl + savePath, false);
            }
            // 数据库更新操作 传递nickname和新的图片url即可
            int flag = UserDataAccess.GetInstance().UpdateUserAvatar(user.Nickname, savePath);
            if (flag > 0)
            {
                MessageBox.Show("更新成功!!\n本地存储图片路径为:" + baseImageUrl + savePath);
                RefreshWindow();
            }
            else
            {
                MessageBox.Show("修改失败!");
            }
    
        }
    
    }
    
    • 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

    说明:

    1. c#中的资源图片通常存放于当前项目的Resources,若想在项目中使用图片,则必须将图片上传到Resources目录下。
    2. 通常上传文件获取文件的路径是一个完整路径,而我们只需要它的文件名,所以通过Substring(localFilePath.LastIndexOf(“\”) + 1) 来截取最后一级目录即文件名
    3. 文件上传一个简单的去重校验 File.Exists(path),返回 true | false,
    4. 文件上传 File.copy(源路径,目的路径,是否重写【true|false】)

    文件动态替换功能

    Bitmap bitmap = new Bitmap(baseImageUrl + user.Avatar);
    this.picAvatar.BackgroundImage = bitmap;
    
    • 1
    • 2

    说白了就两行代码,PictureBox.BackgroundImage 的值可以是一个 Bitmap对象(Bitmap对象继承自Image对象),而 Bitmap对象可以通过类似File类的方式(通过路径产生)。

    在这里插入图片描述

    在这里插入图片描述

    三、图表插件的使用

    因为之前写过一篇类似的博客 ,我就直接贴博客链接了winform .net6 和 framework 的图表控件,为啥项目中不存在chart控件,该如何解决?

    因为我这个项目创建的时候,没注意,然后创建的项目是 .net6版本的,所以下面就介绍 ScottPlot 这个图表插件的使用(看文档就基本ok了),scottPlot 官网链接:

    1. 进入官网,选择QuickStart快速开始,然后选择winform的就行,看看快速入门的例子
      在这里插入图片描述

    2. 看完之后,就根据自己的需求去选择不同的图表进行配置 https://scottplot.net/cookbook/4.1/,查看它的cookbook就好啦
      一个柱状图的demo https://scottplot.net/cookbook/4.1/,感觉着配置都基本不用说,反正按照配置项去获取对应的数据就可以生成一个动态的图表了。

    在这里插入图片描述

    下面贴一张我的SQL图表例子:

    在这里插入图片描述

    四、SQL工具类封装

    SQL工具类,我使用的是一个单例模式
    提供一个静态类对象,一个私有构造器,以及一个获取类对象的静态方法。这样就可以避免每次操作数据库去new一个对象了,至始至终都是一个对象在操作。

    using GamePlantForm.Dao;
    using GamePlantForm.Entity;
    using GamePlantForm.Utils;
    using Microsoft.VisualBasic.ApplicationServices;
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Data.SqlClient;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace GamePlantForm.DataAccess
    {
        public class GameDataAccess
        {
            // 使用单例模式
            private static GameDataAccess instance;
    
            private GameDataAccess() { }
    
            public static GameDataAccess GetInstance()
            {
                return instance ?? (instance = new GameDataAccess());
            }
    
            SqlConnection conn;
            SqlCommand comm;
            SqlDataAdapter adapter;
    
            /// 
            /// 数据库资源释放
            /// 
            private void Dispose()
            {
                if (adapter != null)
                {
                    adapter.Dispose();
                    adapter = null;
                }
                if (comm != null)
                {
                    comm.Dispose();
                    comm = null;
                }
                if (conn != null)
                {
                    conn.Close();
                    conn.Dispose();
                    conn = null;
                }
            }
    
            /// 
            /// 数据库链接
            /// 
            private bool DBConnection()
            {
                // 
                string connStr = "Data Source=.\\SQLEXPRESS;database=game_plantform;uid=sa;pwd=123456";
                if (conn == null)
                {
                    conn = new SqlConnection(connStr);
                }
                try
                {
                    conn.Open();
                    return true;
                }
                catch (Exception ex)
                {
                    return false;
                }
            }
        }
    }
    
    • 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

    五、高德地图天气API的使用

    这个的话,重点在于自己找到对应的API接口文档,然后发送请求,用几个实体类对接一些想要的数据即可。我这里只放一下自己写的发送请求的代码。

    tips:注意,一定使用自己申请的密钥哇

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Net.Http;
    using System.Threading.Tasks;
    using GamePlantForm.Entity;
    
    namespace GamePlantForm.Utils
    {
        // 自定义天气接口工具类
        internal class WeatherRobin
        {
            private readonly HttpClient _httpClient;
    
            public WeatherRobin()
            {
                _httpClient = new HttpClient();
            }
    
           
            // 150200
            public async void GetWeatherAsync(string cityName,Label labprovince,Label labcity, Label labadcode, Label labweather,
               Label labtemperature, Label labwinddirection, Label labwindpower, Label labhumidity, Label labreporttime)
            {
                var response = await _httpClient.GetAsync("https://restapi.amap.com/v3/weather/weatherInfo?city="+cityName+"&key=自己的天气密钥");
                var content = await response.Content.ReadAsStringAsync();
    
                // 1. 将获取到的json转换为数组
                RootObject obj = Newtonsoft.Json.JsonConvert.DeserializeObject (content);
    
                // 2. 将获取到的数据,填充到传递过来的实体类对象中
                labprovince.Text += ":"+ obj.lives[0].province;
                labcity.Text += ":" + obj.lives[0].city;
                labadcode.Text += ":" + obj.lives[0].adcode;
                labweather.Text += ":" + obj.lives[0].weather;
                labtemperature.Text += ":" + obj.lives[0].temperature+"℃";
                labwinddirection.Text += ":" + obj.lives[0].winddirection;
                labwindpower.Text += ":" + obj.lives[0].windpower+"级";
                labhumidity.Text += ":" + obj.lives[0].humidity;
                labreporttime.Text += ":" + obj.lives[0].reporttime;
            }
    
        }
    }
    
    • 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

    数据库设计部分

    在这里插入图片描述
    ER图之间的关系,有点偷懒了,不想画啦QAQ,这个SQL资源需要的可以找我拿

    完整代码资源

    完整代码,可以私信找我发,也可以通过这篇文章的绑定资源去下载。

    tips:本人只是个又菜又爱分享的小白,如果这篇文章可以帮助到你,帮我点个👍,哈哈哈!
    在这里插入图片描述

  • 相关阅读:
    Redis的快速入门【全方位进攻】
    邱锡鹏神经网络怎么样,邱锡鹏神经网络答案
    【Express.js】pm2进程管理
    使用在线的vscode打开github项目
    百度千帆大模型文心一言api调用
    js省市树状结构数据
    前端知识3-JavaScript
    C++:C++哪些时候用到const
    家庭实验室系列文章-电脑如何配置网络唤醒 (WOL)?
    C语言题收录(七)
  • 原文地址:https://blog.csdn.net/m0_63622279/article/details/134022808