首页
/ Electron BaseWindow 深入指南:构建与掌控可组合多视图的原生窗口

Electron BaseWindow 深入指南:构建与掌控可组合多视图的原生窗口

2026-09-05 15:46:40作者:段琳惟

Electron 的 BaseWindow 是主进程中最底层的窗口抽象:它不绑定任何 Web 内容,只提供一个原生窗口加一个可自由组合的 contentView,让你用多个 WebContentsView/ImageView 拼出任意布局。读完本文,你将掌握 BaseWindow 的创建、父子/模态窗口、资源管理、全部事件与实例方法、构造选项的默认值与平台差异,并能对照仓库源码理解事件从 C++ 原生层到 JS 层的完整分发链路。

BaseWindow 只能运行在主进程,且必须在 app 模块的 ready 事件发出后才可创建。官方文档也提示:如果窗口只需一个占满整个窗口的视图,BrowserWindow 会是更简单的选择;BaseWindow 的价值在于"一个窗口、多个 Web 视图"的灵活组合。

快速上手:一个窗口承载两个 WebContentsView

下面的完整示例演示了 BaseWindow 的核心用法——把两个网页左右各占一半:

// In the main process.
const { BaseWindow, WebContentsView } = require('electron')

const win = new BaseWindow({ width: 800, height: 600 })

const leftView = new WebContentsView()
leftView.webContents.loadURL('https://electronjs.org')
win.contentView.addChildView(leftView)

const rightView = new WebContentsView()
rightView.webContents.loadURL('https://github.com/electron/electron')
win.contentView.addChildView(rightView)

leftView.setBounds({ x: 0, y: 0, width: 400, height: 600 })
rightView.setBounds({ x: 400, y: 0, width: 400, height: 600 })

要点:win.contentViewBaseWindow 自动创建的内容视图(在 C++ 层构造时通过 View::Create 生成,见 electron_api_base_window.cc),所有子视图通过 addChildView 挂到它下面,再用 setBounds 控制每个子视图在窗口内的位置与尺寸。视图层级机制详见 ViewWebContentsView

父子窗口与模态窗口

通过 parent 选项可以创建子窗口,子窗口始终显示在父窗口之上:

const { BaseWindow } = require('electron')

const parent = new BaseWindow()
const child = new BaseWindow({ parent })

模态窗口(modal window)是一种会禁用父窗口的子窗口,需要同时设置 parentmodal 两个选项:

const { BaseWindow } = require('electron')

const parent = new BaseWindow()
const child = new BaseWindow({ parent, modal: true })

各平台的平台行为差异必须牢记:

  • macOS 上模态窗口以 sheet 的形式附加在父窗口上显示;
  • macOS 上子窗口会跟随父窗口移动保持相对位置,而 Windows 和 Linux 上子窗口不跟随;
  • Linux 上模态窗口的窗口类型会被改为 dialog
  • Linux 上许多桌面环境不支持隐藏模态窗口。

运行时也可以用 win.setParentWindow(parent)(传 null 则变回顶层窗口)、win.getParentWindow()win.getChildWindows() 管理窗口树。

资源管理:WebContentsView 不会自动销毁

这是使用 BaseWindow 最容易踩的坑:把 WebContentsView 加入 BaseWindow 后,关闭窗口不会自动销毁其中的 webContents,必须手动关闭,否则会内存泄漏——这与 BrowserWindow 的行为不同:

const { BaseWindow, WebContentsView } = require('electron')

const win = new BaseWindow({ width: 800, height: 600 })

const view = new WebContentsView()
win.contentView.addChildView(view)

win.on('closed', () => {
  view.webContents.close()
})

注意 closed 事件触发后应移除对窗口对象的所有引用,不再使用它(C++ 层在 OnWindowClosed 中会先标记对象为 destroyed 再发出该事件,见 electron_api_base_window.cc)。

构造选项 BaseWindowConstructorOptions

完整选项定义在 BaseWindowConstructorOptions 结构文档中,这里给出与实战最相关、有默认值的关键项:

