QProxyStyle类中drawControl和drawComplexControl函数的区别是什么

QProxyStyle类中drawControl和drawComplexControl函数的区别是什么

drawControldrawComplexControlQProxyStyle(以及所有 QStyle 派生类)中两个关键的绘制函数,它们的区别主要在于绘制的控件复杂度结构

1.核心区别总结

特性 drawControl drawComplexControl
绘制对象 简单控件 复合控件
职责 绘制一个单一的、不可再分的视觉元素。 绘制一个由多个部分(子控件) 组成的复杂控件。
参数关键区别 使用 ControlElement 枚举 使用 ComplexControl 枚举和 SubControl 枚举
类比 画一个简单的图形(如一个图标、一段文字)。 画一个由多个零件组成的机器(每个零件可能需要独立交互)。

2详细解释

2.1. drawControl - 简单控件绘制者

  • 功能: 负责绘制基本的、原子性的UI元素。这些元素通常作为一个整体来交互和绘制。
  • 参数标志 : 使用 QStyle::ControlElement 枚举来指定要绘制哪种简单控件。
    • 例如CE_PushButton(整个按钮),CE_CheckBox(复选框的方框和标签),CE_RadioButtonCE_ComboBoxLabel(组合框的文本区域),CE_MenuItem等。
  • 工作方式 : 函数接收到一个 QStyleOption 和绘图区域 (rect),它就在这个区域内绘制出控件的完整外观。它通常不关心内部更细粒度的部分。

示例 : 当绘制一个 CE_PushButton 时,drawControl 的任务就是根据按钮的状态(按下、悬停、启用等),在给定的矩形内画出整个按钮的背景、边框和文本。


2.2. drawComplexControl - 复合控件绘制者

  • 功能 : 负责绘制结构复杂的控件,这些控件由多个可以独立存在、甚至独立交互的子部件(SubControls) 组成。
  • 参数标志
    1. QStyle::ComplexControl cc : 指定要绘制哪种复合控件。
      • 例如CC_SpinBox(数值调整框),CC_ComboBox(组合框),CC_ScrollBar(滚动条),CC_Slider(滑块)等。
    2. QStyle::SubControl sc : 这是关键区别!它指定了本次调用具体要绘制复合控件的哪一个子部分 。它可以是 SC_All(全部)、SC_None(无)或某个特定部分。
      • 例如 : 对于 CC_SpinBox,其子控件包括:
        • SC_SpinBoxUp(向上按钮)
        • SC_SpinBoxDown(向下按钮)
        • SC_SpinBoxFrame(文本框框架)
        • SC_SpinBoxEditField(文本编辑区域)
  • 工作方式 : 函数首先检查 sc 参数,确定需要绘制哪个子部件。然后,它可能需要计算每个子部件的精确位置(通过 subControlRect 方法),并分别绘制它们。

示例 : 当绘制一个 CC_SpinBox(数值调整框)时,drawComplexControl 可能会被调用多次(或者一次处理多个子控件):

  • 一次调用负责绘制 SC_SpinBoxFrame(背景和边框)。
  • 一次调用负责绘制 SC_SpinBoxUp(向上的箭头按钮)。
  • 一次调用负责绘制 SC_SpinBoxDown(向下的箭头按钮)。
  • 编辑框内的文本可能由 drawControl(CE_LineEditEditField, ...) 负责,这体现了两个函数的协作。

2.3为什么需要这种区分?

这种设计体现了关注点分离的原则:

  1. 效率 : 对于复合控件,Qt不需要每次都重绘整个控件。如果只是鼠标悬停在向上按钮上,可以只重绘 SC_SpinBoxUp 子控件,而不必重绘整个SpinBox,这提高了渲染效率。
  2. 灵活性: 它允许样式对不同部分进行精细控制。你可以轻松地改变滚动条箭头的样式而不影响滑块的样式。
  3. 交互 : 输入事件(如鼠标点击)需要确定用户点击的是复合控件的哪个具体部分。hitTestComplexControl 函数就是利用 SubControl 的概念来判断点击发生在哪个子部件上。
  4. 代码示例对比
c++ 复制代码
// 示例:在自定义QProxyStyle子类中重写这两个函数

void MyStyle::drawControl(ControlElement element, const QStyleOption *opt, QPainter *p, const QWidget *w) const
{
    switch (element) {
        case CE_PushButton:
            // 绘制一个简单的按钮:一个矩形和一些文本
            p->setBrush(opt->palette.button());
            p->setPen(opt->palette.buttonText().color());
            p->drawRect(opt->rect);
            p->drawText(opt->rect, Qt::AlignCenter, static_cast<const QStyleOptionButton*>(opt)->text);
            break;
        default:
            QProxyStyle::drawControl(element, opt, p, w); // 委托给基类
    }
}

void MyStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p, const QWidget *w) const
{
    switch (cc) {
        case CC_SpinBox:
            // opt 现在是 QStyleOptionComplex*,实际上是 QStyleOptionSpinBox*
            const QStyleOptionSpinBox *spinboxOpt = static_cast<const QStyleOptionSpinBox*>(opt);

            // 1. 首先绘制框架 (SC_SpinBoxFrame)
            if (opt->subControls & SC_SpinBoxFrame) {
                QRect frameRect = subControlRect(CC_SpinBox, spinboxOpt, SC_SpinBoxFrame, w);
                p->setBrush(opt->palette.base());
                p->drawRect(frameRect);
            }

            // 2. 绘制向上按钮 (SC_SpinBoxUp)
            if (opt->subControls & SC_SpinBoxUp) {
                QRect upRect = subControlRect(CC_SpinBox, spinboxOpt, SC_SpinBoxUp, w);
                // 绘制一个三角形或其他表示"上"的图形
                drawArrow(UP_ARROW, upRect, p, spinboxOpt->state & State_Enabled);
            }

            // 3. 绘制向下按钮 (SC_SpinBoxDown)
            if (opt->subControls & SC_SpinBoxDown) {
                QRect downRect = subControlRect(CC_SpinBox, spinboxOpt, SC_SpinBoxDown, w);
                // 绘制一个表示"下"的图形
                drawArrow(DOWN_ARROW, downRect, p, spinboxOpt->state & State_Enabled);
            }
            break;
        default:
            QProxyStyle::drawComplexControl(cc, opt, p, w); // 委托给基类
    }
}

3.总结

函数 角色 关键概念
drawControl 画家 负责绘制一个完整的、简单的视觉元素。
drawComplexControl 工程师 负责组装一个复杂的控件,协调并绘制其内部的多个子部件。

简单来说,如果一个控件有多个可以独立操作和绘制的"零件",那么绘制它就用 drawComplexControl;否则,就用 drawControl

相关推荐
用户805533698032 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner2 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz7 天前
QML Hello World 入门示例
qt
xcyxiner10 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner10 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner11 天前
DicomViewer (添加模型类)3
qt
xcyxiner12 天前
DicomViewer (目录调整) 2
qt
xcyxiner12 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
桥田智能14 天前
桥田智能 QT-650S:面向白车身焊装的 800kg 重载快换解决方案
开发语言·qt·系统架构
森G14 天前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt