Drawer 是 Qt Quick Controls 里的一个抽屉组件,就像手机 App 从屏幕边拉出来的那种侧栏:会从窗口某一条边滑出,同时盖上遮罩。
最常见的就有底部向上弹的菜单、左侧拉开的主菜单、顶部拉下来的通知。至于从哪边出来,由一个表示"边缘"的属性来决定,代码里叫 edge,取四个方向之一。
这篇文章先把这几个关键属性介绍一下,再用四个例子把四个方向的抽屉演示一遍。

基础概念
抽屉最常用的设置就这几个:
edge(边缘,属性) ------告诉抽屉从哪条边滑出来。取值有四个方向:Qt.TopEdge(从上往下)、Qt.RightEdge(从右往左)、Qt.BottomEdge(从下往上)、Qt.LeftEdge(从左往右)。modal(模态,属性) ------设成true表示"模态",抽屉打开时会盖上一层遮罩,遮罩之外的界面点不动,只能先处理完抽屉再关掉。open()/close()(打开 / 关闭,两个方法) ------open()让抽屉弹出、close()收起;另外点击遮罩、按Esc键也会自动关闭。parent: Overlay.overlay(父级,挂在窗口覆盖层上) ------把抽屉挂到窗口最上层的"覆盖层"里。原因后面会讲:这样抽屉的边界才会贴着窗口边缘,而不是被别的容器框住。
qml
import QtQuick
import QtQuick.Controls
Drawer {
parent: Overlay.overlay
width: Overlay.overlay.width
height: 200
edge: Qt.BottomEdge
modal: true
Text { text: "我是底部抽屉"; anchors.centerIn: parent }
}
这个最小例子跑起来后,一个底部抽屉就弹出了:从下往上滑出、带着遮罩、点击别处会自动关闭。剩下的工作,就是往抽屉里填充自己的内容。方向怎么选?经验是:想从顶部拉下一整条(比如消息、公告)用顶部;从底部顶上来一排快捷按钮用底部。
Demo 1 顶部通知抽屉
从顶边滑下一条横贯整个窗口的通知栏,主要展示了五条不同类型的消息------成功、失败、系统消息分别用绿、红、蓝的圆点标出,点任意一条就会收起。

演示代码
qml
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
// 顶部抽屉:消息通知列表(edge: Qt.TopEdge)
Drawer {
id: root
parent: Overlay.overlay // 挂到窗口 overlay,滑动边界即窗口边缘
width: Overlay.overlay.width
height: Math.min(360, Overlay.overlay.height) // 限高:不能比窗口还高
edge: Qt.TopEdge
modal: true
background: Rectangle { color: "#e6e6e6" }
ColumnLayout {
anchors.fill: parent
anchors.margins: 15
spacing: 15
Text { text: "消息通知"; font.pointSize: 13; font.bold: true; color: "#333" }
Rectangle { Layout.fillWidth: true; Layout.preferredHeight: 1; color: "#ccc" }
ListModel {
id: msgModel
ListElement { type: "opt_ok"; msg: "已保存,内容将在刷新后生效" }
ListElement { type: "opt_ok"; msg: "密码已重置,请使用新密码进行登录" }
ListElement { type: "opt_error"; msg: "网络开小差,请连接后重试" }
ListElement { type: "sys"; msg: "新版本可用:V2.3.1,请立即更新体验最新功能" }
ListElement { type: "sys"; msg: "维护通知:系统将于01-22 00:00-02:00升级,期间暂停服务" }
}
Repeater {
model: msgModel
Rectangle {
required property string type
required property string msg
Layout.fillWidth: true
Layout.preferredHeight: 40
color: "#fff"
radius: 6
MouseArea { anchors.fill: parent; onClicked: root.close() }
RowLayout {
anchors.fill: parent
anchors.margins: 10
spacing: 6
Rectangle { // 类型驱动颜色:成功绿 / 失败红 / 系统蓝
Layout.preferredWidth: 16
Layout.preferredHeight: 16
radius: 8
color: {
if (type === "opt_ok") return "#2ecc71"
else if (type === "opt_error") return "#e74c3c"
return "#3498db"
}
}
Text { text: msg; font.pointSize: 11; color: "#333"; Layout.fillWidth: true }
}
}
}
Item { Layout.fillHeight: true }
}
}
关键逻辑解析
这个抽屉挂在窗口最上层的覆盖层里,所以能以整个窗口为参照撑满宽度------就是前面基础概念里那行 parent 设置的作用。高度加了个上限,窗口再小也不会溢出。
每条消息按类型染色:成功的绿色、失败的红色、系统消息用蓝色,扫一眼就能区分。通知类抽屉的语义就是"看一眼就收",点任意一条都会自动收起。
适用场景:消息通知中心、系统公告、下拉式快捷提示。
Demo 2 底部功能抽屉
从底边滑上来一条抽屉,高度是固定的,里面放着一个"常用功能"宫格,每个功能由圆形彩色图标和文字标签组成,点任意一个图标就收起。

演示代码
qml
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
// 底部抽屉:常用功能宫格(edge: Qt.BottomEdge),点击图标即收起
Drawer {
id: root
parent: Overlay.overlay
width: Overlay.overlay.width
height: 200
edge: Qt.BottomEdge
modal: true
background: Rectangle { color: "#e6e6e6"; border.color: "#ccc" }
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
spacing: 20
Text { text: "常用功能"; color: "#333"; font.pointSize: 12; font.bold: true }
RowLayout {
Layout.fillWidth: true
Layout.fillHeight: true
spacing: 20
CustomModel { id: quickModel }
Repeater {
model: quickModel
Rectangle {
required property string cmIcon
required property string cmText
required property string cmColor
Layout.preferredWidth: 64
Layout.preferredHeight: 64
color: "#e6e6e6"
MouseArea { anchors.fill: parent; onClicked: root.close() }
ColumnLayout {
anchors.fill: parent
Rectangle { // 40×40 圆形色块 + 内嵌图标
Layout.preferredWidth: 40
Layout.preferredHeight: 40
radius: 20
color: cmColor
Layout.alignment: Qt.AlignHCenter
Image { source: cmIcon; sourceSize.width: 24; sourceSize.height: 24; anchors.centerIn: parent }
}
Text {
Layout.alignment: Qt.AlignHCenter
text: cmText
color: "#6a6a6a"
font.bold: true
font.pointSize: 11
}
}
}
}
}
Item { Layout.fillHeight: true }
}
}
CustomModel 是共享的数据源组件,提供"图标 + 文本 + 颜色"三字段,左侧/右侧抽屉也复用它:
qml
import QtQuick
ListModel {
ListElement { cmIcon: "qrc:/images/home.svg"; cmText: "首页"; cmColor: "#e74c3c" }
ListElement { cmIcon: "qrc:/images/stats.svg"; cmText: "数据统计"; cmColor: "#3498db" }
ListElement { cmIcon: "qrc:/images/user.svg"; cmText: "用户管理"; cmColor: "#2ecc71" }
ListElement { cmIcon: "qrc:/images/settings.svg"; cmText: "系统设置"; cmColor: "#f39c12" }
ListElement { cmIcon: "qrc:/images/app.svg"; cmText: "应用中心"; cmColor: "#9b59b6" }
ListElement { cmIcon: "qrc:/images/msg.svg"; cmText: "消息通知"; cmColor: "#e67e22" }
}
关键逻辑解析
底部抽屉高度固定,功能项横着排------对比顶部通知是竖着排,从下往上顶上来顺势横向展开,观感上更顺。
每个功能由圆形色块(内嵌小图标)加一行说明上下叠放。图标、文字、颜色这套数据单独存一份,四个方向的抽屉共用,改一处就能同步。快捷入口嘛,点到就关,所以点图标立即收起。
适用场景:移动端底部操作面板、快捷工具宫格、分享菜单。
Demo 3 左侧导航抽屉
从左侧滑出的是一整块深色主菜单。顶部显示用户信息,中间排着几个带图标的导航项,其中"消息通知"还带一个小红点提醒,抽屉外缘则放了一个收起按钮。点中某个导航项,它会高亮选中、把选中的文案告诉外部,再自动收起。

演示代码
qml
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
// 左侧抽屉:主导航菜单(edge: Qt.LeftEdge),选中项信号通知外部
Drawer {
id: root
parent: Overlay.overlay
width: 260
height: Overlay.overlay.height
edge: Qt.LeftEdge
modal: true
property string selectedItem: "首页" // 当前选中项(高亮依据)
signal itemSelected(string text) // 点击菜单项时向外通知
background: Rectangle {
color: "#2c3e50"
// 抽屉外侧的收起把手
Rectangle {
anchors.top: parent.top
anchors.left: parent.right
width: 20
height: 60
color: "#34495e"
Text { anchors.centerIn: parent; text: "收\n起"; wrapMode: Text.Wrap; font.pointSize: 9; color: "white" }
MouseArea { anchors.fill: parent; onClicked: root.close() }
}
}
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
spacing: 10
// 用户信息区域
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 80
color: "transparent"
RowLayout {
anchors.fill: parent
spacing: 10
Rectangle {
Layout.preferredWidth: 50
Layout.preferredHeight: 50
radius: 25
color: "#3498db"
Label { text: "U"; font.pointSize: 16; color: "white"; anchors.centerIn: parent }
}
ColumnLayout {
Layout.fillWidth: true
spacing: 5
Label { text: "用户名"; font.pointSize: 9; color: "white"; font.bold: true }
Label { text: "user@example.com"; font.pointSize: 9; color: "#bdc3c7" }
}
}
}
Rectangle { Layout.fillWidth: true; Layout.preferredHeight: 1; color: "#34495e" }
CustomModel { id: navModel }
Repeater {
model: navModel
Rectangle {
required property string cmIcon
required property string cmText
required property string cmColor
Layout.fillWidth: true
Layout.preferredHeight: 50
color: cmText === root.selectedItem ? "#34495e" : "transparent"
radius: 8
RowLayout {
anchors.fill: parent
anchors.margins: 10
spacing: 20
Rectangle {
Layout.preferredWidth: 30
Layout.preferredHeight: 30
radius: 15
color: cmColor
Image { source: cmIcon; sourceSize.width: 16; sourceSize.height: 16; anchors.centerIn: parent }
}
Label { text: cmText; font.pointSize: 11; color: "white"; Layout.fillWidth: true }
Rectangle { // 红点提醒(仅"消息通知"项显示)
Layout.preferredWidth: 8
Layout.preferredHeight: 8
radius: 4
color: "#e74c3c"
visible: cmText === "消息通知"
}
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
root.selectedItem = cmText // 自己高亮
root.itemSelected(cmText) // 通知外部
root.close() // 自动收起
}
}
Behavior on color { ColorAnimation { duration: 200 } }
}
}
Item { Layout.fillHeight: true }
}
}
关键逻辑解析
左侧这个抽屉沿整个窗口高度铺开、宽度固定,就是一条标准侧边栏的模样。
顶部是圆形头像、用户名和邮箱,下面隔一条细线------这是导航抽屉很常见的用户信息头部。往下是菜单项列表,点哪一项,那行就高亮(切换时带颜色过渡),同时把选中的文案通知给外部,然后自动收起,一套动作下来很顺手。"消息通知"那项旁边多了个小红点,表示有未读消息。
抽屉外缘还贴了个"收/起"小标签,不想点遮罩的时候,点它也能把抽屉收起来。
适用场景:App 主导航菜单、管理后台侧边菜单、需要"用户 + 菜单 + 提醒"一体的侧栏。
Demo 4 右侧设置抽屉
从右侧滑出一块浅色设置面板。顶部是标题和分隔线,下面每一行由彩色圆形图标、设置项名称和右侧的开关组成。它复用了左侧同一套数据,是把"设置页装进抽屉"的典型形态。

