MFC第六天 使用列表控件CListCtrl类开发一个基础版本的员工管理系统

文章目录

  • CListCtrl类
  • CFile类
  • 员工管理系统示例代码如下
    • Employer.h 应用主程序的头文件
    • Employer.cpp
    • EmployerDlg.h: 头文件
    • EmployerDlg.cpp: 实现文件
    • CLogin.h: 实现文件
    • CLogin.cpp: 实现文件

CListCtrl类

CListCtrl是MFC中的一个控件类,用于显示列表数据。它继承自CWnd类,并提供了许多功能,如列标题、排序、多选等。下面是CListCtrl常用的函数方法和属性样式。

CListCtrl获取多个选中的方法:
a)GetFirstSelectedItemPosition和GetNextSelectItem。
b)while (++i < nCount) CListCtrl::GetItemState
c)CListCtrl::GetNextItem

CListCtrl::Create 创建一个列表控件并将它附加到 CListCtrl 对象。(不是用对话框资源拖入的)
CListCtrl::CreateEx:加强版的创建(扩展风格)
CListCtrl::DeleteAllItems:删除全部行数据(内部数据结构体是CArray)等价于RemoveAll

 CListCtrl::DeleteItem:删除单行数据

CListCtrl::EditLabel:在项上显示一个编辑框
CListCtrl::GetEditControl:基于以上EditLabel
CListCtrl::GetBkColor和CListCtrl::SetBkColor:设置和获取背景色
CListCtrl::GetBkImage和CListCtrl::SetBkImage:背景图片
CListCtrl::GetCheck和CListCtrl::SetCheck:设置和获取打勾(需要设置扩展风格)

CListCtrl::GetExtendedStyle和CListCtrl::SetExtendedStyle:设置和获取扩展风格

GetFirstSelectedItemPosition:获取选中的多行数据,内部数据结构是单项链表
CListCtrl::GetNextSelectedItem:和以上函数配合形成循环获取所有选中项
CListCtrl::GetSelectedCount:选中的个数

CListCtrl::GetHeaderCtrl:获取表头控件,又是一个类CHeaderCtrl

CListCtrl::GetImageList和CListCtrl::SetImageList:设置和获取列表的图标
CListCtrl::GetItem和CListCtrl::SetItem:设置和获取完整项数据,包括图标,文字,选中状态,隐含数据等。
CListCtrl::GetItemCount和CListCtrl::SetItemCount:获取和设置数据的总行数。

CListCtrl::GetItemData和CListCtrl::GetItemData:获取项内隐含数据

CListCtrl::GetItemRect:获取项的位置(RECT)
CListCtrl::GetSubItemRect:获取某行列的小矩形
CListCtrl::SetItemText和CListCtrl::GetItemText:获取和设置某行列的文字
CListCtrl::SetItemState和CListCtrl::GetItemState:设置和获取项的状态。

CListCtrl::InsertItem:插入一项(包括文字和图标等)
CListCtrl::SortItems和CListCtrl::SortItemsEx:按照某列排序
#define WC_LISTVIEWA            "SysListView32"
#define WC_LISTVIEWW            L"SysListView32"

#ifdef UNICODE
#define WC_LISTVIEW             WC_LISTVIEWW
#else
#define WC_LISTVIEW             WC_LISTVIEWA
#endif

#else
#define WC_LISTVIEW             "SysListView"  	LVS
#endif

// begin_r_commctrl

#define LVS_ICON                0x0000 
#define LVS_REPORT              0x0001
#define LVS_SMALLICON           0x0002
#define LVS_LIST                0x0003
以上是视图格式:大图标,小图标,详细列表等。
#define LVS_TYPEMASK            0x0003
#define LVS_SINGLESEL           0x0004 单选
#define LVS_SHOWSELALWAYS       0x0008
#define LVS_SORTASCENDING       0x0010 正向排序(主要以列表项文字作为规则,多个列时最左测的)
#define LVS_SORTDESCENDING      0x0020 反向排序
#define LVS_SHAREIMAGELISTS     0x0040
#define LVS_NOLABELWRAP         0x0080
#define LVS_AUTOARRANGE         0x0100
#define LVS_EDITLABELS          0x0200 可以编辑的属性(主要以列表项文字作为规则,多个列时最左测的)
#define LVS_OWNERDATA           0x1000 海量列表的属性(当有几亿个数据插入都需要十几分钟)
#define LVS_NOSCROLL            0x2000

