Amor-ztt

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

一、设计思路

要实现一个网格状的学生管理页面,必须要一个网格形状的控件用于展示,还需要导入学生的数据。要实现的功能是点击某一行,显示出三个按钮(查看,修改,删除)的功能。
数据库:Mysql

主窗口+3个子窗口
image

主窗口:listview控件,button控件

查看窗口 look:textbox控件

修改窗口 update:lable控件,textbox控件,button控件,radiobutton单选框控件,date日期控件

删除窗口 delate:messagebox控件(只需要在form1中弹出窗口即可,不需要建立新窗口)

二、具体实现

1、主窗口Form1

(1)、主窗口Form1的构造函数

1、首先将主窗口的名字命名image
有一个Main函数,是整个项目的入口,往Application.Run(Form f)中,传入一个Form1类型的实例,用f(实参)去接收它。
这里有一个问题?为什么Application.Run(Form f)中需要的明明是Form类型的参数,你传的是Form1的实例对象,编译器为什么不报错呢?
答案是:Form1继承了Form类,所以子类中拥有了一份基类中完整的代码,即子类可以当做基类使用。( 这是面向对象中的 is a 法则)
image

2、手动拖拽控件之后,我们进入Form1的代码中,根据面向对象的三大原则(封装,继承,多态),我们先观察整个类的基本成员
(补:一个类最常用的三大成员有:属性,方法,事件)
(补:一个类最基本的成员有:属性—>字段,方法(构造函数、析构函数、普通方法、虚方法、抽象方法),事件 ——>委托类型的方法)

首先看Form1的构造函数,先进入InitializeComponent(),点击它,可以进入Form1的分部类中,在其中实例化这个类中的所以控件(一个类就是一个窗口),将字段或属性赋值,以及添加事件点击效果。截止为止,虽然构造函数还没有走完,但这个类的实例其实已经存在了,这个类中所有的字段已经赋完初值了,构造函数中剩下的的语句还是用来修改这个类中的字段或属性值,以及调用一些方法。

3、这个listview控件里面需要插入数据,所以我们需要连接MySql数据库
思考?当我们需要拿到数据库中的数据,用于展示时,应该干什么?
第一步:连接MySql数据库。我们需要找到连接的是哪一个数据库(数据库的username,password,ip,端口号等等信息)
第二步:查询数据库的某个表中的内容。需要写一条mysql的语句,去查询数据库某一个表里的信息
第三步:拿到数据库中的信息,并且用一个对象/字段 去保存信息。
第四步:将信息展示到页面上。

注意!数据库的连接要 有开有关。
image

Form1的构造函数代码
`
public Form1()
{
//将form1里面的[所有拖拽出来的控件],赋初值
InitializeComponent();

        //连接数据库,获取数据
        conn = new MySqlConnection(constr); //第一步:连接数据库。创建数据库连接类的对象
        comm = new MySqlCommand("select * from student", conn); // 第二步:查询数据库的student表。创建数据库查询命令类的对象

        // 打开数据库
        conn.Open();
        //第三步:用dr去接收查询出的内容
        dr = comm.ExecuteReader();
        // 调用Read(),循环遍历查询到的每一条数据
        while (dr.Read())     //数据库有几条数据,dr.Read()执行几次。
        {
            //数据更新,UI暂时挂起,直到EndUpdate绘制控件,可以有效避免闪烁并大大提高加载速度
            list_view.BeginUpdate();

            ListViewItem lt = new ListViewItem();
            //第四步:插入数据。将数据库数据转变成ListView类型的一行数据
            lt.Text = dr["index"].ToString();
            lt.SubItems.Add(dr["id"].ToString());
            lt.SubItems.Add(dr["name"].ToString());
            lt.SubItems.Add(dr["sex"].ToString());
            lt.SubItems.Add(dr["birthday"].ToString());
            lt.SubItems.Add(dr["reportday"].ToString());
            lt.SubItems.Add(dr["handle"].ToString());

            //将lt数据添加到listView1控件中
            list_view.Items.Add(lt);
            //结束数据处理,UI界面一次性绘制。
            list_view.EndUpdate();

        }

        //  数据库使用完毕后关闭数据库连接
        dr.Close();
        conn.Close();

        //设置 listview 的排序方法,在列标头事件中可以取出用来判断
        list_view.Sorting = SortOrder.Ascending;
        //设置按第1列排序
        list_view.ListViewItemSorter = new ListViewItemComparer(list_view.Sorting, 1);
    }

`

