界面设计学习笔记

初学界面设计,把用到的技巧记录下来。。。

1、  怎样在程序开始的时候让它最大化?自定义窗口大小与标题?

App类里的CApp::InitInstance()中把m_pMainWnd->ShowWindow(SW_SHOW)改成m_pMainWnd->ShowWindow(SW_MAXIMIZE);

MainFramePreCreateWindow中修改为:

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)

{

         if( !CFrameWnd::PreCreateWindow(cs) )

                   return FALSE;

         // TODO: Modify the Window class or styles here by modifying

         //  the CREATESTRUCT cs

         cs.cx=1024;//窗口宽度

         cs.cy=768;//窗口高度,这两处自己添加

 

         cs.style &= ~FWS_ADDTOTITLE;

         cs.lpszName = "TPSDemo";//这两句改变窗口标题

 

         return TRUE;

}

 

2、使用CSplitterWnd类分割窗体,拆分窗体

第一步:打开Visual C++ 6.0,文件—>新建,选择MFC AppWizard(exe),输入工程名test,点确定,然后选择单文档点下一步,第二,第三,第四,第五都点下一步,第六步的时候让我选择每个类的基类,我们把CTestView类的基类改为CFormView,点完成。

第二步:新建一个类,类的类型选择Generic Class,填写名称为CMySplitter,基类我们填CSplitterWnd,点击确定。这个时候我们有可能会遇到一个问题(之所以我说有可能是因为这种情况有时不会发生),那就是当我们点击确定之后有时会弹出一个对话框,说找不到CSplitterWnd.h文件,这个时候我们点确定即可。因为,MFCClasswizard不支持继承CSplitter类。但是,我们这里选择的是Generic Class,而不是MFC,所以可以继承,忽略掉那个提醒即可,不明白原因不要紧,只要记得如果弹出对话框,只要点确定即可。

第三步:在CMainFrame类的头文件最顶部加上#include "MySplitter.h",再在CMainFrame类中声明两个publicCMySplitter型的成员变量,如下:

public:
CMySplitter wndSplitter_horizontal;//
水平分隔条

CMySplitter wndSplitter_erect;//
竖直分隔条

第四步:打开资源视图,新建一个对话框,填写IDIDD_MONITORTOP_FORM,新建一个类,类的类型选择MFC Class,填写名称为CMonitorTopView,基类我们填CFormView,对话框ID我们填写IDD_MONITORTOP_FORM,这样我们就新建了一个以CFormView为基类的视图类CMonitorTopView。类似的,我们再新建另外一个对话框,IDIDD_MONITORRIGHT_FORM,以此再建立一个以CFormView为基类的视图类CMonitorRightView

第五步:重载CMainFrame类的OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)方法。加入代码,具体如下:

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
// TODO: Add your specialized code here and/or call the base class

//
创建一个静态分栏窗口,分为21

if(wndSplitter_horizontal.CreateStatic(this,2,1)==NULL)
return FALSE;

   //
CMonitorTopView视图连接到00列窗格上

   wndSplitter_horizontal.CreateView(0,0,RUNTIME_CLASS(CMonitorTopView),CSize(50,50),pContext);
  
  
    //
将第10列再分开12
    if(wndSplitter_erect.CreateStatic(&wndSplitter_horizontal,1,2,WS_CHILD|WS_VISIBLE, wndSplitter_horizontal.IdFromRowCol(1, 0))==NULL)
   
    return FALSE;
   
     //
CMonitorView类连接到第二个分栏对象的00
     wndSplitter_erect.CreateView(0,0,RUNTIME_CLASS(CMonitorView),CSize(220,220),pContext);
    
     //
CMonitorRightView类连接到第二个分栏对象的01
     wndSplitter_erect.CreateView(0,1,RUNTIME_CLASS(CMonitorRightView),CSize(220,220),pContext);
    
      return TRUE;


//return CFrameWnd::OnCreateClient(lpcs, pContext);
}

第六步:其实,截止到第五步完,我们运行程序就可以出现我图例所实现的样子了,但是现在我们来补充一下改变分隔条的特征,好了,现在你应该知道为什么我们要自己定义一个类,继承自CSplitterWnd了吧,因为我们要修改它的特征,例如改变分隔条的宽度,改变分隔条的颜色,固定分隔条(不让别人拖动)等等。

