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

基于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是一个用于存储图像集合的类。它提供了一种方便的方式来管理和使用一组图像,通常用于在用户界面控件中显示图像列表。

c# 复制代码
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. 通过 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 完成文件上传到本地磁盘功能

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

文件动态替换功能

c# 复制代码
Bitmap bitmap = new Bitmap(baseImageUrl + user.Avatar);
this.picAvatar.BackgroundImage = bitmap;

说白了就两行代码,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一个对象了,至始至终都是一个对象在操作。

C# 复制代码
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;

        /// <summary>
        /// 数据库资源释放
        /// </summary>
        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;
            }
        }

        /// <summary>
        /// 数据库链接
        /// </summary>
        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;
            }
        }
    }
}

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

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

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

c# 复制代码
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<RootObject> (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;
        }

    }
}

数据库设计部分

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

完整代码资源

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

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

相关推荐
fangzhanpeng1687 天前
快速掌握C#语言基础知识点(1.基础数据类型)
开发语言·c#·1024程序员节
无己心9 天前
面向多平台 AI 搜索引擎的适配层架构设计
前端·人工智能·搜索引擎·ai·1024程序员节
u01030552715 天前
AI驱动的安卓UI自动生成功能实现
人工智能·1024程序员节
u01030552716 天前
长株潭智能体赋能腾讯元器链接共享
1024程序员节
云贝贝贝17 天前
OceanBase认证体系介绍与备考指南
运维·服务器·oceanbase·1024程序员节
u01030552717 天前
Java图像处理实战指南
人工智能·1024程序员节
u01030552718 天前
Java AWT鼠标事件全解析
人工智能·1024程序员节
u01030552720 天前
Java实用类应用精讲
人工智能·1024程序员节
u01030552720 天前
Java I/O核心操作实战
人工智能·1024程序员节
u01030552721 天前
ArrayList操作详解与实战应用
人工智能·1024程序员节