数据展示出后,我们需要建立3个button按钮,点击触发不同的事件
image

(2)主窗口的3个button按钮

思考!!这3个按钮不是一上来就显示在界面上的,并且按钮的位置,随着我们点击不同的行而改变。如何去实现呢?
第一步:需要在form1的load事件中,构造3个button实例对象,然后将可见属性visible设为false

第二步:当我们点击哪一行,这行就会出现按钮。所以要在对 list_view_SelectedIndexChanged()事件处理。

第三步:当我们点击某一行时,出现3个按钮以后。可以点击某一个按钮,触发响应的事件

`
private void list_view_SelectedIndexChanged(object sender, EventArgs e)
{
if (list_view.SelectedItems.Count > 0) //如果被选中行的数量>0,则确定button的位置,并且button的Visible属性设为 true
{
btn1.Location = new Point(list_view.SelectedItems[0].SubItems[6].Bounds.Left, list_view.SelectedItems[0].SubItems[6].Bounds.Top);
btn1.Visible = true;

            // location的位置是(x,y)x=选中行的第1行,第7列  y=是这一列中第5项的高(任意一个项的高都可以)
            btn2.Location = new Point(list_view.SelectedItems[0].SubItems[6].Bounds.Left + btn1.Width, list_view.SelectedItems[0].SubItems[5].Bounds.Top);
            btn2.Visible = true;

            btn3.Location = new Point(list_view.SelectedItems[0].SubItems[6].Bounds.Left + btn1.Width + btn2.Width, list_view.SelectedItems[0].SubItems[5].Bounds.Top);
            btn3.Visible = true;
        }
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        btn1.Visible = false;
        btn1.Text = "查看";
        btn1.Click += button_Click;
        list_view.Controls.Add(btn1);
        btn1.Size = new Size(handle.Width / 3, list_view.Items[0].SubItems[0].Bounds.Height);

        btn2.Visible = false;
        btn2.Text = "修改";
        btn2.Click += button_Click;
        list_view.Controls.Add(btn2);
        btn2.Size = new Size(handle.Width / 3, list_view.Items[0].SubItems[0].Bounds.Height);

        btn3.Visible = false;
        btn3.Text = "删除";
        btn3.Click += button_Click;
        list_view.Controls.Add(btn3);
        btn3.Size = new Size(handle.Width / 3, list_view.Items[0].SubItems[0].Bounds.Height);

        //插入滚动条
        list_view.Scrollable = false;
        ShowScrollBar((int)list_view.Handle, (int)ScrollBar.Vert , 1);
    }

点击查看代码

  private void button_Click(object sender, EventArgs e)
        {
            //用switch case 判断到底是哪一个button操作
            string btn_Text = ((Button)sender).Text;
            switch (btn_Text)
            {
                case "查看":
                    Look look = new Look(Convert.ToInt32(list_view.SelectedItems[0].SubItems[1].Text));     //构建一个Look类的实例对象,然后展示
                    look.Show();
                    break;
                case "修改":
                    Update update = new Update(list_view.SelectedItems[0].SubItems[1].Text, this);     //构建一个Update类的实例对象,然后展示
                    update.Show();
                    break;
                case "删除":
                    DialogResult result = MessageBox.Show("确定删除吗?", "删除", MessageBoxButtons.YesNo, MessageBoxIcon.Question); //弹出对话框
                    if (result == DialogResult.Yes)
                    {
                        // 如果确定删除,去连接数据库,执行删除语句,然后关闭数据库
                        comm.CommandText = "delete from student where id = " + list_view.SelectedItems[0].SubItems[1].Text;
                        // 连接数据库
                        conn.Open();
                        comm.ExecuteNonQuery();
                        conn.Close();
                        // 删除成功之后,调用RefreshListView刷新页面
                        RefreshListView();
                        // 然后再次隐藏3个按钮
                        btn1.Visible = false;
                        btn2.Visible = false;
                        btn3.Visible = false;
                    }
                    break;
                default:
                    break;
            }
        }

刷新方法
` public void RefreshListView()
{
// 刷新之前清空list_view中的已有数据
list_view.Items.Clear();

        // 因为类的实例已经被new出来了,所以不需要再重新new实例了,只需要通过属性去修改字段即可
        comm.CommandText = "select * from student";
        // 连接数据库
        conn.Open();
        // 查询数据库
        dr = comm.ExecuteReader();
        // 调用Read(),循环遍历查询到的每一条数据
        while (dr.Read())
        {
            //数据更新,UI暂时挂起,直到EndUpdate绘制控件,可以有效避免闪烁并大大提高加载速度
            list_view.BeginUpdate();

            ListViewItem lt = new ListViewItem();
            //将数据库数据转变成ListView类型的一行数据
            lt.Text = dr["index"].ToString();
            lt.SubItems.Add(dr["id"].ToString());
            lt.SubItems.Add(dr["name"].ToString());
            lt.SubItems.Add(dr["sex"].ToString());
            lt.SubItems.Add(dr["birthday"].ToString());
            lt.SubItems.Add(dr["reportday"].ToString());
            lt.SubItems.Add(dr["handle"].ToString());

            //将lt数据添加到listView1控件中
            list_view.Items.Add(lt);
            //结束数据处理,UI界面一次性绘制。
            list_view.EndUpdate();

        }

        //  数据库使用完毕后关闭数据库连接
        dr.Close();
        conn.Close();
    }`

`

