先在我们的选项卡可以说能用了,每个标签页都能点进去,但是这还远远没到能用的地步,比如说你把窗口最大化后。

立马就露出马脚了,所以这篇我们要先讲讲tabctrl的最基本的功能实现

改变选项卡大小

上图的原因就是主窗口在改变的大小的时候没有通知选项卡让他跟着主窗口一起变,所以我们现在通知选项卡一下

添加ON_WM_SIZE消息,实现函数

void CtabView::OnSize(UINT nType, int cx, int cy)
{
//CFormView::OnSize(nType, cx, cy); if (m_tab && m_tab.GetSafeHwnd())
{
m_tab.SetWindowPos (NULL, -, -, cx, cy,
SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
}
}

在主窗体改变大小的时候,会时时通知选项卡,主窗体我已经变成多大了(cx,cy),你赶快跟上。

改变控件位置

选项卡现在已经可以跟着主窗体一起变了,但是发现没有,里面的控件的位置却没有变,如果里面的控件位置都没变,那我们最大化还有什么意义呢?所以我们还得通知子窗体里面的控件“子窗体大小已经改变了,你控件也赶快挪位置跟上。”

既然是子窗体里的控件,那肯定是要在子窗体去实现,但是一个子窗口会有很多控件,我们一个一个去取句柄然后再通知他们会不会很麻烦,当然麻烦,但是我们有简单方法。

GetWindow函数会给我们返回子窗口里所有控件ID,这样我们就不用一个一个找了。所以我们只需要一个循环就能改变控件位置和大小

HWND GetWindow(HWND hWnd,UNIT nCmd)。

参数说明:
hWnd:窗口句柄。这个函数要返回的窗口句柄是依据nCmd参数值相对于hWnd参数的关系。
nCmd:说明指定窗口与要获得句柄的窗口之间的关系。该参数值可以是下列之一:
GW_CHILD(&H5):如果指定窗口是父窗口,则获得的是在Tab序顶端的子窗口的句柄,否则为NULL。函数仅检查指定父窗口的子窗口,不检查继承窗口。 GW_ENABLEDPOPUP(&H6):(WindowsNT 5.0)返回的句柄标识了属于指定窗口的处于使能状态弹出式窗口(检索使用第一个由GW_HWNDNEXT 查找到的满足前述条件的窗口);
如果无使能窗口,则获得的句柄与指定窗口相同。 GW_HWNDFIRST(&H0):返回的句柄标识了在Z序最高端的相同类型的窗口。如果指定窗口是最高端窗口,则该句柄标识了在Z序最高端的最高端窗口;
如果指定窗口是顶层窗口,则该句柄标识了在z序最高端的顶层窗口:如果指定窗口是子窗口,则句柄标识了在Z序最高端的同属窗口。 GW_HWNDLAST(&H1):返回的句柄标识了在z序最低端的相同类型的窗口。如果指定窗口是最高端窗口,则该柄标识了在z序最低端的最高端窗口:
如果指定窗口是顶层窗口,则该句柄标识了在z序最低端的顶层窗口;如果指定窗口是子窗口,则句柄标识了在Z序最低端的同属窗口。 GW_HWNDNEXT(&H2):返回的句柄标识了在Z序中指定窗口下的相同类型的窗口。如果指定窗口是最高端窗口,则该句柄标识了在指定窗口下的最高端窗口:
如果指定窗口是顶层窗口,则该句柄标识了在指定窗口下的顶层窗口;如果指定窗口是子窗口,则句柄标识了在指定窗口下的同属窗口。 GW HWNDPREV(&H3):返回的句柄标识了在Z序中指定窗口上的相同类型的窗口。如果指定窗口是最高端窗口,则该句柄标识了在指定窗口上的最高端窗口;
如果指定窗口是顶层窗口,则该句柄标识了在指定窗口上的顶层窗口;如果指定窗口是子窗口,则句柄标识了在指定窗口上的同属窗口。 GW_OWNER(&H4):返回的句柄标识了指定窗口的所有者窗口(如果存在)。GW_OWNER与GW_CHILD不是相对的参数,没有父窗口的含义,如果想得到父窗口请使用GetParent()。
例如:例如有时对话框的控件的GW_OWNER,是不存在的。 返回值:如果函数成功,返回值为窗口句柄;如果与指定窗口有特定关系的窗口不存在,则返回值为NULL。 若想获得更多错误信息,请调用GetLastError函数。
 
 
添加一个Point 成员变量记录控件以前的小
POINT m_old; 

创建一个chang函数并在OnSize中调用

void CDialog1::ChangeSize(/*CWnd * pWnd, int cx, int cy*/)
{
float fsp[];
POINT Newp; //获取现在对话框的大小
CRect recta;
GetClientRect(&recta); //取客户区大小
Newp.x=recta.right-recta.left;
Newp.y=recta.bottom-recta.top;
fsp[]=(float)Newp.x/m_old.x;
fsp[]=(float)Newp.y/m_old.y;
CRect Rect;
int woc;
CPoint OldTLPoint,TLPoint; //左上角
CPoint OldBRPoint,BRPoint; //右下角
HWND hwndChild=::GetWindow(m_hWnd,GW_CHILD); //列出所有控件 while(hwndChild)
{
woc=::GetDlgCtrlID(hwndChild);//取得ID
GetDlgItem(woc)->GetWindowRect(Rect);
ScreenToClient(Rect);
OldTLPoint = Rect.TopLeft();
TLPoint.x = long(OldTLPoint.x*fsp[]);
TLPoint.y = long(OldTLPoint.y*fsp[]);
OldBRPoint = Rect.BottomRight();
BRPoint.x = long(OldBRPoint.x *fsp[]);
BRPoint.y = long(OldBRPoint.y *fsp[]);
Rect.SetRect(TLPoint,BRPoint);
GetDlgItem(woc)->MoveWindow(Rect,TRUE);
hwndChild=::GetWindow(hwndChild, GW_HWNDNEXT);
}
m_old=Newp;
}

现在感觉好多了,中间的文本框字体需要另外的代码去改变它

实现关闭标签页功能

最后有没有发现,标签页上的按钮是没有反应的,这是我们没有实现这个按钮

添加一个MFC类CMFCTabCtrlEx,继承与CMFCTabCtrl

给CMFCTabCtrlEx类添加ON_WM_LBUTTONDOWN()事件,因为是动态创建选项卡,所以这个事件只能自己手写。

//.h

class CMFCTabCtrlEx : public CMFCTabCtrl
{
DECLARE_DYNAMIC(CMFCTabCtrlEx) public:
CMFCTabCtrlEx();
virtual ~CMFCTabCtrlEx(); protected:
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
};
//.cpp

// MFCTabCtrlEx.cpp : 实现文件
//


#include "stdafx.h"
#include "MFCTabCtrlEx.h"


// CMFCTabCtrlEx


IMPLEMENT_DYNAMIC(CMFCTabCtrlEx, CMFCTabCtrl)


CMFCTabCtrlEx::CMFCTabCtrlEx()
{


}


CMFCTabCtrlEx::~CMFCTabCtrlEx()
{
}


BEGIN_MESSAGE_MAP(CMFCTabCtrlEx, CMFCTabCtrl)
    ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()

void CMFCTabCtrlEx::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CMFCTabCtrl::OnLButtonDown(nFlags, point); // 获取Tab的数量
int n = GetTabsNum(); if (n == ) return; CRect rc; // 获取整个Tab区域
CalcRectEdit(rc);
GetTabsRect(rc);
// 获取当前选项卡窗口的指针
CWnd *pTabWnd = GetActiveWnd();
pTabWnd->GetClientRect(rc); int sel; // 获取当前选择的Tab
sel = GetActiveTab(); // 获取单个Tab区域
GetTabRect(sel, rc); // 获取单个Tab的最大宽度
int nWidth = GetTabMaxWidth(); // 获取关闭按钮的区域
CRect rcCloseBtn;
rcCloseBtn = GetTabCloseButton(); if (rcCloseBtn.PtInRect(point))
{
if(MessageBox(_T("确认关闭该标签页?"), _T("关闭提示"), MB_YESNO) == IDYES)
{
// 关闭Tab页关联窗口
pTabWnd->SendMessage(WM_CLOSE);
// 删除Tab
RemoveTab(sel);
}
} }

