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::GetNextItemCListCtrl::Create 创建一个列表控件并将它附加到 CListCtrl 对象。(不是用对话框资源拖入的)
CListCtrl::CreateEx:加强版的创建(扩展风格)
CListCtrl::DeleteAllItems:删除全部行数据(内部数据结构体是CArray)等价于RemoveAllCListCtrl::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:获取表头控件,又是一个类CHeaderCtrlCListCtrl::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 _UNICODEtypeUnicode =      (int) 0x00400, // used in derived classes (e.g. CStdioFile) only
#endifmodeCreate =       (int) 0x01000,	创建一个新的文件。如果文件已经存在,则会清除文件内容。modeNoTruncate =   (int) 0x02000,	打开一个已经存在的文件,但不清除文件内容,可以在文件末尾追加新的数据。typeText =         (int) 0x04000, // used in derived classes (e.g. CStdioFile) onlytypeBinary =       (int) 0x08000, // used in derived classes (e.g. CStdioFile) onlyosNoBuffer =       (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
#endifBEGIN_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_TIMEenum { IDD = IDD_MAIN_DIG };// 对话框数据  类向导通过这个去关联
#endifprotected: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 LPCTSTRwcscpy_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_TIMEenum { IDD = IDD_LOGIN_DLG };
#endifprotected: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();
}

本文链接:https://my.lmcjl.com/post/5451.html

展开阅读全文

4 评论

留下您的评论.