2 Look.cs查看页面

{

public partial class Look : Form
{

    private string constr = "Database = db_student;Server = localhost;Port = 3306;Password = root;UserID = root;charset = utf8mb3";
	
    //连接对象
	
    private MySqlConnection conn = null;
	
    //语句执行对象
	
    private MySqlCommand comm = null;
	
    //执行结果对象

    private MySqlDataReader dr = null;

    // 因为look是一个新的窗口(类),所以需要重新创建这三个对象

    public Look(int id)
    {
        InitializeComponent();

        // 因为look是一个新的窗口(类),要重新连接数据库,获取数据
        conn = new MySqlConnection(constr); //创建数据库连接类的对象
        comm = new MySqlCommand("select * from student where id = " + id.ToString(), conn); //创建数据库查询命令类的对象

        // 连接数据库
        conn.Open();
        // 查询数据库
        dr = comm.ExecuteReader();
        // 预防脏数据
        textBox1.Text = "";

        // 调用Read(),循环遍历查询到的每一条数据
        while (dr.Read())
        {
            //将数据库数据转变成ListView类型的一行数据
            textBox1.Text += dr["index"].ToString()+"; ";
            textBox1.Text += dr["id"].ToString()+"; ";
            textBox1.Text += dr["name"].ToString() + "; ";
            textBox1.Text += dr["sex"].ToString() + "; ";
            textBox1.Text += dr["birthday"].ToString() + "; ";
            textBox1.Text += dr["reportday"].ToString() + "; ";
        }

        //  数据库使用完毕后关闭数据库连接
        dr.Close();
        conn.Close();
    }
}

}

3、update.cs更新页面

`

public partial class Update : Form

{

    private string constr = "Database = db_student;Server = localhost;Port = 3306;Password = root;UserID = root;charset = utf8mb3";
	
    //连接对象
	
    private MySqlConnection conn = null;
	
    //语句执行对象
	
    private MySqlCommand comm = null;
	
    //执行结果对象
	
    private MySqlDataReader dr = null;

    private Form1 form = null;

    public Update(string id, Form1 form1)
    {
        // 获取主界面实例,用于更新数据以后刷新主界面
        form = form1;

        InitializeComponent();
        // 连接数据库,获取数据
        conn = new MySqlConnection(constr); //创建数据库连接类的对象
        comm = new MySqlCommand("select * from student where id ="+ id , conn); //创建数据库查询命令类的对象

        // 连接数据库
        conn.Open();
        // 查询数据库
        dr = comm.ExecuteReader();

        textBox_id.Text = "";
        textBox_name.Text = "";
        radioButton_male.Checked = false;
        radioButton_female.Checked = false;
        textBox_reportday.Text = "";

        // 调用Read(),循环遍历查询到的每一条数据
        while (dr.Read())
        {
            textBox_id.Text = dr["id"].ToString();
            textBox_name.Text = dr["name"].ToString();
            //对性别进行判断处理
            if ("男" == dr["sex"].ToString())
            {
                radioButton_male.Checked = true;
            }
            else if ("女" == dr["sex"].ToString())
            {
                radioButton_female.Checked = true;
            }
            else 
            {
                MessageBox.Show("性别错误!");
            }

            //对出生日期进行分隔处理
            string birthday = dr["birthday"].ToString();
            string[] birthdayArr = birthday.Split('/');
            dateTime_birthday.Value = new DateTime(Convert.ToInt32(birthdayArr[0]),Convert.ToInt32(birthdayArr[1]),Convert.ToInt32(birthdayArr[2]));
            
            textBox_reportday.Text = dr["reportday"].ToString();
        }

        dr.Close();
    } 
    private void button_confirm_Click(object sender, EventArgs e)
    {
        try
        {
            // 对性别修改进行判断
            string temp_sex = "";
            if (radioButton_male.Checked)
                temp_sex = "男";
            else if (radioButton_female.Checked)
                temp_sex = "女";

            // 保存时根据控件特性需要对出生日期进行处理,将2020/10/22 19:20以空格为分隔
            string[] arr = dateTime_birthday.Value.ToString().Split(' ');

            string updateContent = string.Format("UPDATE student SET name='{0}',sex='{1}',birthday='{2}' WHERE id={3};",
             textBox_name.Text.ToString(),
             temp_sex,
             arr[0],
             textBox_id.Text);

            // 执行数据库带条件查询命令
            comm = new MySqlCommand(updateContent, conn);
            int num = 0;
            // 成功返回的是一受影响的行数,
            num = comm.ExecuteNonQuery();
            if (num > 0)
            {
                MessageBox.Show("修改成功");
            }
            else
            {
                MessageBox.Show("修改失败");

            }
        }
        catch (Exception)
        {
            throw;
        }
        finally
        {
            //更新完毕,关闭数据库连接
            conn.Close();
            form.RefreshListView();
            //关闭窗口
            Close();
        }
    }

    private void Update_Load(object sender, EventArgs e)
    {
       
    }

    private void button_cancel_Click(object sender, EventArgs e)
    {
        this.Close();
    }

    private void radioButton_female_CheckedChanged(object sender, EventArgs e)
    {

    }
}

}

`