#define LVS_TYPESTYLEMASK       0xfc00

#define LVS_ALIGNTOP            0x0000
#define LVS_ALIGNLEFT           0x0800
#define LVS_ALIGNMASK           0x0c00

#define LVS_OWNERDRAWFIXED      0x0400 自绘(在第十章讲解)
#define LVS_NOCOLUMNHEADER      0x4000 在详细资料REPROT模式下多列却没有标头
#define LVS_NOSORTHEADER        0x8000 没有排序标头

CFile类

CFile类是MFC中的一个文件操作类,提供了对文件的读写、查找、定位等操作.
由于对开发的员工系统的数据需要进行本地保存,需要用到CFile类,下面是CFile类的基本方法和打开模式:

1、CFile类的重要方法:
CFile::Open		函数功能:打开一个文件并返回一个文件句柄。
BOOL Open(LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError = NULL);

参数说明:
lpszFileName:要打开的文件名。
nOpenFlags:打开文件的模式。可以是以下几个值之一:
	CFile::modeRead:以只读方式打开文件。
	CFile::modeWrite:以写入方式打开文件。如果文件不存在,则创建一个新文件;如果文件已存在,则截断文件长度为0。
	CFile::modeReadWrite:以读写方式打开文件。如果文件不存在,则创建一个新文件;如果文件已存在,则保留原文件内容。
	CFile::modeCreate:创建一个新文件并以写入方式打开它。如果文件已存在,则截断文件长度为0。
	CFile::modeNoTruncate:不截断现有文件的长度。
	CFile::shareCompat:允许其他进程打开文件。
	CFile::shareExclusive:不允许其他进程打开文件。
pError:一个指向CFileException异常对象的指针,用于接收打开文件过程中可能出现的错误信息。

返回值:打开文件是否成功。CFile::Open:内部封装CreateFile产生句柄记录在m_hFile;


CFile::Close:内部CloseHandle 关闭文件

CFile::Read:内部ReadFile	函数功能:从文件中读取指定数量的字节,并将它们存储在缓冲区中。
UINT Read(void* lpBuf, UINT nCount);

参数说明:
lpBuf:指向接收数据的缓冲区的指针。
nCount:要读取的字节数。
返回值:实际读取的字节数。

CFile::Write:内部WriteFile	函数功能:将指定数量的字节从缓冲区写入文件中。
void Write(const void* lpBuf, UINT nCount);

参数说明:
lpBuf:指向要写入文件的数据的缓冲区的指针。
nCount:要写入的字节数。

CFile::Seek		函数功能:移动文件指针到指定位置。
LONG Seek(LONG lOff, UINT nFrom);

参数说明:
lOff:要移动的字节数。如果nFrom是CFile::begin,则此参数是从文件开头算起的字节数;如果nFrom是CFile::current,则此参数是相对于当前文件指针的字节数;如果nFrom是CFile::end,则此参数是从文件结尾算起的字节数。
nFrom:指定从哪个位置开始移动文件指针。可以是以下值之一:
	CFile::begin:从文件开头计算。
	CFile::current:从当前文件指针位置计算。
	CFile::end:从文件结尾计算。
返回值:新的文件指针位置。

CFile打开模式:
以下打开模式可以通过按位或(|)的方式一起使用,来达到更灵活的文件操作效果。例如,可以使用
CFile::modeReadWrite | CFile::shareExclusive的方式打开一个文件,实现独占方式的读写操作。

//表示如果文件不存在则创建文件,如果文件存在则清空文件内容并写入新数据
modeCreate|modeWrite联合等价于fopen("wb")模式 

modeRead :等价于"rb"模式