选项 默认值 说明
width / height 800 / 600 窗口像素尺寸
x / y 居中 窗口偏移;使用其一必须同时使用另一个
useContentSize false true 时宽高按网页区域计算,实际窗口会因边框略大
minWidth / minHeight 0 最小尺寸约束
maxWidth / maxHeight 无限制 最大尺寸约束
resizable / movable / minimizable / maximizable / closable true 后者四项在 Linux 上未实现(no-op)
focusable true Windows 上设 false 隐含 skipTaskbar: true;Linux 上会使窗口脱离窗口管理器、常驻所有工作区顶层
alwaysOnTop false Wayland(Linux)不支持
fullscreen / fullscreenable / simpleFullscreen false / true / false 全屏相关;macOS 的 simpleFullscreen 使用 Lion 之前的全屏行为
skipTaskbar false macOS、Windows
kiosk false iosk 模式
name 窗口唯一标识,是窗口状态持久化等功能的前提;重复使用未销毁窗口的 name 会抛错
windowStatePersistence 开启跨重启的位置/尺寸/显示模式持久化(实验特性),需配合 name;配置见 WindowStatePersistence
title "Electron" 默认标题;若加载的页面定义了 <title>,此值被忽略
icon 窗口图标;Windows 建议 ICO 格式
show true 创建时是否显示
frame true false 创建无边框窗口
parent / modal null / false 父窗口与模态标记
autoHideMenuBar false Linux、Windows,Alt 键唤起菜单
backgroundColor #FFF 支持 Hex/RGB/RGBA/HSL/HSLA/命名色
hasShadow true 窗口阴影
opacity 0.0–1.0,仅 Windows 与 macOS
transparent false 透明窗口;Windows 上必须无边框才生效,且视图本身也要用 view.setBackgroundColor 设为透明
type 普通窗口 平台相关:Linux 有 desktop/dock/toolbar/splash/notification;macOS 有 desktop/paneltextured 已废弃);Windows 只有 toolbar
titleBarStyle default default/hidden/hiddenInset(macOS)/customButtonsOnHover(macOS,实验)
titleBarOverlay false 启用 Window Controls Overlay
vibrancy / backgroundMaterial macOS 毛玻璃效果 / Windows 11 22H2+ 的 micaacrylic 等背景材质
tabbingIdentifier macOS 原生标签分组,会触发 new-window-for-tab 事件

两个容易忽略的规则:

  1. minWidth/maxWidth 等尺寸约束只约束用户手动操作,不会阻止你在构造函数或 setBounds/setSize 中传入越界尺寸;
  2. title 一旦被 API 显式设置,C++ 构造逻辑会置位 title_set_from_api_ 标记(见 electron_api_base_window.cc),后续页面标题变更不会覆盖它。

实例事件

BaseWindow 是标准的 EventEmitter。在 JS 层,base-window.tsEventEmitter.prototype 设置为 BaseWindow.prototype 的原型,而事件本身全部来自 C++ 层 NativeWindowObserver 回调(见 electron_api_base_window.h 中实现的全部 observer 方法),原生事件经 Emit/EmitEventSoon 转发到 JS。

生命周期事件

close:窗口即将关闭时发出,早于 DOM 的 beforeunload/unload,调用 event.preventDefault() 可取消关闭。实践中通常用渲染进程的 beforeunload 决定是否允许关闭——在 Electron 中只要返回非 undefined 的值就会静默取消关闭(没有浏览器那样的确认弹窗),建议配合 dialog API 让用户确认:

window.onbeforeunload = (e) => {
  console.log('I do not want to be closed')
  e.returnValue = false
}

官方文档特别提示:window.onbeforeunload = handlerwindow.addEventListener('beforeunload', handler) 行为有细微差异,建议总是显式设置 event.returnValue,而不是仅靠返回值。C++ 侧对应 WillCloseWindow:只要 JS 的 close 监听器返回"可取消",就把 prevent_default 置真(见 electron_api_base_window.cc)。

closed:窗口已关闭,收到后应丢弃对窗口对象的引用。

persisted-state-restored:持久化窗口状态(bounds 与 maximized/fullscreen/kiosk 显示模式)恢复完成后发出;仅在构造时启用了 windowStatePersistence 才可能触发。

Windows 会话事件query-session-endevent 携带 WindowSessionEndEventpreventDefault() 可延缓关机/注销/重启,仅在可能丢失用户数据时使用)与 session-end(发出后无法再阻止会话结束),二者见 WindowSessionEndEvent

焦点与显示状态