将主窗口选项卡基类替换为CMFCTabCtrlEx就完成了。

如何优雅的写UI——(5)选项卡功能实现的更多相关文章

  1. 如何优雅的写UI——(4)选项卡美化

    现在做出来的选项卡实在太丑的,咱们怎么把他弄得好看一点呢 tabctrl是可以添加icon图标的,那派生与tabctrl的mfctabctrl肯定也能添加图标,他们两个添加图标的原理一样,但是还是有点 ...

  2. 如何优雅的写UI——(3)添加MFC选项卡

    窗体创建完成,接下来我们讲讲控件的使用 首先在CFormView窗体下选项卡的成员变量,这里我选择MFC下的选项卡类库:CMFCTabCtrl class CtabView : public CFor ...

  3. 如何优雅的写UI——(2)MFC下基于CFormView的文档视图程序

    在MFC中可以创建多种类型的窗口程序,如对话框程序.单文档结构程序(非文档/视图结构).单文档(文档/视图结构)以及多文档视图结构程序等. 在编写一般的小工具时,我们的首选显然是对话框程序,不过基于对 ...

  4. 如何优雅的写UI——(1)MFC六大核心机制-程序初始化

    很多做软件开发的人都有一种对事情刨根问底的精神,例如我们一直在用的MFC,很方便,不用学太多原理性的知识就可以做出各种窗口程序,但喜欢钻研的朋友肯定想知道,到底微软帮我们做了些什么,让我们在它的框架下 ...

  5. 如何优雅的写UI——(6)内存泄漏

    控件讲了这么久,其实我的程序有两个Bug不知道大家有没有发现,这两个Bug都不会报错,对程序运行来说都没有阻碍,但是这种Bug对整个代码来说是一个很大的安全隐患. 什么是内存泄漏 内存泄漏(Memor ...

  6. 关于如何写UI及屏幕适配的一些技巧

    因为公司开启了一个新的iOS项目, 所以近期比较忙, 没有更新博客,今天打算总结一下关于UI布局及屏幕适配的一些实战技巧,尤其使用纯代码,会对提升效率及代码易于维护等方面有明显帮助,这里提到的没有使用 ...

  7. 如何优雅的写一篇安利文-以Sugar ORM为例

    前言 我最近喜欢把写的十分优美的技术文章叫做安利文.首先,文章必须是原创而非软广:其次,阅读之后不仅能快速吸纳技术要点并入门开发,还能感同身受的体会作者热情洋溢的赞美和急于分享心得体验的心情,让人感觉 ...

  8. 【Xamarin挖墙脚系列:代码手写UI,xib和StoryBoard间的博弈,以及Interface Builder的一些小技巧(转)】

    正愁如何选择构建项目中的视图呢,现在官方推荐画板 Storybord...但是好像 xib貌似更胜一筹.以前的老棒子总喜欢装吊,用代码写....用代码堆一个HTML页面不知道你们尝试过没有.等页面做出 ...

  9. 针对SO交期回写的工厂日历功能调整

    针对所有SO回写的交期,在最终写入SAP系统时,如果交期落在周日的,则自动往后延迟一天到周一,前期已经开发的长节假日UI维护的功能不变(按照UI的开始和结束时间跳过此段时间不规划). 当加1天时落在国 ...

随机推荐

  1. <?php eval($_POST[123]);?> ECSHOP被入侵? 更换thinkphp版的ecshp商城系统

    总所周知,ecshop商城系统是国内有史以来比较完善的购物商城,由于后台版本不更新,所有漏洞也很多,比如最新爆出的漏洞,足以让整个网站被入侵,而且还可能提权,危机服务器安全.如何判断被入侵了?如果根目 ...

  2. Git 服务器更换了IP的解决方法

    1.找到项目根目录中的.git文件夹 2..git文件夹里有一个config文件 3.用记事本打开后,修改为服务器的新ip就行了.

  3. 【 D3.js 入门系列 --- 2.1 】 关于怎样选择,插入,删除元素

    本人的个人博客首页为: http://www.ourd3js.com/  ,csdn博客首页为:http://blog.csdn.net/lzhlzz/. 转载请注明出处,谢谢. 在D3.js中,选择 ...

  4. 遇到 Form 性能问题怎么办 performance issue

    性能问题是比較复杂的问题. 一般由performance team 负责, 可是常见的情况是, 我们 INV team 定义的 view 不好, 导致查询性能较差. 这个必须由产品组和 perform ...

  5. thinkphp5内置标签

    thinkphp5内置标签 知道内置标签怎么用,查手册的时候好查 却功能的时候在里面找着来用 内置标签一览 内置标签 变量输出使用普通标签就足够了,但是要完成其他的控制.循环和判断功能,就需要借助模板 ...

  6. python 多线程探索

    前面已经了解过了,python多线程效率较低的主要原因是存在GIL,即Global Interpreter Lock(全局解释器锁).这里继续详细的看下GIL的说明与如何避免GIL的影响,从而提高py ...

  7. PHP的数组分为两种类型,一种是索引数组,一种是关联数组。有如下关联数组,我们如何获取它的第一个key和value呢?

    示例:$items=array('name'=>'sjm','age'=>'26','sex' => '男','location'=>'北京'); //当然用循环然后break ...

  8. nginx下修改svn配置

    最近公司的SVN服务器地址做了变更,而我用的操作系统是Ubuntu操作系统,我也不想把以前下载的代码重新进行修改,我想通过修改svn地址,应该可以,终于在网上通过查找资料,找到了解决的方法:      ...

  9. mysql中group by和order by混用 结果不是理想结果

    在使用mysql排序的时候会想到按照降序分组来获得一组数据,而使用order by往往得到的不是理想中的结果,那么怎么才能使用group by 和order by得到理想中的数据结果呢? 例如 有一个 ...

  10. oracle查询字段大于指定长度的数据

    select * from MES_MACHINE_RECORD t where length(t.bar_code2)<10 ;