Skip to content

Electron - 系统对话框

桌面应用程序经常需要通过标准的系统对话框与用户交互,例如用于打开文件、保存文件或显示警报和确认的对话框。Electron 的 dialog 模块提供了一种直接的方式来使用这些原生的系统对话框,确保用户体验与操作系统保持一致。

对于这些标准交互,使用原生对话框比使用基于 HTML 的自定义对话框更可取,因为它们是用户熟悉的,并且与操作系统功能集成良好。

dialog 模块只能在主进程中使用。如果你需要在渲染进程中触发对话框,则必须使用 IPC 请求主进程显示它。大多数 dialog 方法是异步的,并返回 Promise。

我们来创建一个示例应用程序,允许用户打开文本文件并显示其内容。

你的 main.js 文件将处理对话框和文件读取:

const { app, BrowserWindow, ipcMain, dialog } = require('electron');
const path = require('path');
const fs = require('fs').promises; // Use the promise-based fs module
let mainWindow;
function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
});
mainWindow.loadFile('index.html');
}
app.whenReady().then(createWindow);
// Handle 'dialog:openFile' IPC message from renderer
ipcMain.handle('dialog:openFile', async () => {
const { canceled, filePaths } = await dialog.showOpenDialog(mainWindow, {
title: 'Open Text File',
properties: ['openFile'],
filters: [
{ name: 'Text Files', extensions: ['txt', 'md', 'js', 'html', 'css'] },
{ name: 'All Files', extensions: ['*'] }
]
});
if (canceled || filePaths.length === 0) {
console.log('File open dialog canceled or no file selected.');
return null; // Or throw an error, or return an object indicating cancellation
}
const filePath = filePaths[0];
try {
const content = await fs.readFile(filePath, 'utf-8');
return { filePath, content };
} catch (error) {
console.error('Failed to read file:', error);
dialog.showErrorBox('Error Reading File', `Could not read file: ${error.message}`);
return null; // Or re-throw, or return an error object
}
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit();
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});

创建 preload.js 以向渲染进程暴露 IPC 调用:

const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
openFile: () => ipcRenderer.invoke('dialog:openFile')
});

以及你的 index.html 文件,用于触发对话框并显示内容:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>System Dialogs - File Reader</title>
<style>
body { font-family: sans-serif; margin: 20px; }
#fileInfo { margin-bottom: 10px; font-style: italic; }
#fileContent { white-space: pre-wrap; border: 1px solid #ccc; padding: 10px; background-color: #f9f9f9; }
</style>
</head>
<body>
<h1>Text File Viewer</h1>
<button id="openFileButton">Open File</button>
<div id="fileInfo">No file selected.</div>
<pre id="fileContent">File content will appear here.</pre>
<script>
const openFileButton = document.getElementById('openFileButton');
const fileInfoDiv = document.getElementById('fileInfo');
const fileContentPre = document.getElementById('fileContent');
openFileButton.addEventListener('click', async () => {
try {
const result = await window.electronAPI.openFile();
if (result && result.content !== null) {
fileInfoDiv.textContent = `Displaying: ${result.filePath}`;
fileContentPre.textContent = result.content;
} else if (result === null) {
// Error handled by main process (dialog.showErrorBox)
fileInfoDiv.textContent = 'Failed to open or read file.';
fileContentPre.textContent = '';
} else {
// Dialog was canceled
fileInfoDiv.textContent = 'File open canceled.';
fileContentPre.textContent = '';
}
} catch (error) {
console.error('Error in renderer trying to open file:', error);
fileInfoDiv.textContent = 'An unexpected error occurred.';
fileContentPre.textContent = '';
// Optionally, show a more user-friendly error in the UI
}
});
</script>
</body>
</html>

当你运行应用程序(electron .)并点击“Open File”按钮时,将会出现一个原生的文件打开对话框。它的外观将与你操作系统的标准文件对话框一致。选择文本文件后,其内容将显示在应用程序窗口中。

dialog 模块提供几种类型的对话框:

  • dialog.showOpenDialogSync([browserWindow, ]options) 和 dialog.showOpenDialog([browserWindow, ]options): 用于打开文件和目录。异步版本返回一个 Promise。
  • dialog.showSaveDialogSync([browserWindow, ]options) 和 dialog.showSaveDialog([browserWindow, ]options): 用于提示用户选择保存文件的路径。异步版本返回一个 Promise。
  • dialog.showMessageBoxSync([browserWindow, ]options) 和 dialog.showMessageBox([browserWindow, ]options): 用于显示消息框(警报、确认、带有自定义按钮的提示)。异步版本返回一个 Promise,该 Promise 解析为一个包含用户响应的对象。
  • dialog.showErrorBox(title, content): 一个简单的对话框,用于显示错误消息。这是一个同步操作。

在现代 Electron 开发中,始终优先使用对话框方法的异步版本,以避免阻塞主进程。记住要处理这些方法返回的 Promise 的成功结果和取消/错误情况。