这个文档会教你怎么样自定义一个自己样式的窗口,不要长得和操作系统原生的样。这时有定制样式,功能,比如关闭,最大化,最小化。还有点击什么位置能让程序拖动。
为什么需要自定义窗口头部?
默认情况下,操作系统会为应用程序窗口提供标准的标题栏。但在许多情况下,您可能希望:
- 品牌化: 让窗口外观与您的应用程序设计保持一致。
- 添加自定义控件: 在标题栏中加入搜索框、工具栏按钮或其他 UI 元素。
- 独特的视觉风格: 创建一个完全自定义的、非标准的窗口外观。
Sciter.js 提供了强大的机制,让您可以使用 HTML 和 CSS 完全控制窗口的外观和行为。
核心概念:window-frame="extended"
要开始自定义窗口头部,最关键的一步是在您主 HTML 文件的根 <html>
元素上设置 window-frame="extended"
属性。这告诉 Sciter 您将自己绘制窗口的非客户区(包括标题栏和边框)。
html
<html window-frame="extended" window-width="800px" window-height="600px">
<head>
<title>我的自定义窗口</title>
<style src="window.css" />
<script type="module" src="main.js" />
</head>
<body>
<!-- 窗口内容 -->
</body>
</html>
使用 HTML 构建头部结构
设置 window-frame="extended"
后,您需要使用 HTML 元素来定义窗口头部的结构。通常,这会放在 <body>
标签之前,或者作为 <body>
的第一个子元素(取决于您的布局)。一个常见的结构是使用 <header>
元素。
关键在于使用特定的 role
属性来告诉 Sciter 哪些元素扮演标准窗口控件的角色:
-
role="window-caption"
: 必需。指定一个元素作为窗口标题栏。用户可以通过拖动此元素来移动窗口。 -
role="window-icon"
: (可选)指定一个元素作为窗口图标。在 Windows 上,单击此图标通常会显示窗口菜单。 -
role="window-minimize"
: (可选)使元素表现为最小化按钮。 -
role="window-maximize"
: (可选)使元素表现为最大化/还原按钮。 -
role="window-close"
: (可选)使元素表现为关闭按钮。重要提示 : 当用户点击带有
role="window-minimize"
,role="window-maximize"
, 或role="window-close"
属性的元素时,Sciter 会自动处理相应的窗口操作(最小化、最大化/还原、关闭),您通常不需要为此编写额外的 JavaScript 事件处理代码。
示例 HTML 结构:
html
<header>
<img role="window-icon" src="images/my-icon.svg" />
<window-caption role="window-caption">我的应用程序标题</window-caption>
<window-buttons>
<window-button role="window-minimize"></window-button>
<window-button role="window-maximize"></window-button>
<window-button role="window-close"></window-button>
</window-buttons>
</header>
在这个例子中:
- 我们使用
<header>
作为容器。 - 一个
<img>
标签用作窗口图标。 - 一个
<window-caption>
(或任何其他元素,如<span>
,<div>
)用作可拖动的标题区域。 - 一个
<window-buttons>
容器(通常是<div>
或自定义元素)包含标准的窗口控制按钮。 <window-button>
(通常是<button>
或自定义元素)扮演最小化、最大化和关闭的角色。 注意这些也可以直接写进 css 的类当中,也是相当的方便。
使用 CSS 设计头部样式
一旦有了 HTML 结构,您就可以使用 CSS 来完全控制头部的外观。
关键 CSS 属性和技术:
- 布局 (
flow: horizontal
) : 通常,头部元素(图标、标题、按钮)是水平排列的。flow: horizontal;
是实现这一点的常用方法。 - 高度 (
height: window-caption-height
) : Sciter 提供了一个 CSS 变量window-caption-height
,它代表了操作系统标准标题栏的高度。使用它可以让您的自定义头部具有合适的高度。 - 宽度 (
width: *
) : 对于像标题这样需要填充可用空间的元素,width: *;
(星号宽度) 非常有用。 - 背景和颜色 : 使用
background-color
,color
等标准 CSS 属性来设置背景和文本颜色。 - 按钮样式 :
- 大小 :
width: window-button-width;
可以用来获取标准按钮宽度。 - 图标 : 使用
foreground-image
(对于 Sciter 的矢量图标路径) 或background-image
来设置按钮图标。 - 描边/填充 (
stroke
,fill
) : 对于矢量图标,使用stroke
和fill
来控制颜色。 - 悬停效果 (
:hover
): 定义鼠标悬停在按钮上时的样式变化(例如,改变背景色)。
- 大小 :
- 平台特定样式 (
@media platform
) : 您可以使用@media
查询来为不同操作系统(如 Windows, Linux, OSX)应用不同的样式。
使用 JavaScript 自定义行为 (可选)
虽然 Sciter 会自动处理带有 role="window-..."
属性的元素的默认行为(最小化、最大化、关闭),但在某些高级场景下,您可能希望通过 JavaScript 完全控制这些按钮的点击事件。例如,在关闭窗口前显示一个确认对话框。
为此,您可以:
- 不使用
role
属性 : 如果您想完全接管,可以不在按钮上设置role="window-close"
等属性。 - 添加事件监听器 : 使用 JavaScript 为您的按钮元素(例如,通过 ID 或 class 选择)添加
click
事件监听器。 - 调用窗口 API: 在事件处理函数中,调用相应的 Sciter 窗口 API 来执行所需的操作。
示例:自定义关闭按钮
假设您的关闭按钮 HTML 是:
html
<button id="my-close-button">关闭</button>
您的 sciter.js 中的 JS 代码可以这样写:
javascript
on["click", "button#my-close-button"], (evt) {
// 阻止可能的默认行为(如果设置了 role)
// event.stopPropagation(); // 通常不需要,除非 role 存在且引起冲突
// 显示确认对话框
const confirmed = Window.this.modal(<alert caption="确认">确定要关闭窗口吗?</alert>);
if (confirmed) {
Window.this.close(); // 调用关闭窗口 API
}
});
类似地,您可以使用以下 API 来自定义其他按钮:
- 最小化 :
Window.this.state = Window.WINDOW_MINIMIZED;
- 最大化/还原 : 通过检查当前状态
Window.this.state
(例如Window.WINDOW_MAXIMIZED
) 来决定是最大化 (Window.this.state = Window.WINDOW_MAXIMIZED;
) 还是还原 (Window.this.state = Window.WINDOW_RESTORED;
)。
注意: 如果您选择使用 JavaScript 处理事件,请确保您的逻辑覆盖了所有必要的窗口状态管理。
完整示例
这是使用 sciter.js 写的微信一样的头部。
下面是一个将前面讨论的概念整合在一起的微信风格的自定义 GUI 的软件头部的完整示例。
html
<!DOCTYPE html>
<html window-frame="extended" window-width="800px" window-height="600px" window-corners="not-round" >
<head>
<meta charset="UTF-8">
<title>微信</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Microsoft YaHei", sans-serif;
}
html {
border-radius: 0px;
}
body {
background-color: #f5f5f5;
}
.container {
flow: horizontal;
height: *;
}
.sidebar {
width: 60px;
background-color: #2c2c2c;
height: 100%;
flow: vertical;
content-horizontal-align: center;
padding-top: 20px;
}
.avatar {
width: 50px;
height: 50px;
border-radius: 4px;
overflow: hidden;
background-color: #555;
text-align: center;
line-height: 50px;
font-size: 35px;
}
.main {
width: 1*;
flow: vertical;
}
.header {
height: 56px;
background-color: #f6f6f6;
border-bottom: 1px solid #e0e0e0;
flow: horizontal;
padding: 0 10px;
position: relative;
}
.search-area {
flow: horizontal;
vertical-align: middle;
width: 340px;
}
.search-container {
flow: horizontal;
align-items: center;
background-color: #e6e6e6;
border-radius: 4px;
padding: 4px 10px;
width: 300px;
height: 24px;
}
.search-icon {
color: #999;
margin-right: 8px;
font-size: 16px;
}
.search-input {
background: none;
border: none;
outline: none;
width: 1*;
color: #999;
font-size: 12px;
}
.add-button {
width: 24px;
height: 24px;
border-radius: 4px;
background-color: #e6e6e6;
border: none;
margin-left: 10px;
font-size: 16px;
cursor: pointer;
text-align: center;
line-height: 24px;
color: #666;
}
.divider {
width: 0.5px;
height: 100%;
background-color: #e0e0e0;
margin: 0 20px;
}
.user-info {
color: #333;
font-weight: bold;
font-size: 16px;
width: 1*;
padding-left: 20px;
line-height: 56px;
min-width: 200px;
role: window-caption;
/* 按这块就可以拖动 */
}
.controls-container {
flow: vertical;
}
.window-controls {
margin-top: 8px;
flow: horizontal;
}
.control-button {
background: none;
border: none;
cursor: pointer;
size: 16px;
margin-left: 15px;
margin-right: 5px;
stroke: #666;
}
.control-button:hover {
stroke: #333;
}
.control-button:nth-child(1) {
role: window-minimize;
foreground-image: url(icon:window-minimize);
}
.control-button:nth-child(2) {
role: window-maximize;
foreground-image: url(icon:window-maximize);
}
.control-button:nth-child(3) {
role: window-close;
foreground-image: url(icon:window-close);
}
.control-button:nth-child(3):hover {
stroke: #ff0000;
}
.more-button-container {
margin-top: 4px;
margin-right: 10px;
text-align: right;
}
.more-button {
background: none;
border: none;
cursor: pointer;
size: 16px;
stroke: #666;
foreground-image: url(icon:opts-h);
foreground-size: 18px;
margin-left: *;
}
.more-button:hover {
stroke: #333;
}
</style>
</head>
<body>
<div class="container">
<div class="sidebar">
<div class="avatar">
👨
</div>
</div>
<div class="main">
<div class="header">
<div class="search-area">
<div class="search-container">
<span class="search-icon">🔍</span>
<input type="text" class="search-input" placeholder="搜索">
</div>
<button class="add-button">+</button>
</div>
<div class="divider"></div>
<div class="user-info">凯哥1970</div>
<div class="controls-container">
<div class="window-controls">
<button class="control-button"></button>
<button class="control-button"></button>
<button class="control-button"></button>
</div>
<div class="more-button-container">
<button class="more-button"></button>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
最佳实践
- 保持简洁: 除非绝对必要,否则不要在标题栏中添加过多的交互元素,以免让用户混淆。
- 明确可拖动区域 : 确保
role="window-caption"
的元素足够大且易于点击和拖动。 - 提供标准控件 : 除非您的 UI 设计有充分理由省略它们,否则应始终提供最小化、最大化和关闭按钮,并赋予它们正确的
role
。 - 使用 CSS 变量 : 利用 Sciter 提供的变量(如
window-caption-height
,window-button-width
,window-accent-color
)来适应系统设置。 - 分离关注点: 将 HTML 结构、CSS 样式和 JavaScript 行为分别放在不同的文件中,以提高可维护性。
- 测试: 在目标平台上测试您的自定义头部,确保外观和行为符合预期。
总结
通过在 <html>
标签上设置 window-frame="extended"
,并结合使用带有特定 role
属性的 HTML 元素和 CSS 样式,您可以完全控制 Sciter.js 应用程序窗口的外观。这为您提供了创建美观、品牌化和功能丰富的用户界面的能力。
查阅 Sciter SDK 中的示例(特别是 samples.sciter/window/chrome-types/
和 demos/usciter/
目录下的示例)以获取更多灵感和实现细节。