演示代码
qml
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
// 右侧抽屉:功能设置(edge: Qt.RightEdge),条目带开关
Drawer {
id: root
parent: Overlay.overlay
width: 280
height: Overlay.overlay.height
edge: Qt.RightEdge
modal: true
background: Rectangle { color: "#e6e6e6"; border.color: "#ccc" }
ColumnLayout {
anchors.fill: parent
anchors.margins: 15
spacing: 15
Text { text: "功能设置"; font.pointSize: 13; font.bold: true; color: "#333" }
Rectangle { Layout.fillWidth: true; Layout.preferredHeight: 1; color: "#ccc" }
CustomModel { id: settingsModel }
Repeater {
model: settingsModel
Rectangle {
required property string cmIcon
required property string cmText
required property string cmColor
Layout.fillWidth: true
Layout.preferredHeight: 50
color: "#f5f5f5"
radius: 6
RowLayout {
anchors.fill: parent
anchors.margins: 10
spacing: 10
Rectangle {
Layout.preferredWidth: 30
Layout.preferredHeight: 30
radius: 15
color: cmColor
Image { source: cmIcon; sourceSize.width: 16; sourceSize.height: 16; anchors.centerIn: parent }
}
Label { text: cmText; font.pointSize: 11; color: "#333"; Layout.fillWidth: true }
Switch { checked: true }
}
}
}
Item { Layout.fillHeight: true }
}
}
关键逻辑解析
右侧抽屉比左侧稍宽,因为每一行要同时放下彩色图标、设置项名称和右侧开关。它和左侧抽屉共用同一份数据,只是渲染成不同形态------左边画成可高亮的导航项,右边画成可拨动的设置行。开关的按下反馈由框架自带,不用额外写;如果想记住开关状态,在状态变化时写回数据就行。
配色上右侧用浅色底、每行圆角卡片,和左侧深色菜单形成"深色导航 / 浅色设置"的对比,也是常见的"左功能、右设置"配色习惯。
适用场景:设置面板、通知偏好、筛选条件等"临时滑出的配置区"。
四个方向对比
| 维度 | 顶部抽屉 | 底部抽屉 | 左侧抽屉 | 右侧抽屉 |
|---|---|---|---|---|
滑出方向(edge) |
Qt.TopEdge(上→下) |
Qt.BottomEdge(下→上) |
Qt.LeftEdge(左→右) |
Qt.RightEdge(右→左) |
| 尺寸形态 | 限高、随窗口 | 固定较矮 | 撑满高度、定宽 | 撑满高度、定宽 |
| 内容方向 | 纵向列表 | 横向宫格 | 纵向菜单 | 纵向设置 |
| 数据源 | 内置 ListModel |
CustomModel |
CustomModel |
CustomModel |
| 色调 | 浅色 | 浅色 | 深色 | 浅色 |
| 交互 | 点消息关闭 | 点图标关闭 | 选中高亮 + 信号 | Switch 开关 |
四个抽屉用的是同一套做法(挂到窗口覆盖层 + 定好尺寸 + 用 Repeater 批量渲染),差别只在滑出方向(edge)、尺寸和内容形态------每个抽屉都独立,可以整体替换。
已验证环境:
- Qt 版本:Qt 6.8.2 / Qt 6.11.1
- 操作系统:Windows 11
- GitHub:QML-Minimal-Demos/qml_drawer