Appearance
第5章:Electron 窗口操作
5.1 窗口创建与配置
5.1.1 BrowserWindow 参数详解
BrowserWindow 是 Electron 中创建和控制窗口的核心类,它提供了丰富的配置选项来定制窗口的外观和行为。
5.1.1.1 窗口大小与位置
- width:窗口宽度(默认:800)
- height:窗口高度(默认:600)
- x:窗口左上角 x 坐标(默认:居中)
- y:窗口左上角 y 坐标(默认:居中)
- minWidth:窗口最小宽度
- minHeight:窗口最小高度
- maxWidth:窗口最大宽度
- maxHeight:窗口最大高度
5.1.1.2 窗口样式
- frame:是否显示窗口边框和标题栏(默认:true)
- titleBarStyle:标题栏样式('default', 'hidden', 'hiddenInset', 'customButtonsOnHover')
- resizable:是否可调整大小(默认:true)
- maximizable:是否可最大化(默认:true)
- minimizable:是否可最小化(默认:true)
- closable:是否可关闭(默认:true)
- fullscreen:是否全屏(默认:false)
- fullscreenable:是否可进入全屏(默认:true)
- skipTaskbar:是否在任务栏中显示(默认:false)
5.1.1.3 窗口内容
- icon:窗口图标路径
- title:窗口标题
- webPreferences:网页设置对象
5.1.2 窗口创建示例
javascript
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({
// 窗口大小
width: 800,
height: 600,
// 窗口位置
x: 100,
y: 100,
// 窗口样式
frame: true,
titleBarStyle: 'default',
resizable: true,
maximizable: true,
minimizable: true,
closable: true,
// 窗口图标和标题
icon: __dirname + '/assets/icon.png',
title: 'My Electron App',
// 网页设置
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
})
// 加载页面
win.loadFile('index.html')5.2 窗口常用操作
5.2.1 窗口状态控制
5.2.1.1 显示与隐藏
- show():显示窗口
- hide():隐藏窗口
- isVisible():检查窗口是否可见
javascript
// 显示窗口
win.show()
// 隐藏窗口
win.hide()
// 检查窗口是否可见
const isVisible = win.isVisible()
console.log('窗口是否可见:', isVisible)5.2.1.2 最小化与最大化
- minimize():最小化窗口
- maximize():最大化窗口
- unmaximize():取消最大化
- isMinimized():检查窗口是否最小化
- isMaximized():检查窗口是否最大化
javascript
// 最小化窗口
win.minimize()
// 最大化窗口
win.maximize()
// 取消最大化
win.unmaximize()
// 检查窗口状态
const isMinimized = win.isMinimized()
const isMaximized = win.isMaximized()
console.log('窗口是否最小化:', isMinimized)
console.log('窗口是否最大化:', isMaximized)5.2.1.3 关闭窗口
- close():关闭窗口(会触发 close 事件)
- destroy():强制关闭窗口(不会触发 close 事件)
javascript
// 关闭窗口
win.close()
// 强制关闭窗口
win.destroy()5.2.2 窗口大小与位置
- setSize(width, height, animate):设置窗口大小
- getSize():获取窗口大小
- setPosition(x, y, animate):设置窗口位置
- getPosition():获取窗口位置
- center():将窗口居中
javascript
// 设置窗口大小
win.setSize(1000, 700, true) // 第三个参数为是否动画
// 获取窗口大小
const size = win.getSize()
console.log('窗口大小:', size) // [width, height]
// 设置窗口位置
win.setPosition(200, 150, true)
// 获取窗口位置
const position = win.getPosition()
console.log('窗口位置:', position) // [x, y]
// 将窗口居中
win.center()5.2.3 多窗口管理
5.2.3.1 创建多个窗口
javascript
const { BrowserWindow } = require('electron')
// 创建主窗口
const mainWindow = new BrowserWindow({ /* 配置 */ })
// 创建第二个窗口
const secondWindow = new BrowserWindow({
width: 600,
height: 400,
parent: mainWindow, // 设置父窗口
modal: false, // 是否为模态窗口
show: false // 初始隐藏
})
// 加载页面
secondWindow.loadFile('second.html')
// 显示第二个窗口
secondWindow.show()5.2.3.2 管理所有窗口
- BrowserWindow.getAllWindows():获取所有窗口
- BrowserWindow.getFocusedWindow():获取当前聚焦的窗口
javascript
const { BrowserWindow } = require('electron')
// 获取所有窗口
const windows = BrowserWindow.getAllWindows()
console.log('窗口数量:', windows.length)
// 获取当前聚焦的窗口
const focusedWindow = BrowserWindow.getFocusedWindow()
if (focusedWindow) {
console.log('当前聚焦的窗口:', focusedWindow.title)
}5.3 窗口事件
5.3.1 常用窗口事件
- close:窗口关闭时触发
- closed:窗口关闭后触发
- show:窗口显示时触发
- hide:窗口隐藏时触发
- minimize:窗口最小化时触发
- maximize:窗口最大化时触发
- unmaximize:窗口取消最大化时触发
- resize:窗口大小改变时触发
- move:窗口位置改变时触发
- focus:窗口获得焦点时触发
- blur:窗口失去焦点时触发
5.3.2 事件监听示例
javascript
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ /* 配置 */ })
// 监听窗口关闭事件
win.on('close', (event) => {
console.log('窗口即将关闭')
// 可以在这里阻止窗口关闭
// event.preventDefault()
})
// 监听窗口关闭后事件
win.on('closed', () => {
console.log('窗口已关闭')
// 可以在这里清理资源
win = null
})
// 监听窗口显示事件
win.on('show', () => {
console.log('窗口显示')
})
// 监听窗口大小改变事件
win.on('resize', () => {
const size = win.getSize()
console.log('窗口大小改变:', size)
})
// 监听窗口位置改变事件
win.on('move', () => {
const position = win.getPosition()
console.log('窗口位置改变:', position)
})5.4 实操案例:多窗口应用
5.4.1 场景描述
创建一个具有以下功能的多窗口 Electron 应用:
- 主窗口显示应用主界面
- 点击按钮打开设置窗口
- 设置窗口可以独立操作
- 主窗口和设置窗口之间可以通信
- 关闭主窗口时关闭所有窗口
5.4.2 实现步骤
- 修改 main.js
javascript
const { app, BrowserWindow, ipcMain } = require('electron')
const path = require('path')
let mainWindow
let settingsWindow
function createMainWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
icon: path.join(__dirname, 'assets', 'icon.png'),
title: '主窗口',
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
})
mainWindow.loadFile('index.html')
mainWindow.webContents.openDevTools()
// 监听来自渲染进程的消息
ipcMain.on('open-settings', () => {
createSettingsWindow()
})
// 监听窗口关闭事件
mainWindow.on('closed', () => {
// 关闭所有窗口
if (settingsWindow) {
settingsWindow.close()
}
mainWindow = null
})
}
function createSettingsWindow() {
// 如果设置窗口已存在,显示它
if (settingsWindow) {
settingsWindow.show()
return
}
settingsWindow = new BrowserWindow({
width: 600,
height: 400,
parent: mainWindow,
modal: false,
icon: path.join(__dirname, 'assets', 'icon.png'),
title: '设置窗口',
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
})
settingsWindow.loadFile('settings.html')
settingsWindow.webContents.openDevTools()
// 监听窗口关闭事件
settingsWindow.on('closed', () => {
settingsWindow = null
})
// 监听来自设置窗口的消息
ipcMain.on('settings-changed', (event, settings) => {
console.log('设置已更改:', settings)
// 向主窗口发送设置更改消息
if (mainWindow) {
mainWindow.webContents.send('settings-updated', settings)
}
})
}
app.whenReady().then(() => {
createMainWindow()
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createMainWindow()
})
})
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})- 修改 index.html(主窗口)
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>主窗口</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
padding: 0;
background-color: #f0f0f0;
}
.container {
max-width: 700px;
margin: 0 auto;
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
h1 {
color: #333;
text-align: center;
}
button {
padding: 10px 20px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
button:hover {
background-color: #45a049;
}
#settings-info {
margin-top: 20px;
padding: 10px;
background-color: #f9f9f9;
border-radius: 4px;
}
</style>
</head>
<body>
<div class="container">
<h1>主窗口</h1>
<p>这是应用的主窗口,点击下面的按钮打开设置窗口。</p>
<button id="open-settings-btn">打开设置窗口</button>
<div id="settings-info">
<h3>设置信息</h3>
<p>当前设置:默认设置</p>
</div>
</div>
<script>
const { ipcRenderer } = require('electron')
// 打开设置窗口按钮点击事件
document.getElementById('open-settings-btn').addEventListener('click', () => {
ipcRenderer.send('open-settings')
})
// 监听设置更新
ipcRenderer.on('settings-updated', (event, settings) => {
const settingsInfo = document.getElementById('settings-info')
settingsInfo.innerHTML = `
<h3>设置信息</h3>
<p>当前设置:${JSON.stringify(settings)}</p>
`
})
</script>
</body>
</html>- 创建 settings.html(设置窗口)
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>设置窗口</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
padding: 0;
background-color: #f0f0f0;
}
.container {
max-width: 500px;
margin: 0 auto;
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
h1 {
color: #333;
text-align: center;
}
.setting-item {
margin: 15px 0;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input[type="text"], select {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
}
button {
padding: 10px 20px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
margin-top: 20px;
}
button:hover {
background-color: #45a049;
}
</style>
</head>
<body>
<div class="container">
<h1>设置窗口</h1>
<div class="setting-item">
<label for="username">用户名</label>
<input type="text" id="username" value="user123">
</div>
<div class="setting-item">
<label for="theme">主题</label>
<select id="theme">
<option value="light">浅色</option>
<option value="dark" selected>深色</option>
<option value="system">系统</option>
</select>
</div>
<div class="setting-item">
<label for="language">语言</label>
<select id="language">
<option value="zh-CN" selected>中文</option>
<option value="en-US">英文</option>
</select>
</div>
<button id="save-settings">保存设置</button>
</div>
<script>
const { ipcRenderer } = require('electron')
// 保存设置按钮点击事件
document.getElementById('save-settings').addEventListener('click', () => {
const settings = {
username: document.getElementById('username').value,
theme: document.getElementById('theme').value,
language: document.getElementById('language').value
}
// 向主进程发送设置更改消息
ipcRenderer.send('settings-changed', settings)
// 显示保存成功提示
alert('设置已保存')
})
</script>
</body>
</html>- 创建资源文件夹和图标
- 创建
assets文件夹 - 添加
icon.png(应用图标)
5.4.3 运行效果
启动应用:
bashnpm start测试功能:
- 点击 "打开设置窗口" 按钮,打开设置窗口
- 在设置窗口中修改设置,点击 "保存设置"
- 观察主窗口中的设置信息更新
- 关闭主窗口,设置窗口也会关闭
5.5 小结
通过本章的学习,你已经掌握了 Electron 窗口操作的核心功能:
- 窗口创建与配置:使用 BrowserWindow 类创建和配置窗口
- 窗口常用操作:显示、隐藏、最小化、最大化、关闭等
- 窗口事件:监听窗口状态变化事件
- 多窗口管理:创建和管理多个窗口
- 窗口间通信:通过 IPC 在不同窗口之间传递数据
这些功能是 Electron 应用开发的基础,掌握它们可以帮助你创建更加复杂和功能丰富的桌面应用。在接下来的章节中,我们将深入学习进程间通信的高级用法。