blurfocus(获得/失去焦点,C++ 层通过 EmitEventSoon 延迟到 UI 任务队列发出)、showhidemaximizeunmaximizeminimizerestore。其中 minimize 在 Wayland 上只有经由客户端装饰(如无边框窗口 Window Control Overlay 的最小化按钮)触发时才会发出,因为 Wayland 目前不支持"最小化"状态。

尺寸与位置事件

  • will-resize(macOS/Windows):参数 eventnewBoundsRectangle)、details.edgeedge 在 Windows 可为 bottom/top/left/right/top-left/top-right/bottom-left/bottom-right;macOS 只有 bottom(纵向缩放)与 right(横向缩放)。preventDefault() 可阻止缩放。仅用户手动缩放时发出,setBounds/setSize 不触发。
  • resize:缩放完成后发出;C++ 实现中该回调还会顺带触发防抖的窗口状态持久化保存(DebouncedSaveWindowState,见 electron_api_base_window.cc)。
  • resized(macOS/Windows):一次缩放动作结束时发出一次;macOS 上带 animate: truesetBounds/setSize 结束也会发出。
  • will-move(macOS/Windows):参数 eventnewBounds;Windows 上 preventDefault() 可阻止移动。仅手动移动时发出。
  • move:移动过程中发出;moved(macOS/Windows):移动完成发出一次,macOS 上它是 move 的别名。

全屏与置顶

enter-full-screenleave-full-screenalways-on-top-changed(参数 eventisAlwaysOnTop)。

平台特有事件

  • app-command(Windows/Linux):媒体键、浏览器命令、鼠标后退键等触发。命令名被小写化、下划线转连字符并去掉 APPCOMMAND_ 前缀,例如 APPCOMMAND_BROWSER_BACKWARD 发出为 browser-backward
const { BaseWindow } = require('electron')

const win = new BaseWindow()
win.on('app-command', (e, cmd) => {
  // Navigate the window back when the user hits their mouse back button
  if (cmd === 'browser-backward') {
    // Find the appropriate WebContents to navigate.
  }
})

Linux 上明确支持的命令只有 browser-backwardbrowser-forward

  • swipe(macOS):三指滑动手势,directionup/right/down/left。该 API 面向旧式 macOS 触控板"内容不随手势移动"的滑动方式,需要在系统设置的触控板"更多手势"中开启"两指或三指滑动"才能正常触发。
  • rotate-gesture(macOS):触控板旋转手势,持续发出直到手势结束;每次的 rotation 是相对上次发出的角度增量,最后一次恒为 0,逆时针为正、顺时针为负。
  • sheet-begin / sheet-end(macOS):窗口打开/关闭 sheet。
  • new-window-for-tab(macOS):用户点击原生新标签按钮时发出,前提是窗口设置了 tabbingIdentifier;必须在该回调里创建新窗口,macOS 的标签功能才能正常工作。
  • system-context-menu(Windows/Linux):用户在非客户端区域(标题栏或无边框窗口的 -webkit-app-region: drag 区域)右键时发出,参数为 event 与屏幕坐标 pointPoint);preventDefault() 可阻止系统菜单显示。屏幕坐标转 DIP 可用 screen.screenToDipPoint(point),见 Screen

静态方法

BaseWindow.getAllWindows() 返回 BaseWindow[],全部已打开的窗口。

BaseWindow.getFocusedWindow() 返回当前应用内聚焦的窗口,否则 null。从源码看它是在 JS 层实现的便利方法——遍历所有窗口找 isFocused() 为真的那一个,见 base-window.ts

BaseWindow.fromId(id) 按整数 id 返回窗口或 nullwin.id 来自 C++ 对象的 weak map 内部 id(GetID()weak_map_id(),见 electron_api_base_window.h),在整个应用的 BaseWindow 实例间唯一。

BaseWindow.clearPersistedState(name) 清除指定 name 窗口的已保存状态(bounds、显示模式、工作区信息)。实现见 electron_api_base_window.cc 与头文件注释:它通过 PrefService 清除 app.getPath('userData') 下 Local State JSON 中的窗口状态;name 为空或状态不存在时会记录警告。

实例属性

win.id(只读整数)与 win.contentViewView 类型,内容视图)外,其余属性大多是"getter/setter 语法糖",在 base-window.ts 中以 Object.defineProperty 逐个映射到同名的 C++ 方法。按用途归纳:

  • 窗口状态fullScreensimpleFullScreen(macOS 的 pre-Lion 全屏)、kioskresizableminimizable/maximizable/closable/movable(后三者 Linux 上 setter 为 no-op、getter 返回 true)、fullScreenable(最大化按钮是切换全屏还是最大化)、shadowfocusable(Windows/macOS)、visibleOnAllWorkspaces(macOS/Linux,Windows 恒 false)、autoHideMenuBar/menuBarVisible(Linux/Windows)。
  • 标题title(原生窗口标题,可与网页标题不同)、accessibleTitle(仅给读屏等无障碍工具的替代标题,用户不可见)。
  • macOS 专属documentEdited(为 true 时标题栏图标变灰)、representedFilename(标题栏显示文件图标)、excludedFromShownWindowsMenu(默认 false,配合 role: 'windowmenu' 的应用菜单使用)、tabbingIdentifier(只读)。
  • Windows 专属snapped(只读,是否通过 Snap 停靠排列)。

实例方法(按功能分组)

内容视图与生命周期

  • setContentView(view) / getContentView():替换或获取窗口的内容视图(View)。
  • close():等效于用户点关闭按钮,网页可取消(走 close 事件)。
  • destroy():强制关闭,不发 unload/beforeunload/close,但保证发出 closed
  • focus() / blur() / isFocused() / isDestroyed()

显示

  • show() / showInactive() / hide() / isVisible() / isModal()
  • maximize() / unmaximize() / isMaximized()maximize 在未显示时会显示但不聚焦窗口)。
  • minimize() / restore() / isMinimized()(某些平台最小化后窗口仍显示在 Dock)。
  • setFullScreen(flag) / isFullScreen():macOS 全屏切换是异步的,若后续操作依赖全屏状态,应监听 enter-full-screen/leave-full-screen 事件。
  • setSimpleFullScreen(flag) / isSimpleFullScreen()(macOS)。
  • isNormal():非最大化、非最小化、非全屏。
  • flashFrame(flag):开始/停止闪烁窗口以吸引注意,macOS 上会持续闪烁 Dock 图标。
  • setSkipTaskbar(skip)(macOS/Windows)、setKiosk(flag) / isKiosk()isTabletMode()(Windows 10 平板模式,可配合 resize 事件监听切换)。

位置与尺寸

  • setBounds(bounds[, animate]):未提供的属性保持当前值,如 win.setBounds({ width: 100 }) 只改宽度;macOS 上 y 不能小于 Tray 高度(约 20–40px)。getBounds() 在 macOS 上返回的 y 至少为 Tray 高度;Wayland 上因协议禁止内省全局坐标,返回 { x: 0, y: 0, ... }
  • setPosition(x, y[, animate]) / getPosition()(Wayland 恒返回 [0, 0])、center()
  • setSize(width, height[, animate]) / getSize():低于最小尺寸约束时会吸附到最小值。
  • setContentBounds(bounds) / getContentBounds() / setContentSize(width, height[, animate]) / getContentSize():针对客户端区域(网页区域)。
  • getNormalBounds():无论当前处于最大化/最小化/全屏什么状态,都返回正常状态下的位置与尺寸。
  • setMinimumSize / getMinimumSize / setMaximumSize / getMaximumSize
  • setAspectRatio(aspectRatio[, extraSize])extraSize 仅 macOS):让窗口维持宽高比,extraSize 指定不参与比例计算的额外像素区域(例如视频播放器周围的控制条);对 setSize 等程序化调整不生效;传 0 重置。
  • 行为开关的 setter/getter 对:setResizablesetMovable(Linux 无效)、setMinimizablesetMaximizablesetFullScreenablesetClosable(以上均 macOS/Windows)、setMenuBarVisibility/isMenuBarVisiblesetAutoHideMenuBar/isMenuBarAutoHide(Linux/Windows)。