1、改变分隔条的宽度:在CMySplitter类的构造函数中加入代码,具体如下:

CMySplitter::CMySplitter()
{
m_cxSplitter = 10;    //must >=4 ,
拖动时横向拖动条的宽度

m_cySplitter = 25;     //must >=4 ,
拖动时竖向拖动条的宽度
m_cxBorderShare = 0; //
按下鼠标时横向拖动条的偏移量
m_cyBorderShare = 0; //
按下鼠标时竖向拖动条的偏移量
m_cxSplitterGap= 5; //
静止时横向拖动条的宽度  
m_cySplitterGap= 5; //
静止时横向拖动条的宽度

}

2、固定分隔条(不让别人拖动):锁定切分条的最简单的方法莫过于不让CSplitterWnd类来处理WM_LBUTTONDOWN,WM_MOUSEMOVE,WM_SETCURSOR消息,而是将这些消息交给CWnd窗口进行处理,从而屏蔽掉这些消息。现在我们打开CMySplitter类的头文件,我们手动的添加一些东西(为什么要手动呢?因为,我们选择的是Generic Class),好了,我们来看一下都加入了哪些代码:

class CMySplitter : public CSplitterWnd
{
public:
CMySplitter();
virtual ~CMySplitter();

//以固定分隔条加入的代码

DECLARE_DYNCREATE(CMySplitter)
  
protected:
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);


DECLARE_MESSAGE_MAP()

//以上是固定分隔条加入的代码
};

我们仔细的看一下在DECLARE_DYNCREATE(CMySplitter)DECLARE_MESSAGE_MAP()之间是消息处理的声明,告诉计算机,我们重载了这三个消息处理函数。现在我们在打开CMySplitter类的.cpp文件,在构造函数CMySplitter::CMySplitter()上面加入如下代码:

IMPLEMENT_DYNCREATE(CMySplitter, CSplitterWnd)

BEGIN_MESSAGE_MAP(CMySplitter, CSplitterWnd)
ON_WM_LBUTTONDOWN()
ON_WM_SETCURSOR()
ON_WM_MOUSEMOVE()
END_MESSAGE_MAP()

在程序结尾添加下面的代码:

void CMySplitter::OnLButtonDown(UINT nFlags, CPoint point)
{    
    //
直接返回,不处理

return;
}

BOOL CMySplitter::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{  
    //
当光标进入分割窗口时,不允许改变样子,不处理

return FALSE;
}

void CMySplitter::OnMouseMove(UINT nFlags, CPoint point)
{       

     //CSplitter类的处理改为由CWnd处理
      //CSplitterWnd::OnMouseMove(nFlags, point);
    CWnd::OnMouseMove(nFlags, point);
}

 

3、给对话框加背景图片

(可用WM_PAINT)把下面这段代码加进OnPaint()

   CPaintDC dc(this);

   CBitmap   bitmap;

   //这个IDB_BITMAP1要自己添加

   bitmap.LoadBitmap(IDB_BITMAP1);

   CBrush   brush;  

   brush.CreatePatternBrush(&bitmap);  

   CBrush*   pOldBrush   =   dc.SelectObject(&brush);

   //这些参数可以调整图片添加位置和大小

   dc.Rectangle(0,0,200,200); 

   dc.SelectObject(pOldBrush);

 

4、改变对话框背景颜色,设置CFormView背景色

在需要改变的View中增加变量 CBrush m_Brush;

在构造函数中创建颜色画刷 m_Brush.CreateSolidBrush(RGB(255,0,0)); //在此创建为红色画刷,(255255255)为白色

View添加WM_CTLCOLOR消息

注释掉return hdr;

返回自己的画刷 return m_Brush;

此时FormView的背景被更改

 

5、添加启动画面

利用组件库中的Splash Screen组件实现

  (1)Photoshop等制作启动画面图像,保存为bmp格式。
  (2)Appwizard建一个基于单文档的工程Splash

  (3)在资源中插入位图资源

  打开VC++的资源编辑器,用鼠标右键单击Resources文件夹,选择Import命令,插入所制作的位图。如果位图超过256色,VC会弹出一个对话框,提示位图已经插入但不能在位图编辑器中显示,确定即可。将位图ID改为IDB_SPLASH

  (4)添加Splash Screen控件

  选择菜单“project”/“Add To Project”/“Conponents and Controls”打开对话框,在列表框中双击“Visual C++ Conponents”选项,选择“Splash Screen”控件,然后单击“Insert”
  确认或修改类名和位图资源ID,单击OK确认。

  编译、连接,漂亮的启动画面就显示出来了。

  (5)如果需要改变启动画面的停留时间,就修改SetTimer()函数的第二个参数,默认是750 毫秒。该函数所在位置:

int CSplashWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
 
...
   
// Set a timer to destroy the splash screen.
   SetTimer(1, 750, NULL); //修改第二个参数以调整画面停留时间

   
return 0;
}

6、自定义向导的建立

1、生成一个MFC APPWIZARD 新工程,命名为CustomWizard,Step1 中选择基于Dialog Based样式。在自动生成的Dialog 资源中加入一个按钮IDC_BENGINWIZ 用来启动向导。新建一个对话框 资源,命名为IDC_WIZARD,用来显示自定义向导界面,如图

依次创建向导的每页 的对话框资源,命名为IDD_STEP1IDD_STEP2IDD_STEP3


(图4
2
生成所需要的类

为了方便叙述,表1将所用的类进行了归纳

(表1

类名

基类

说明

CWizard

CDialog

向导的框架

CStep1

CDialog

向导的第一步

CStep2

CDialog

向导的第二步

CStep3

CDialog

向导的第三步

CCustomWizardDlg

CDialog

启动向导

3. CWizard添加要使用的数据结构
为了方便描述,表2列出了使用到的成员变量
(表2

成员变量

类型

说明

rectPage

CRect

每页显示的范围

nPageCount

UINT

页的总数

nCurrentPage

UINT

正在显示的页

nPageLink

PAGELINK*

用来链接所有的页

typedef struct PAGELINK{
UINT nNum;
CDialog* pDialog;
struct PAGELINK* Next;};

nNum为页的编号
pDialog
为页所对应的对话框的指针


4. CWizard
所使用到的函数 添加一个新页到Wizard框架,入口参数为要添加的对话框指针和ID

void CWizard::AddPage(CDialog* pDialog, UINT nID)

{

       struct PAGELINK* pTemp = pPageLink;

       //插入新生成的结点

       struct PAGELINK* pNewPage = new PAGELINK;

       pNewPage->pDialog = pDialog;

       pNewPage->pDialog->Create(nID,this); // 以无模式创建窗口

 

  ASSERT(::IsWindow(pNewPage->pDialog->m_hWnd));

  // 检查每页的样式

  DWORD dwStyle = pNewPage->pDialog->GetStyle();

  ASSERT((dwStyle & WS_CHILD) != 0); // 子窗口

  ASSERT((dwStyle & WS_BORDER) == 0); // 无边界

  // 显示

  pNewPage->pDialog->ShowWindow(SW_HIDE); //先隐藏,需要时再显示

  pNewPage->pDialog->MoveWindow(rectPage);

  //移动对话框到制定位置,rectPage已经初始化了

  pNewPage->Next=NULL;

  pNewPage->nNum=++nPageCount; //计数器加1

  if (pTemp)  //插入到链表

  { //如果不是空链表

       while (pTemp->Next) pTemp=pTemp->Next; // 移动链表末尾

       pTemp->Next=pNewPage;

  }

  else  // 空链表

       pPageLink=pNewPage;  //若是第一个节点

  }

显示的页,入口参数为要显示的某特定页的编码

void CWizard::ShowPage(UINT nPos)

{

  struct PAGELINK* pTemp=pPageLink;

       while(pTemp)

       {

       if(pTemp->nNum==nPos)

       {

              pTemp->pDialog->ShowWindow(SW_SHOW);

       }

  else

              //不显示

              pTemp->pDialog->ShowWindow(SW_HIDE);

  pTemp=pTemp->Next;

  }

  if (nPos>=nPageCount)  //最后一页

  {

       nCurrentPage=nPageCount;

       SetWizButton(2);

       return;

  }

  if (nPos<=1) //首页

  {

       nCurrentPage=1;

       SetWizButton(0);

       return;

  }

  //如果是中间步

  SetWizButton(1);

}

为了与显示统一,需要相应的设置按钮

void CWizard::SetWizButton(UINT uFlag)

{

  GetDlgItem(IDC_CANCEL)->EnableWindow(TRUE);

  GetDlgItem(IDC_PREV)->EnableWindow(TRUE);

  GetDlgItem(IDC_NEXT)->EnableWindow(TRUE);

  GetDlgItem(IDC_FINISH)->EnableWindow(TRUE);

  switch(uFlag)

  {

  case 0: //第一步

       GetDlgItem(IDC_PREV)->EnableWindow(FALSE);

       break;

  case 1: //中间步

       break;

  case 2: //最后一步

       GetDlgItem(IDC_NEXT)->EnableWindow(FALSE);

       break;

  }

}

点击上一步下一步完成取消代码

void CWizard::OnPrev() 

{

  // TODO: Add your control notification handler code here

  ShowPage(--nCurrentPage);

}

void CWizard::OnNext() 

 {

  // TODO: Add your control notification handler code here

  ShowPage(++nCurrentPage);

}

void CWizard::OnFinish() 

{

  // TODO: Add your control notification handler code here

  AfxMessageBox("采用默认值完成向导");

  CDialog::OnOK();

}

void CWizard::OnCancel() 

{

  // TODO: Add your control notification handler code here

  if (AfxMessageBox(IDS_QUIT,MB_OKCANCEL|MB_ICONQUESTION)==IDCANCEL)

       return;

  CDialog::OnCancel();

}

5. 辅助代码,如初始化等

BOOL CWizard::OnInitDialog() 

 {

  CDialog::OnInitDialog();

  //获得每页显示的范围

  CRect Rect1;

  GetWindowRect(&Rect1); // 获得主窗口的位置

  int nCaption = ::GetSystemMetrics(SM_CYCAPTION); // 系统Title高度

  int nXEdge = ::GetSystemMetrics(SM_CXEDGE); 

  int nYEdge = ::GetSystemMetrics(SM_CYEDGE);

  CRect Rect2;

  GetDlgItem(IDC_POS)->GetWindowRect(&Rect2); // 获得框架的位置

  Rect1.top=Rect1.top+nCaption+nYEdge; // 相对坐标

  Rect1.left=Rect1.left+2*nXEdge;

  //计算机位置

  rectPage.top=Rect2.top-Rect1.top;

  rectPage.left=Rect2.left-Rect1.left;

  rectPage.bottom=Rect2.bottom-Rect1.top;

  rectPage.right=Rect2.right-Rect1.left;

 

  //页示的添加要显

  CStep1* pStep1 = new CStep1;

  CStep2* pStep2 = new CStep2;

  CStep3* pStep3 = new CStep3;

 

  AddPage(pStep1, IDD_STEP1);

  AddPage(pStep2, IDD_STEP2);

  AddPage(pStep3, IDD_STEP3);

 

  //显示第一页

  ShowPage(1);

 

  return TRUE;// return TRUE unless you set the focus to a control

  // EXCEPTION: OCX Property Pages should return FALSE

}

因为是无模式窗体,所以要自己销毁窗体

void CWizard::OnDestroy()

{

  CDialog::OnDestroy();

  // TODO: Add your message handler code here

  //每页依次消除

  struct PAGELINK* pTemp=pPageLink;

  while(pTemp)

  {

              struct PAGELINK* pNextTemp = pTemp->Next;

              pTemp->pDialog->DestroyWindow();

              delete pTemp->pDialog;

              delete pTemp;

              pTemp = pNextTemp;

  }

}

6 启动向导需要在IDC_BEGINWIZ 按钮的Click事件中加入下列代码:

CWizard MyWiz; //显示向导

MyWiz.DoModal();

 

 

7、类XP系统按钮的实现

CXPButton类的使用:往对话框中添加一个按钮控件,假设它的ID值为IDC_BUTTON1。进入类向导(Class Wizard)的Member Variables属性页,为IDC_BUTTON1添加一个变量m_btnNormal。确定退出后再进行编译,就可以看到重新定义过XP风格按钮了。



如果你是直接把CXPButton的源文件引入自己的工程中的,那么在上图的Variable type中是看不到CXPButton选项的。但是可以通过以下方法加入:

1. 首先保存工程后退出。
2.
在工程的目录下找到一个后缀名为.clw的文件,将其删除。但是为了以防万一还是建议你实现备份一下。
3.
重新打开工程,进入类向导,此时会看到一下一个弹出对话框,我们选择是(Yes



4.
再选择“Add All”,这样我们就可以在类向导中使用CXPButton的变量类型了。

 

8、使用dll

采用隐式链接法,将*.lib文件放置在工程目录下,*.dll文件放置在输出目录下,在projectàSettingsàLink中的Object/library  modules:下添加所要用到的*.lib名称,如多个用逗号隔开。

9error C2660: 'new' : function does not take 3 parameters改错

错误来自于函数的声明与具体调用不匹配,当代码是复制得来时常出现这样的错误,可将*.cpp*.h中关于此函数的声明同时改为源代码中的声明。

10error C2248: 'CMainFrame::CMainFrame' : cannot access protected member declared in class 'CMainFrame'改错

public,private,protected修饰访问符的作用,错误来自于protectedprivate成员不能在该类域外直接引用,对象不能访问,而public 可以访问,将出错的对象改为public即可

11error C2065: 'IDD_XXXX_DIALOG' : undeclared identifier”的问题

编译vc项目时提示类似“error C2065: 'IDD_XXXX_DIALOG' : undeclared identifier”的问题,可能有两种原因:

第一种是确实不存在该对话框的ID,这种情况下就要把对应的对话框的ID改为正确的;

第二种是存在该对话框,但是找不到,这种情况下可以在类的头文件中加入“#include   "resource.h" ”语句解决;

12、退出SDI

一个基于CFormViewSDI程序,在View上加一个按钮Button1,并在OnButton1中加入下面三句话的任何一句,均可正常退出,没有任何问题:

1AfxGetApp()-> m_pMainWnd-> PostMessage(WM_CLOSE);   //SendMessage

2PostQuitMessage(1);

3ExitProcess(1);

第二种方法当多线程时可能不灵,其他两种方法绝对没问题——除非程序有什么特殊处理。

这里我选择了第三种,可以实现,如果是对话框可用CDialog::OnCancel();来退出,OnOK();也是一种退出的选择,二者分别可查看MSDN

13、错误LNK2001

<File>.obj : error LNK2001: unresolved external symbol "public: void __thiscall <Class1>::<Function1>(<Type>)"

This a generic form of a LNK2001 error where <File>.obj can be any object file in your project and <Class1>::<Function1>(<Type>) can be any function in any class.  Substitute the specific <File>, <Class>, <Function>, and <Type> in your message into the instructions below to diagnose and correct the problem.

An LNK2001 error means that the link editor is looking for a compiled function and can't find it.  The call to the "missing function" is somewhere in <File>.cpp. Unfortunately, double-clicking on the error message won't take you to the point in <File.cpp> where the function is called but you can search for it with Find or Find In Files.  The function the link editor can't find is a member of <Class>, its name is <Function1>, and its return type is <Type>.

There are two common reasons for a LNK2001 error:

1.        The call in <File>.cpp doesn't match the function prototype in <Class>.h and/or the implementation in <Class>.cpp.  The mismatch may be in the function name, return type, or number and/or type of parameters.   Correction strategies include:

o        Check that the function name is spelled the same (case sensitive) in all three files (File.cpp, Class.h, and Class.cpp).

o   Check that the function is actually declared and defined within <Class> - perhaps you defined it as a member of a different class or perhaps you tried to call the function (in <File>.cpp) using an object or object pointer of a different class.

o  Check that the number and type of parameters in the function implementation (in <Class>.cpp) matches the number and type of parameters declared in the function declaration in <Class>.h.

o  Check that the number and type of parameters in the function call (in <File>.cpp) matches the number and type of parameters declared in the function header in <Class>.cpp.

2.        The function was never declared or was declared but never defined.  To see if either is the case go to the ClassView window of the Workspace view.  Click the + next to <Class> and find <Function> in the list of member functions.

o        If <Function> is NOT in the list then it was never declared or defined - add a declaration to the class declaraion in <Class>.h and implement the function in <Class>.cpp.

14、用DECLARE_DYNCREATECMyClass ,编译生成dll时连接出错

解决:需要在相应的实现文件中添加IMPLEMENT_DYNCREATE(CMyClass,基类)

15、待续。。。

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值