以下是打开的一些模式:
enum OpenFlags {
		modeRead =         (int) 0x00000,	以只读方式打开文件。
		modeWrite =        (int) 0x00001,	以只写方式打开文件。如果文件已经存在,将会清除文件内容,如果文件不存在,则会创建一个新的文件。
		modeReadWrite =    (int) 0x00002,	以读写方式打开文件。如果文件不存在,则会创建一个新的文件。
		shareCompat =      (int) 0x00000,
		shareExclusive =   (int) 0x00010,	独占方式打开文件,其他程序无法访问已经打开的文件
		shareDenyWrite =   (int) 0x00020,	拒绝其他程序读取已经打开的文件。
		shareDenyRead =    (int) 0x00030,	拒绝其他程序写入已经打开的文件。
		shareDenyNone =    (int) 0x00040,	允许其他程序读写已经打开的文件。
		modeNoInherit =    (int) 0x00080,
#ifdef _UNICODE
		typeUnicode =      (int) 0x00400, // used in derived classes (e.g. CStdioFile) only
#endif
		modeCreate =       (int) 0x01000,	创建一个新的文件。如果文件已经存在,则会清除文件内容。
		modeNoTruncate =   (int) 0x02000,	打开一个已经存在的文件,但不清除文件内容,可以在文件末尾追加新的数据。
		typeText =         (int) 0x04000, // used in derived classes (e.g. CStdioFile) only
		typeBinary =       (int) 0x08000, // used in derived classes (e.g. CStdioFile) only
		osNoBuffer =       (int) 0x10000,
		osWriteThrough =   (int) 0x20000,
		osRandomAccess =   (int) 0x40000,
		osSequentialScan = (int) 0x80000,
		};

提示:以下是本篇文章正文内容,下面案例可供参考

员工管理系统示例代码如下

Employer.h 应用主程序的头文件

#pragma once
#ifndef __AFXWIN_H__
	#error "在包含此文件之前包含 'pch.h' 以生成 PCH"
#endif
#include "resource.h"		// 主符号

class CEmployerApp : public CWinApp
{
public:
	CEmployerApp();

public:
	virtual BOOL InitInstance();

	DECLARE_MESSAGE_MAP()
};
extern CEmployerApp theApp;

Employer.cpp

#include "pch.h"
#include "framework.h"
#include "Employer.h"
#include "EmployerDlg.h"
#include "CLogin.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif

BEGIN_MESSAGE_MAP(CEmployerApp, CWinApp)
	ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()
CEmployerApp::CEmployerApp()
{
	m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;
}

CEmployerApp theApp;// 唯一的 CEmployerApp 对象
	
BOOL CEmployerApp::InitInstance()// CEmployerApp 初始化
{
	CWinApp::InitInstance();
	CLogin  LogDlg;
	if (IDCANCEL == LogDlg.DoModal())
		return false;	

	CEmployerDlg dlg;
	m_pMainWnd = &dlg;
	INT_PTR nResponse = dlg.DoModal();
	return FALSE;
}

EmployerDlg.h: 头文件

#pragma once
struct SData
{
	//CString sNumb;//指针变量 这里面存的是指针的地址,而不是内容 不能这样用
	int nNumb;
	TCHAR sName[20];
	float fSalary;
	TCHAR sDate[20];
};
class CEmployerDlg : public CDialogEx	// CEmployerDlg 对话框
{
// 构造
public:
	CEmployerDlg(CWnd* pParent = nullptr);	// 标准构造函数
	int CheckNumb(CString str);
	void Load();

#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_MAIN_DIG };// 对话框数据  类向导通过这个去关联
#endif
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持
protected:
	HICON m_hIcon;
	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnPaint();
	DECLARE_MESSAGE_MAP()
public:
	afx_msg void OnClickedAdd();
	afx_msg void OnClickedDel();
	afx_msg void OnClickedModeify();
	afx_msg void OnBnClickedSave();
};

EmployerDlg.cpp: 实现文件

#include "pch.h"
#include "framework.h"
#include "Employer.h"
#include "EmployerDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CEmployerDlg 对话框 弹出对话框用的