外观

  • setBackgroundColor(backgroundColor):接受 Hex(#fff#ffff#ffffff#ffffffff)、rgb()rgba()hsl()hsla() 及大小写敏感的 CSS 命名色;getBackgroundColor()#RRGGBB 返回(不含 alpha)。
  • setHasShadow(hasShadow) / hasShadow() / invalidateShadow()(macOS,透明窗口动画后清除残影)。
  • setOpacity(opacity)(Windows/macOS,越界值会被夹到 [0,1],Linux 无效、getOpacity() 恒 1)。
  • setShape(rects)(Windows/Linux,实验性):给定矩形集合定义允许绘制与鼠标交互的区域,区域外像素不绘制、鼠标事件穿透到下层窗口;传空数组恢复矩形。
  • setTitle(title) / getTitle() / setSheetOffset(offsetY[, offsetX])(macOS sheet 附加点,可在 HTML 工具栏下方)。

层级与 z-order

  • setAlwaysOnTop(flag[, level][, relativeLevel]) / isAlwaysOnTop()level(macOS/Windows)可选 normalfloatingflag 为 true 时的默认值)、torn-off-menumodal-panelmain-menustatuspop-up-menuscreen-saverfloatingstatus 区间显示在 Dock(macOS)/任务栏(Windows)之下,pop-up-menu 及以上显示在其上;relativeLevel(macOS)默认 0,Apple 不建议超过 screen-saver 以上 1 层。Wayland 不支持。
  • moveAbove(mediaSourceId):把窗口移到指定 DesktopCapturerSource id(如 "window:1869:0")之上,id 不存在或类型不符会抛错;getMediaSourceId() 返回本窗口的同格式 id(window:id:other_id,id 在 Windows 为 HWND、macOS 为 CGWindowID、Linux 为 X Window)。
  • moveTop():无条件移到 z-order 顶部(不聚焦)。

Windows 平台方法

  • hookWindowMessage(message, callback) / isWindowMessageHooked(message) / unhookWindowMessage(message) / unhookAllWindowMessages():钩住 WndProc 消息,回调参数为 wParam/lParam Buffer。C++ 实现中事件经 OnWindowMessage 查表分发(见 electron_api_base_window.cc)。
  • setProgressBar(progress[, options]):[0, 1.0] 有效;progress < 0 移除进度条;progress > 1 变为不确定模式。Windows 的 options.mode 可为 none/normal/indeterminate/error/paused(未指定时按 normal);Linux 上通过支持 LauncherEntry D-Bus API 的 dock/任务栏显示,要求 app.setDesktopName.desktop 文件名一致,且不支持不确定模式。
  • setOverlayIcon(overlay, description):任务栏图标右下角 16×16 覆盖层。
  • setThumbarButtons(buttons):任务栏缩略图工具栏按钮,最多 7 个,创建后不能移除但可用空数组清空;每个按钮含 icon(NativeImage)、click、可选 tooltipflagsenabled/disabled/dismissonclick/nobackground/hidden/noninteractive)。
  • setThumbnailClip(region):设置任务栏悬停缩略图的裁剪区域,{ x: 0, y: 0, width: 0, height: 0 } 恢复全窗口。
  • setThumbnailToolTip(toolTip)setAppDetails(options)appId 必须设置否则其余选项无效;relaunchCommandrelaunchDisplayName 必须同时设置)。
  • setAccentColor(accentColor) / getAccentColor():接受 CSS 颜色字符串(alpha 被忽略)、true(用系统强调色)、false(禁用)、null(跟随系统设置);getAccentColor 返回自定义 Hex 颜色或表示跟随系统/禁用的布尔值。
  • isSnapped():是否通过 Snap 停靠(悬停最大化按钮的按钮或拖到屏幕边缘)。
  • setBackgroundMaterial(material):Windows 11 22H2+,auto(默认)/none/mica/acrylic/tabbed,设置系统绘制的背景材质(含非客户端区域后方)。
  • setTitleBarOverlay(options):更新已启用 Window Controls Overlay 的窗口样式,color/symbolColor(CSS 颜色)/height(像素);Linux 上未显式指定 symbolColor 时会自动计算与 color 满足最小可访问对比度的颜色。
  • setIcon(icon):更改窗口图标(Windows/Linux)。

