如何优雅的写UI——(5)选项卡功能实现

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

立马就露出马脚了,所以这篇我们要先讲讲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, -1, -1, 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[2];
    POINT Newp; //获取现在对话框的大小
    CRect recta;
    GetClientRect(&recta);     //取客户区大小
    Newp.x=recta.right-recta.left;
    Newp.y=recta.bottom-recta.top;
    fsp[0]=(float)Newp.x/m_old.x;
    fsp[1]=(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[0]);
        TLPoint.y = long(OldTLPoint.y*fsp[1]);
        OldBRPoint = Rect.BottomRight();
        BRPoint.x = long(OldBRPoint.x *fsp[0]);
        BRPoint.y = long(OldBRPoint.y *fsp[1]);
        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 == 0) 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就完成了。

原文地址:https://www.cnblogs.com/ye-ming/p/9277599.html

时间: 2024-10-05 10:00:15

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

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

现在做出来的选项卡实在太丑的,咱们怎么把他弄得好看一点呢 tabctrl是可以添加icon图标的,那派生与tabctrl的mfctabctrl肯定也能添加图标,他们两个添加图标的原理一样,但是还是有点不同 首先给项目添加三个图标 然后在成员变量中添加ImageList对象,必须要添加在成员变量中,否则加载不出来图片. CImageList m_imglist; 之后在初始化中创建CImageList,他的声明为 BOOL Create(int cx, int cy, UINT nFlags, i

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

窗体创建完成,接下来我们讲讲控件的使用 首先在CFormView窗体下选项卡的成员变量,这里我选择MFC下的选项卡类库:CMFCTabCtrl class CtabView : public CFormView { ...... ...... public: CMFCTabCtrl m_tab; } 在初始化中动态创建选项卡并设置选项卡的样式,这里我们使用了Creat函数,他的原型是 BOOL Create(Style style, const RECT& rect, CWnd* pParent

关于代码手写UI,xib和StoryBoard

代码手写UI 这种方法经常被学院派的极客或者依赖多人合作的大型项目大规模使用.Geek们喜欢用代码构建UI,是因为代码是键盘敲出来的,这样可以做到不开IB,手不离开键盘就完成工作,可以专注于编码环境,看起来很cool很高效,而且不到运行时大家都不知道会是什么样子,也显出了程序员这一职业的高大上及神秘气息(这个真的不是在黑..想想大家一起在设计师背后指点江山的场景吧).大型多人合作项目使用代码构建UI,主要是看中纯代码在版本管理时的优势,检查追踪改动以及进行代码合并相对容易一些. 另外,代码UI可

代码手写UI,xib和StoryBoard间的博弈,以及Interface Builder的一些小技巧

代码手写UI,xib和StoryBoard间的博弈,以及Interface Builder的一些小技巧 最近接触了几个刚入门的iOS学习者,他们之中存在一个普遍和困惑和疑问,就是应该如何制作UI界面.iOS应用是非常重视用户体验的,可以说绝大多数的应用成功与否与交互设计以及UI是否漂亮易用有着非常大的关系.而随着iOS开发发展至今,可以说在UI制作上大家逐渐分化为了三种主要流派:使用代码手写UI及布局:使用单个xib文件组织viewController或者view:使用StoryBoard来通过

停止使用循环 教你用underscore优雅的写代码

你一天(一周)内写了多少个循环了? var i; for(i = 0; i < someArray.length; i++) {   var someThing = someArray[i];   doSomeWorkOn(someThing); } 这当然无害,但这种写法非常丑而且奇怪,这也不是真正需要抱怨的.但这种写法太平庸了. var i,   j; for(i = 0; i < someArray.length; i++) {   var someThing = someArray[i

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

前言 我最近喜欢把写的十分优美的技术文章叫做安利文.首先,文章必须是原创而非软广:其次,阅读之后不仅能快速吸纳技术要点并入门开发,还能感同身受的体会作者热情洋溢的赞美和急于分享心得体验的心情,让人感觉相见恨晚,醍醐灌顶. 安利文基于技术文章但又高于技术文章,同是经验总结,但却因为作者认真的揣摩每一个标点.断句而变得优雅.一篇满是主观感受的文章却不嚼之乏味,作者用心的指出每一个需要注意的技术亮点在文字中如蛟龙戏水,让阅读者大呼过瘾.因此,我觉得能原创分享一篇技术文章精神已经难能可贵,但若能锦上添花

原生js、jQuery实现选项卡功能

在大家在网上平常浏览网页的时候,想必各位都会看到选项卡功能,在这里给大家详解一下用原生js.jQuery如何来写一些基本的选项卡 话不多说,先给各位看一下功能图:              好了,下边开始写代码了: HTML代码: <ul> <li class="click">red</li> <li>blue</li> <li>yellow</li> </ul> <div class

IOS基础UI之(三)手写UI和storyboard方式实现图片移动和缩放

手写UI是最早进行UI界面布局的方法,优点是灵活自由,缺点是使代码看起来比较长.平时学习的时候可以多尝试手写ui,这样会更深入熟悉控件.storyboard开发效率相对比较高.实际开发中看情况而定!! 下面用这两种方式分别实现图片移动和缩放. 功能描述: 1. 界面布局 2.点击相应的按钮,对显示的图片移动.缩放. 效果如下:    掌握点: 一:熟悉代码的描述UIButton属性 1.UIButton状态 UIControlStateNormal          // 正常状态 UICont

用JavaScript实现选项卡功能

--做更好的自己? 用js实现选项卡功能 我们在一些常见的网站中经常看到将很大的内容进行叠加显示,这样就会节省很大的版面,而显示的内容更加丰富,如下淘宝部分截图: 1.仿照以上布局,一个标题标签(我们给它设计五个选项卡标签:公告.规则.论坛.安全.公益,相应的就会有五个一样大小的内容盒子来设计内容)一个内容标签. <div id="title"> <h3 >公告</h3> <h3 >规则</h3> <h3 >论坛&