4.删除控件,用message.box写在主窗体中即可(在button.Click中)

5.点击列表排序 list_view_ColumnClick(重点!!!)

鼠标单击每一项的列头,实现列表顺序排序。鼠标再点一次,则为逆序排序。

笔者最开始的想法是,先设置一个flag标志位,用点击次数判断,true为正序,false为逆序。
然后拿到这一行的所有数据,比如说点击index编号的列头,利用id值去查数据库,找到这一列的所有index,然后存入数组中。然后对数组进行升序或降序,然后从数组中依次取出按照index排好的每一条数据。

但是经过试验,明明将数据排好序插入了,但发现在listview中数据不更新,还是按照原来的顺序排列。疑惑!猜想这可能是listview这个控件的排序规则问题,可能不是从上到下,按照查询的顺序,依次将列表填满的。

于是上网查询,发现listview中有一个ListViewItemSorter属性,它接受一个实现了IComparer接口类型的值。
image

在list_view_ColumnClick中以SortOrder这个枚举值做判断

image

所以定义了一个ListViewItemComparer类,继承了IComparer接口,续写了Compare(object x, object y)方法。
将ListViewItemComparer类的实例 赋给 list_view.ListViewItemSorter
在Compare(object x, object y)中,定义排序方法
image

`

//定义一个类,这个类实现 IComparer 接口
class ListViewItemComparer : IComparer
{
    private int col;
    private SortOrder sort = SortOrder.None;
    public ListViewItemComparer(SortOrder sortOrder)
    {
        col = 0;
    }
    public ListViewItemComparer(SortOrder sortOrder, int column)
    {
        sort = sortOrder;
        col = column;
    }

    //实现接口的 Compare 方法,x、y 为要比较的两个对象 
    public int Compare(object x, object y)
    {
        //默认升序。判断传入的排序枚举,如果为降序就对换要比较的对象
        if (sort == SortOrder.Descending)
        {
            object temp = x;    //x、y是第几行
            x = y;
            y = temp;
        }

        string xx = ((ListViewItem)x).SubItems[col].Text;    // xx 是第x行的第col列的文本
        string yy = ((ListViewItem)y).SubItems[col].Text;    // yy 是第y行的第col列的文本

        int xxx = 0;
        int yyy = 0;

        //判断是否可以转换为数字,如果可以就按数字比较
        if (int.TryParse(xx.ToString(), out xxx) && int.TryParse(yy.ToString(), out yyy))
            return xxx.CompareTo(yyy);//按数字比较
        return string.Compare(xx, yy);//按字符比较
    }
}

`

posted on 2023-04-11 16:05  小颜七七  阅读(754)  评论(0编辑  收藏  举报