CEmployerDlg::CEmployerDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_MAIN_DIG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CEmployerDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CEmployerDlg, CDialogEx)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_ADD, &CEmployerDlg::OnClickedAdd)
	ON_BN_CLICKED(IDC_DEL, &CEmployerDlg::OnClickedDel)
	ON_BN_CLICKED(IDC_MODEIFY, &CEmployerDlg::OnClickedModeify)
	ON_BN_CLICKED(IDC_SAVE, &CEmployerDlg::OnBnClickedSave)
END_MESSAGE_MAP()

// CEmployerDlg 消息处理程序

BOOL CEmployerDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	auto pList = (CListCtrl*)GetDlgItem(IDC_LIST);
	pList->InsertColumn(0, L"工号", LVCFMT_CENTER, 120);
	pList->InsertColumn(1, L"姓名", LVCFMT_CENTER, 120);
	pList->InsertColumn(2, L"工资", LVCFMT_CENTER, 130);
	pList->InsertColumn(3, L"入职日期", LVCFMT_CENTER, 180);
	pList->SetExtendedStyle(LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT); //Extended List-View Styles列表控件的额外样式
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标
	Load();
	// TODO: 在此添加额外的初始化代码

	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CEmployerDlg::OnPaint()
{
		CPaintDC dc(this); // 用于绘制的设备上下文
}
int CEmployerDlg::CheckNumb(CString str)
{
	auto pList = (CListCtrl*)GetDlgItem(IDC_LIST);
	int nCount = pList->GetItemCount();
	while (nCount--)
	{
		if (pList->GetItemText(nCount, 0) == str)
			return nCount;  //0代表第一个 3 代表第四个
	}
	return -1; //代表不存在
}

void CEmployerDlg::OnClickedAdd() //首先获取列表控件 对编辑框中的文字进行获取 插入到列表控件 
{//通过GetItemCount来获取当前列表视图控件项的数目 依次排序
	auto pList = (CListCtrl*)GetDlgItem(IDC_LIST);
	CString str;
	GetDlgItemText(IDC_NUMB, str);
	int nIndex = CheckNumb(str);
	if (nIndex >= 0)
	{
		MessageBox(L"你输入的工号已存在,请重新输入", L"提示");
		return;
	}
	int nCount = pList->GetItemCount();
	pList->InsertItem(nCount,str);
	GetDlgItemText(IDC_NAME, str);
	pList->SetItemText(nCount, 1, str);
	GetDlgItemText(IDC_SALARY, str);
	pList->SetItemText(nCount, 2, str);
	GetDlgItemText(IDC_DATETIME, str);
	pList->SetItemText(nCount, 3, str);
	OnBnClickedSave();
}
void CEmployerDlg::OnClickedDel()
{
	auto pList = (CListCtrl*)GetDlgItem(IDC_LIST);
	int nCount = pList->GetSelectedCount();
	if (nCount<=0)
	{//::MessageBox 加了::就是强制指定全局变量和函数的用法 参数全部添上
	 // 不加::的话默认靠this这个句柄来
		MessageBox(L"请先选中一行再进行删除");  
		return;
	}
	auto pos = pList->GetFirstSelectedItemPosition();
	while (pos)
	{
		int nItem = pList->GetNextSelectedItem(pos);
		CString str = pList->GetItemText(nItem, 0);
		str += L" ";
		str += pList->GetItemText(nItem, 1);
		str += L" ";
		str += pList->GetItemText(nItem, 2);
		if (IDYES == MessageBox(str+ L"\r\n你确定要删除吗?", L"提示", MB_YESNO))
		{
			pList->DeleteItem(nItem);
		}
	}
	OnBnClickedSave();
}