macOS 平台方法

  • previewFile(path[, displayName]) / closeFilePreview():Quick Look 预览文件,路径需为绝对路径(文件扩展名决定内容类型)。
  • setHiddenInMissionControl(hidden) / isHiddenInMissionControl()
  • setRepresentedFilename(filename) / getRepresentedFilename()setDocumentEdited(edited) / isDocumentEdited()
  • setWindowButtonVisibility(visible):红绿灯按钮显隐;setWindowButtonPosition(position) / getWindowButtonPosition():无边框窗口中自定义红绿灯位置,传 null 复位。
  • setVibrancy(type):毛玻璃效果,titlebar/selection/menu/popover/sidebar/header/sheet/window/hud/fullscreen-ui/tooltip/content/under-window/under-page,传 null 或空字符串移除。
  • 原生标签组方法:selectPreviousTab() / selectNextTab() / showAllTabs() / mergeAllWindows() / moveTabToNewWindow() / toggleTabBar() / addTabbedWindow(baseWindow)(均要求启用了原生 tabs)。
  • setAutoHideCursor(autoHide):输入时隐藏光标(构造选项 disableAutoHideCursor 是其初始化入口,C++ 中为 SetAutoHideCursor)。
  • setTouchBar(touchBar):设置 TouchBar 布局(实验性 API,可能在未来版本变更或移除)。

跨平台杂项

  • setEnabled(enable) / isEnabled()setIgnoreMouseEvents(ignore[, options])options.forward 为 true 时把鼠标移动消息转发给 Chromium,使 mouseleave 等事件仍可触发;窗口有焦点时仍会收键盘事件)、setContentProtection(enable) / isContentProtected()(macOS 设 NSWindow sharingType 为 None;Windows 用 SetWindowDisplayAffinity 排除捕获,Win10 2004+ 完全排除、旧版本捕获为黑屏)、setFocusable(focusable) / isFocusable()
  • setMenu(menu) / removeMenu()(Linux/Windows 窗口菜单栏);另外在非 macOS 平台,JS 层会在窗口初始化时自动把 app.applicationMenu 设为窗口菜单以模拟应用菜单(见 base-window.ts)。
  • getNativeWindowHandle():平台原生句柄(Windows HWND / macOS NSView* / Linux Window),以 Buffer 返回。

源码架构:从 JS 事件到原生观察者

BaseWindow 的完整实现链路可以概括为三层,全部可在当前仓库中查证:

  1. JS 包装层lib/browser/api/base-window.tsprocess._linkedBinding('electron_browser_base_window') 取出 C++ 导出的 BaseWindow,继承 EventEmitter,并为 fullScreenkioskshadowtitle 等属性定义语法糖属性,同时实现 getFocusedWindow
  2. C++ 可跟踪对象层electron_api_base_window.hBaseWindow 继承 gin_helper::TrackableObject 并实现 NativeWindowObserver 全部回调(OnWindowBlurOnWindowWillResizeOnWindowQueryEndSession 等)。它持有 std::unique_ptr<NativeWindow>,并持有对 JS 包装对象的全局引用 self_ref_ 防止被提前回收;析构时先 CloseImmediately(),再把原生窗口推迟到下一个 tick 销毁(避免原生代码正在遍历窗口列表时发生重入),见 electron_api_base_window.cc
  3. 原生窗口层NativeWindownative_window.hnative_window.cc)负责各平台窗口行为与状态持久化:SaveWindowState/DebouncedSaveWindowState/FlushWindowState(位于 native_window.h)分别对应立即保存、防抖保存(由 resize/move 事件触发)与关闭前刷盘;窗口关闭时 JS 层的 OnWindowClosed 会调用 FlushWindowState 落盘,随后发出 closed。窗口列表与聚焦查询则依赖 window_list.h 的注册机制。

测试方面,窗口相关的集成验证散布在 spec/api-view-spec.tsspec/api-web-contents-view-spec.ts、spec/api-browser-window-spec.ts 等文件中,公共辅助逻辑(窗口创建与布局断言)集中在 spec/lib/window-helpers.ts

选型小结

  • 需要"一个窗口内多视图自由布局"(分栏、主从面板、嵌入式侧边栏):选 BaseWindow + WebContentsView/ImageView,并记得手动管理 webContents 生命周期;
  • 单一网页占满窗口:直接用 BrowserWindow,它在 BaseWindow 之上(同为 NativeWindowObserver 体系,见 electron_api_browser_window.h)提供了默认 webContents 与自动资源回收;
  • 需要跨重启记住窗口位置/大小/显示模式:给窗口起 name 并开启 windowStatePersistence(实验特性),必要时用 BaseWindow.clearPersistedState(name) 清理状态。

注意:Electron 的内置类无法在用户代码中被子类化(详见 FAQ),BaseWindow 只能通过组合与事件扩展来定制。

登录后查看全文
热门项目推荐
相关项目推荐