MFC登录系统
第一步、建立一个框架结构工程
选择其它语言中的Visual C++,在中间视图中选择MFC应用程序,下面的名称中输入工
程名称GzyOa,解决方案名称是你的工程目录名可以使用默认的工程名也可以修改成自己好记的名称。点击确定。
下一步
我们选择“多个文档”“选项卡式文档”,我们不用文档视图,所以将下面的“文档/视图结构支持(V)”复选框去掉,点击完成。
这样就完成了工程的创建。
第二步,建立登录对话框。
选择“类视图”导航栏,点击右键选择“类向导”。
选择添加类
类名CLogin基类为CDialog点击完成。在类视图中找到刚建的类,点右键
选择“转到”对话框(D)
制作如下对话框。(确定改为“登录”,取消改为“退出”,增加“设置”按钮。)
鼠标放在第一个编辑框点右键,选添加变量m_editName
同法定义第二个编辑框变量为m_editPassWord,同时将其属性Password设置为True,并在其头文件中手动添加两个变量:
public:
CString cName;
CString cPass;
双击登录按钮添加如下代码:
void CLogin::OnBnClickedOk()
{
m_editName.GetWindowTextW (cName);
m_editPassWord.GetWindowTextW(cPass);
CDialog::OnOK();
}
这里是把编辑框的内容传给public变量,以便于主程序存储登录信息,这里以后还要添加认证代码。(这是后话)
在类视图中找到CGzyOaApp类(程序入口)修改InitInstance()函数,使用程序先启动对话框后再启动框CMainFrame。方法如下:
1.为CGzyOaApp类添加两个对应变量(用于接收登录窗口的用户信息)
CString m_strSqlName;
CString m_strSqlPassword;
2.先在CGzyOaApp类的源文件头添加
#include"Login.h"
3.找到InitInstance()函数定义(向下翻)添加如下代码:红色部分
BOOL CGzyOaApp::InitInstance()
{
INITCOMMONCONTROLSEX InitCtrls;
InitCtrls.dwSize = sizeof(InitCtrls);
InitCtrls.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&InitCtrls);
CWinAppEx::InitInstance();
if (!AfxOleInit())
{
AfxMessageBox(IDP_OLE_INIT_FAILED);
return FALSE;
}
AfxEnableControlContainer();
EnableTaskbarInteraction();
SetRegistryKey(_T("应畖用?程ì序ò向ò导?生Θ?成é的?本?地?应畖用?程ì序ò"));
InitContextMenuManager();
InitKeyboardManager();
InitTooltipManager();
CMFCToolTipInfo ttParams;
ttParams.m_bVislManagerTheme = TRUE;
theApp.GetTooltipManager()->SetTooltipParams(AFX_TOOLTIP_TYPE_ALL,
RUNTIME_CLASS(CMFCToolTipCtrl), &ttParams);
CLogin m_login;
if (m_login.DoModal ()==IDOK)
{
m_strSqlName=m_https://www.doczj.com/doc/ce16558244.html,ame ;
m_strSqlPassword=m_login.cPass ;
CMDIFrameWnd* pFrame = new CMainFrame;
if (!pFrame)
return FALSE;
m_pMainWnd = pFrame;
if (!pFrame->LoadFrame(IDR_MAINFRAME))
return FALSE;
HINSTANCE hInst = AfxGetResourceHandle();
m_hMDIMenu = ::LoadMenu(hInst, MAKEINTRESOURCE(IDR_GzyOaTYPE));
m_hMDIAccel = ::LoadAccelerators(hInst, MAKEINTRESOURCE(IDR_GzyOaTYPE));
CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
return FALSE;
m_pMainWnd = pMainFrame;
pMainFrame->ShowWindow(m_nCmdShow);
pMainFrame->UpdateWindow();
}
return TRUE;
}
这样就完成了登录过程的修改,但对话框还太单调,这里我们使用绘图方法添加标题等信息,方法如下:
在类视图中找到对话框类CLogin,点右键,选择类向导。添加消息响应函数
代码如下:
void CLogin::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: 在此处添加消息处理程序代码
// 不为绘图消息调用CDialog::OnPaint()
// CPaintDC dc(this);
CRect rc;
CPen pen;
GetClientRect(&rc); //获取客户其大小
int nHeight=rc.Height();
int i ,j;
for(i=255,j=0;nHeight>=0;nHeight--,j++)
{
pen.CreatePen(PS_SOLID,1,RGB(255,i,i));//创建画笔
//通过改变RGB()函数的参数可以改变背景颜色,经过复杂的算法可以画出很复杂的背景图
CPen *pOldPen=dc.SelectObject(&pen);
dc.MoveTo(rc.left,j); //将比尖移到起点
dc.LineTo(rc.right,j); //画线到终点
dc.SelectObject(pOldPen);
pen.DeleteObject(); //删除创建的画笔
i=max(0,i-1); //改变颜色值
}
dc.SetTextColor(RGB(255,0,0));
dc.SetBkMode (1);
dc.SetTextColor(RGB(0,0,255));
dc.TextOut(50,92,L"用户:");
dc.TextOut(50,132,L"密码:");
CFont font;
VERIFY(font.CreatePointFont(200,_T(""), &dc));
CFont* def_font = dc.SelectObject(&font);
dc.SetTextColor(RGB(10,10,10));
dc.TextOut(20,30,L"浩翔综合无纸办公系统");
dc.SetTextColor(RGB(255,0,0));
dc.TextOut(21,31,L"浩翔综合无纸办公系统");
}
将对话框的Border必为none效果如下:
感觉不美观可以自己重新调整以上语句。
第三步,建立设置SQL或ACCESS数据库连接设置对话框如下:
为控件添加变量如下(在控件中右击添加变量):
CComboBox m_cmbSqlServer;
CEdit m_editName;
CEdit m_editPass;
CComboBox m_editDatabase;
添加函数void DrawGradient(CDC* pDC, const CRect& rect, COLORREF rgbBegin, COLORREF rgbEnd, const int & iStep, const int & iDirection);
代码如下:(渐变填充背景)
void CLinkSet::DrawGradient(CDC* pDC, const CRect& rect, COLORREF rgbBegin, COLORREF rgbEnd, const int & iStep, const int & iDirection)
{
float fStep=iStep;
if(iStep==0)
{
fStep=1.0;
}
UINT nWidth=rect.Width ();
UINT nHeight=rect.Height ();
CRect tempRect;
float fSteps=0;
float nRed=0,nGreen=0,nBlue=0;//定义颜色差
float fRedStep=0.0,fGreenStep=0.0,fBlueStep=0.0;
//得到色差空间
nRed=(GetRValue(rgbEnd)-GetRValue(rgbBegin));
nGreen=(GetGValue(rgbEnd)-GetGValue(rgbBegin));
nBlue=(GetBValue(rgbEnd)-GetBValue(rgbBegin));
//计算分多少步填充
switch(iDirection)
{
case 1:
fSteps=(float)nHeight/fStep;
break;
case 2:
fSteps=(float)nWidth/fStep;
break;
case 3:
case 4:
fSteps=(float)max(nWidth,nHeight);//^(1/2)) /fStep;
break;
default:
fSteps=(float)nHeight/fStep;
break;
}
fRedStep=nRed/fSteps;
fGreenStep=nGreen/fSteps;
fBlueStep=nBlue/fSteps;
nRed=GetRValue(rgbBegin);
nGreen=GetGValue(rgbBegin);
nBlue=GetBValue(rgbBegin);
CPen pen;
switch(iDirection)
{
case 1:
for(int i=0;i<=fSteps;i++)
{
tempRect.SetRect (0,i,nWidth,i+fStep);
nRed+=fRedStep;
nGreen+=fGreenStep;
nBlue+=fBlueStep;
pDC->FillSolidRect (&tempRect,RGB(nRed,nGreen,nBlue));
}
break;
case 2:
for(int i=0;i<=fSteps;i++)
{
tempRect.SetRect (i,0,i+fStep,nHeight);
nRed+=fRedStep;
nGreen+=fGreenStep;
nBlue+=fBlueStep;
pDC->FillSolidRect (&tempRect,RGB(nRed,nGreen,nBlue)); }
break;
default:
for(int i=0;i<=fSteps;i++)
{
nRed+=fRedStep;
nGreen+=fGreenStep;
nBlue+=fBlueStep;
tempRect.SetRect (0,i,nWidth,i+fStep);
pDC->FillSolidRect (&tempRect,RGB(nRed,nGreen,nBlue));
}
break;
}
}
对话框响应WM_ERASEBKGND消息如下:
CRect rect;
GetWindowRect(rect);
DrawGradient(pDC,&rect,RGB(100,186,255),RGB(15,42,255),1,1);
CFont font;
CFont* def_font ;
CPaintDC dc(this);
font.CreatePointFont(130,_T("宋体"), &dc);
def_font = dc.SelectObject(&font);
dc.SetBkMode (1);
dc.SetTextColor(RGB(0,0,0));
dc.TextOut(10,62,L"SQL服务器:");
dc.TextOut(55,94,L"用户名:");
dc.TextOut(55,119,L"密码:");
dc.TextOut(10,195,L"数据库名:");
font.DeleteObject ();
font.CreatePointFont (200,L"宋体",&dc);
def_font = dc.SelectObject(&font);
dc.SetTextColor (RGB(200,0,0));
dc.TextOutW (80,10,L"SQL数据连接设置");
return TRUE;//CDialog::OnEraseBkgnd(pDC);
接下来我们创建一个类,用于获取局域网内的所有SQL数据库服务器名称
在头文件中删掉基类(红色部分)添加如下变量及函数,或者我们在创建类时使用C++类而不是MFC类。
class CGetSqlServer : public CObject
头文件如下:
#pragma once
// CGetSqlServer 命令目标
class CGetSqlServer
{
public:
CGetSqlServer();
virtual ~CGetSqlServer();
BOOL GetServer(DWORD ServerType,CStringArray &mArray);
int m_recordcount;
};
源文件如下:注意lm.h后面的#pragma语句必须有
// GetSqlServer.cpp : 实现文件
//
#include "stdafx.h"
#include "GzyOa.h"
#include "GetSqlServer.h"
#include"afxtempl.h"
#include
#pragma comment(lib, "Netapi32.lib")
// CGetSqlServer
CGetSqlServer::CGetSqlServer()
{
}
CGetSqlServer::~CGetSqlServer()
{
}
/*************************************************
ServerType为枚举项目类别定义如下
#define SV_TYPE_WORKSTA TION 0x00000001
#define SV_TYPE_SERVER 0x00000002
#define SV_TYPE_SQLSERVER 0x00000004
#define SV_TYPE_DOMAIN_CTRL 0x00000008
#define SV_TYPE_DOMAIN_BAKCTRL 0x00000010
#define SV_TYPE_TIME_SOURCE 0x00000020
#define SV_TYPE_AFP 0x00000040
#define SV_TYPE_NOVELL 0x00000080
#define SV_TYPE_DOMAIN_MEMBER 0x00000100
#define SV_TYPE_PRINTQ_SERVER 0x00000200
#define SV_TYPE_DIALIN_SERVER 0x00000400
#define SV_TYPE_XENIX_SERVER 0x00000800
#define SV_TYPE_SERVER_UNIX SV_TYPE_XENIX_SERVER
#define SV_TYPE_NT 0x00001000
#define SV_TYPE_WFW 0x00002000
#define SV_TYPE_SERVER_MFPN 0x00004000
#define SV_TYPE_SERVER_NT 0x00008000
#define SV_TYPE_POTENTIAL_BROWSER 0x00010000
#define SV_TYPE_BACKUP_BROWSER 0x00020000
#define SV_TYPE_MASTER_BROWSER 0x00040000
#define SV_TYPE_DOMAIN_MASTER 0x00080000
#define SV_TYPE_SERVER_OSF 0x00100000
#define SV_TYPE_SERVER_VMS 0x00200000
#define SV_TYPE_WINDOWS 0x00400000 //Windows95 and above
#define SV_TYPE_DFS 0x00800000 //Root of a DFS tree /
#define SV_TYPE_CLUSTER_NT 0x01000000 // NT Cluster //
#define SV_TYPE_TERMINALSERVER 0x02000000 // Terminal Server(Hydra) /
#define SV_TYPE_CLUSTER_VS_NT 0x04000000 // NT Cluster Virtual Server Name /
#define SV_TYPE_DCE 0x10000000 // IBM DSS (Directory and Security Services) or equivalent / #define SV_TYPE_ALTERNATE_XPORT 0x20000000 // return list for alternate transport /
#define SV_TYPE_LOCAL_LIST_ONLY 0x40000000 // Return local list only/
#define SV_TYPE_DOMAIN_ENUM 0x80000000
#define SV_TYPE_ALL 0xFFFFFFFF // handy for NetServerEnum2 / *************************************************/
BOOL CGetSqlServer::GetServer(DWORD ServerType)
{
mArray.RemoveAll ();
LPSERVER_INFO_101 pBuf = NULL;
LPSERVER_INFO_101 pTmpBuf;
DWORD dwLevel = 101;
DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH;
DWORD dwEntriesRead = 0;
DWORD dwTotalEntries = 0;
DWORD dwTotalCount = 0;
DWORD dwServerType = ServerType;//SV_TYPE_SERVER; // all servers
DWORD dwResumeHandle = 0;
NET_API_STATUS nStatus;
LPTSTR pszServerName = NULL;
DWORD i;
nStatus = NetServerEnum(NULL,
dwLevel,
(LPBYTE *) &pBuf,
dwPrefMaxLen,
&dwEntriesRead,
&dwTotalEntries,
dwServerType,
NULL,
&dwResumeHandle);
int j=0;
if ((nStatus == NERR_Success) || (nStatus == ERROR_MORE_DATA))
{
if ((pTmpBuf = pBuf) != NULL)
{
m_recordcount=dwEntriesRead;
for (int i=0; i < dwEntriesRead; i++)
{
if(pBuf!=NULL)
{
//swprintf(m_servername[i],L"%s",pTmpBuf->sv101_name);
mArray.Add (pTmpBuf->sv101_name);
j++;
}
pTmpBuf++;
dwTotalCount++;
}
}
}
if (pBuf != NULL)
NetApiBufferFree(pBuf);
// TODO: Add extra initialization here
return TRUE;
}
// CGetSqlServer 成员函数
再建一个SQL数据库操作类CMySql头文件如下:
#pragma once
#import "C:\Program Files (x86)\Common Files\System\ado\msado15.dll"no_namespace \
rename("EOF","adoEOF")rename("BOF","adoBOF")
// CMySql 命令目标
class CMySql
{
public:
CMySql();
virtual ~CMySql();
//添加一个指向Connection对象的指针
_ConnectionPtr m_pConnection;
//添加一个指向Recordset对象的指针
_RecordsetPtr m_pRecordset;
_RecordsetPtr& GetRecordSet(_bstr_t bstrSQL);
void ExitConnect();
void OnInitADOConn();
public :
BOOL GetDatabaseName( CStringArray &mArray);
void OnInitADOConn(CString strServer, CString strUser, CString strPass, CString strDatabase); };
源文件如下:
// MySql.cpp : 实现文件
//
#include "stdafx.h"
#include "GzyOa.h"
#include "MySql.h"
#include "afxtempl.h"
// CMySql
CMySql::CMySql()
{
}
CMySql::~CMySql()
{
}
void CMySql::OnInitADOConn()
{
::CoInitialize (NULL);
try
{
//Data Source=192.168.1.186;Initial Catalog=GzyOa;Persist Security Info=True;User ID=sa;Password=***********Data Source=192.168.1.186;Initial Catalog=GzyOa;Persist Security Info=True;User ID=sa CString SerIp=_T("192.168.1.186");
CString user=_T("sa");
CString password=_T("clsedit");
CString strConnect;
strConnect.Format(_T("DRIVER={SQL
SERVER};SERVER=%s;Database=master;uid=%s;pwd=%s;"),SerIp,user,password);
//创建connection对象
m_pConnection.CreateInstance ("ADODB.Connection");
////设置连接字符串
//_bstr_t strConnect="Provider=SQLOLEDB.1;Integrated Security=192.168.1.186;UID=sa;PWD=clsedit;datebase=master";
m_pConnection->Open((_bstr_t)strConnect,"","",adModeUnknown);
}
catch(_com_error e)
{
AfxMessageBox(e.Description ());
}
}
void CMySql::ExitConnect()
{
if (m_pRecordset!=NULL)
m_pRecordset->Close();
m_pConnection->Close();
::CoUninitialize();
}
_RecordsetPtr& CMySql::GetRecordSet(_bstr_t bstrSQL)
{
try
{
if(m_pConnection==NULL)
OnInitADOConn();
m_pRecordset.CreateInstance(__uuidof(Recordset));
m_pRecordset->Open(bstrSQL,m_pConnection.GetInterfacePtr(),adOpenDynamic,adLockOptimistic,adCmdText);
}
catch(_com_error e)
{
e.Description();
}
return m_pRecordset;
}
BOOL CMySql::GetDatabaseName(CStringArray &mArray)
{
int i=mArray.GetCount() ;
if(i!=4)
{
mArray.RemoveAll();
return FALSE;
}
CString strServer=mArray.GetAt (0);
CString strUser=mArray.GetAt (1);
CString strPass=mArray.GetAt (2);
CString strDatabase=mArray.GetAt (3);
mArray.RemoveAll();
if(m_pConnection!=NULL)
m_pConnection->Close ();
OnInitADOConn(strServer,strUser,strPass,strDatabase);
if(m_pConnection==NULL) return FALSE;
CString sql;
sql.Format(L"select name from sysdatabases order by name");
try
{
m_pRecordset=GetRecordSet((_bstr_t)sql);//m_pConnection->Execute(_T("select* from sysdatabases"),NULL,adCmdText);//获取记录集
if(m_pRecordset!=NULL)
{
if(m_pRecordset->adoEOF != V ARIANT_TRUE)
{
m_pRecordset->MoveFirst ();
while(!m_pRecordset->adoEOF)
{
_variant_t vCount = m_pRecordset->GetCollect("name");///取得第一个字段的值放入vCount变量
CString str=(_bstr_t)vCount;
mArray.Add(str);
m_pRecordset->MoveNext ();
}
}
else
{
return 0;
}
}
else
{
return 0;
}
}
catch(_com_error *e)
{
AfxMessageBox(e->ErrorMessage());
}
return 0;
}void CMySql::OnInitADOConn(CString strServer, CString strUser, CString strPass, CString strDatabase)
{
::CoInitialize (NULL);
try
{
CString strConnect;
strConnect.Format(_T("DRIVER={SQL
SERVER};SERVER=%s;Database=%s;uid=%s;pwd=%s;"),strServer,strDatabase,strUser,strPass);
//创建connection对象
m_pConnection.CreateInstance ("ADODB.Connection");
////设置连接字符串
//_bstr_t strConnect="Provider=SQLOLEDB.1;Integrated Security=192.168.1.186;UID=sa;PWD=clsedit;datebase=master";
m_pConnection->Open((_bstr_t)strConnect,"","",adModeUnknown);
}
catch(_com_error e)
{
AfxMessageBox(e.Description ());
}
}
下面我作使用C++类再创建一个文件操作类CMyFile。我们在类视图的最上面右击工程名GzyOa选择添加类。