void CEmployerDlg::OnClickedModeify()
{
	auto pList = (CListCtrl*)GetDlgItem(IDC_LIST);
	auto pos = pList->GetFirstSelectedItemPosition();
	if(!pos)
	{ 
		MessageBox(L"请先选中一行再进行修改");
		return;
	}
	if (IDYES == MessageBox(L"\r\n你确定要修改吗?", L"提示", MB_YESNO))
	{
		CString str;
		int nItem = pList->GetNextSelectedItem(pos);
		GetDlgItemText(IDC_NUMB, str);
		pList->SetItemText(nItem, 0, str);
		GetDlgItemText(IDC_NAME, str);
		pList->SetItemText(nItem, 1, str);
		GetDlgItemText(IDC_SALARY, str);
		pList->SetItemText(nItem, 2, str);
		GetDlgItemText(IDC_DATETIME, str);
		pList->SetItemText(nItem, 3, str);
	}
	OnBnClickedSave();
}

void CEmployerDlg::Load()
{
	CFile file;
	if (!file.Open(L"./Data.txt", CFile::modeRead))
	{
		MessageBox(L"打开文件失败");
		return;
	}

	SData d;
	CString str;
	auto pList = (CListCtrl*)GetDlgItem(IDC_LIST);
	pList->DeleteAllItems();
	int i = 0;
	while (file.Read(&d,sizeof(d)) ==sizeof(d))
	{
		str.Format(L"%d", d.nNumb);
		pList->InsertItem(i, str);
		pList->SetItemText(i, 1, d.sName);
		str.Format(L"%g", d.fSalary);
		pList->SetItemText(i, 2,str);
		pList->SetItemText(i, 3, d.sDate);
		++i;
	}
	file.Close();
}
void CEmployerDlg::OnBnClickedSave()
{
	CFile file;
	if (!file.Open(L"./Data.txt", CFile::modeCreate | CFile::modeWrite))
	{
		MessageBox(L"打开文件失败");
		return;
	}
	auto pList = (CListCtrl*)GetDlgItem(IDC_LIST);
	int i = -1, nCount = pList->GetItemCount();
	SData d;
	while (++i<nCount)
	{
		d.nNumb = _tstoi(pList->GetItemText(i, 0));//CString 的核心是WCAHR* pData; operatot LPCTSTR
		wcscpy_s(d.sName,pList->GetItemText(i, 1));
		d.fSalary = (float)_tstof(pList->GetItemText(i, 2));
		wcscpy_s(d.sDate, pList->GetItemText(i, 3));
		file.Write(&d, sizeof(d));
	}

	file.Close();//可以不用执行,因为有析构函数
}

CLogin.h: 实现文件

#pragma once
#include "afxdialogex.h"

class CLogin : public CDialogEx		// CLogin 对话框
{
	DECLARE_DYNAMIC(CLogin)

public:
	CLogin(CWnd* pParent = nullptr);   // 标准构造函数
	virtual ~CLogin();

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_LOGIN_DLG };
#endif

protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

	DECLARE_MESSAGE_MAP()
public:
	afx_msg void OnBnClickedOk();
};

CLogin.cpp: 实现文件

#include "pch.h"
#include "Employer.h"
#include "afxdialogex.h"
#include "CLogin.h"

IMPLEMENT_DYNAMIC(CLogin, CDialogEx)

CLogin::CLogin(CWnd* pParent /*=nullptr*/)	// CLogin 对话框
	: CDialogEx(IDD_LOGIN_DLG, pParent)
{

}

CLogin::~CLogin()
{
}

void CLogin::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CLogin, CDialogEx)
	ON_BN_CLICKED(IDOK, &CLogin::OnBnClickedOk)
END_MESSAGE_MAP()

void CLogin::OnBnClickedOk()	// CLogin 消息处理程序
{
	CString sName, sPass;
	GetDlgItemText(IDC_USERNAME, sName);
	GetDlgItemText(IDC_PASS, sPass);
	if (sName=="abc"&&"123"==sPass)
	{
		EndDialog(IDOK);
		return;
	}
	else
	{
		MessageBox(L"你的账号或者密码输入错误,请重新输入。");
		SetDlgItemText(IDC_USERNAME, L"");
		SetDlgItemText(IDC_PASS, L"");
		GetDlgItem(IDC_USERNAME)->SetFocus();
	}
		//CDialogEx::OnOK();
}

你可能感兴趣的:(MFC开发,mfc,c++,开发语言)