Duilib 源码分析之 COptionUI 篇

COptionUI 继承自 CButtonUI, 按钮的各个状态会显示不同的文字颜色啊、背景图片啊什么的这个就不再介绍了,每个版本的 Duilib 对 COptionUI 的状态支持可能不同,大家参考一下自己的代码就可以了。这部分内容也可以看一下 Duilib 源码分析之 CButtonUI 篇。 这篇帖子中着重介绍一下 COptionUI 自己的特色的功能

  • bool m_bSelected
  • CDuiString m_sGroupName

以上两个成员变量相关处理是体现 COptionUI 功能的部分。

bool COptionUI::Activate()
{
    if( !CButtonUI::Activate() ) return false;
    if( !m_sGroupName.IsEmpty() ) Selected(true);
    else Selected(!m_bSelected);

    return true;
}
  • m_sGroupName 不为空的情况下,点击当前单选按钮相当于选中它,也就是说有一组单选按钮的情况下。
  • m_sGroupName 为空,代表此单选按钮不与其他单选按钮为一组,此时此单选按钮的作用其实是相当于一个 Checkbox ,每点击一次就切换一次当前的选中状态。
void COptionUI::Selected(bool bSelected, bool bTriggerEvent)
{
    if( m_bSelected == bSelected ) return;
    m_bSelected = bSelected;
    if( m_bSelected ) m_uButtonState |= UISTATE_SELECTED;
    else m_uButtonState &= ~UISTATE_SELECTED;

    if( m_pManager != NULL ) {
        if( !m_sGroupName.IsEmpty() ) {
            if( m_bSelected ) {
                CDuiPtrArray* aOptionGroup = m_pManager->GetOptionGroup(m_sGroupName);
                for( int i = 0; i < aOptionGroup->GetSize(); i++ ) {
                    COptionUI* pControl = static_cast<COptionUI*>(aOptionGroup->GetAt(i));
                    if( pControl != this ) {
                        pControl->Selected(false, bTriggerEvent);
                    }
                }
                if (bTriggerEvent) m_pManager->SendNotify(this, DUI_MSGTYPE_SELECTCHANGED);
            }
        }
        else {
            if (bTriggerEvent) m_pManager->SendNotify(this, DUI_MSGTYPE_SELECTCHANGED);
        }
    }

    Invalidate();
}
  1. 第一行,当选中状态就是当前的状态直接退出,这种情况发生在你单击某一个分组内的一个已经是选中状态的单选按钮时
  2. m_sGroupName.IsEmpty()false 时,注意此时会调用 m_pManager->GetOptionGroup(m_sGroupName) 来获取同组内的所有按钮,将当前按钮设置为选中状态且将其他按钮设置为非选中状态。我认为这里的 if( m_bSelected ) 判断是多余的,因为在组名非空的情况下,调用 Select 函数时 m_bSelected 必然为 true

接下来我们看一下这个所谓的 CStdPtrArray* CPaintManagerUI::GetOptionGroup(LPCTSTR pStrGroupName) 函数。根据组名获取此组内的所有控件。关于 COptionUI 的组名的处理有两种场合:

  1. 设置了 group 属性时,初始化控件时
  2. 后续通过主动修改 SetGroup

好,接下来看一下 SetGroup 的代码

void COptionUI::SetGroup(LPCTSTR pStrGroupName)
{
    if( pStrGroupName == NULL ) {
        if( m_sGroupName.IsEmpty() ) return;
        m_sGroupName.Empty();
    }
    else {
        if( m_sGroupName == pStrGroupName ) return;
        if (!m_sGroupName.IsEmpty() && m_pManager) m_pManager->RemoveOptionGroup(m_sGroupName, this);
        m_sGroupName = pStrGroupName;
    }

    if( !m_sGroupName.IsEmpty() ) {
        if (m_pManager) m_pManager->AddOptionGroup(m_sGroupName, this);
    }
    else {
        if (m_pManager) m_pManager->RemoveOptionGroup(m_sGroupName, this);
    }

    Selected(m_bSelected);
}

不知道大家有没有发现这段代码的问题。我在第一次读到这个代码的时候,就对最后调用 m_pManager->RemoveOptionGroup 的条件产生了疑问,于是就看了下手头另外一个版本的 Duilib 代码,发现是一模一样的。其实这里是有个小 bug 的,但是几乎不会影响我们平时的使用。因为几乎谁也不会主动调用 SetGroup 去修改一个单选按钮的组名为空对吧。

问题就出在传入参数为空的情况下,大家想想,此时调用者的目的是要将当前按钮从原来所属的组内移除。但是由于 m_sGroupName.Empty() 调用的时机过早,导致调用 m_pManager->RemoveOptionGroup 时传入的组名为空,这样的话就导致这个函数根本没有起到作用嘛。 之后再对原来组内的其他单选按钮进行控制时,会同时将当前按钮设置非选中状态,呃呃呃。 所以我们需要做的就是在传入参数为空的情况下,先从组内移除,再设置 m_sGroupName 为空。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
duilib是一个开源的C++图形界面库,它提供了丰富的控件和布局管理功能,以及良好的跨平台支持。下面我将对duilib源码进行简要分析。 1. 基础架构:duilib源码采用了模块化的设计,主要分为“Core”和“UI”两个部分。其中,“Core”模块是duilib的核心部分,提供了基础的窗口、消息循环等功能;而“UI”模块则提供了各种控件和布局管理等高级功能。 2. 控件类别:duilib提供了丰富的控件类别,包括基础的窗口类(如窗口、对话框)、容器类(如水平布局、垂直布局)、常用控件类(如按钮、文本框)、自定义控件类等。每个控件类都有相应的成员函数和消息处理函数,以便实现对控件的创建、设置属性和处理事件等操作。 3. 消息处理机制:duilib使用了消息映射的机制来处理控件的事件。每个控件类都有自己的消息映射表,用于将消息和相应的处理函数关联起来。当控件接收到特定的消息时,duilib会根据映射表找到对应的处理函数进行处理。 4. 布局管理:duilib提供了灵活且强大的布局管理功能,可以通过设置布局属性实现控件的自动适应和自动排列。布局管理器可以根据指定的规则对子控件进行自动布局,以适应不同的窗口尺寸。 5. 绘制引擎:duilib使用了自定义的绘制引擎来实现界面绘制。该绘制引擎可以根据控件的属性和状态来决定绘制的方式,以实现不同的视觉效果。 总结来说,duilib源码分析涉及到基础架构、控件类别、消息处理机制、布局管理和绘制引擎等方面。通过深入研究这些内容,我们可以更好地理解duilib的设计理念和工作原理,以便能够更好地使用和定制duilib提供的功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值