使用Python在五分钟内实现CoreUI在桌面窗口中
使用CoreUI Bootstrap 5暗色主题构建Python桌面应用程序的指南。我们将一步步引导您,
- 创建项目目录并设置虚拟环境。
- 使用npm安装CoreUI免费后台模板。
- 构建CoreUI模板供生产环境使用。
- 整理生成的构建文件并更新模板。
- 创建Flask应用的
app.py
文件(应用主文件)。 - 将CoreUI模板整合进您的Flask应用中。
- 使用PyWebView在本地窗口中显示应用。
- 解决常见问题并进行必要的修复。
最后,你将有一个功能桌面应用,在PyWebView窗口中展示CoreUI的深色Bootstrap 5主题。
前提条件- 系统中已安装 Python 3.6+。
- 已安装 Node.js 和 npm(用于构建 CoreUI 模板)。
- 具备 Python 和 Web 开发(如 HTML、CSS)的基本知识。
- 随 Python 一起安装的 pip 包管理器。
- 已安装 Git(用于克隆仓库)。
- 对于 Windows 用户,需要熟悉命令提示符或 PowerShell。
打开你的终端或命令提示符,并为你的项目新建一个目录。
在Windows PowerShell:
# 创建项目文件夹
New-Item -ItemType Directory -Name coreui_pywebview_app
# 进入项目文件夹
Set-Location coreui_pywebview_app
适用于 VS Code Windows/Unix/macOS 终端(Terminal):
# 创建项目文件夹
mkdir coreui_pywebview_app
# 切换到项目文件夹
cd coreui_pywebview_app
1.2 搭建 Python 虚拟环境
创建一个虚拟环境有助于将项目的依赖关系隔离。
对于 Windows PowerShell 来说,
python -m venv venv # 创建一个虚拟环境
.\venv\Scripts\Activate.ps1 # 激活虚拟环境
对于 Unix/macOS 终端用户来说,
python3 -m venv venv # 创建虚拟环境
source venv/bin/activate # 激活虚拟环境
1.3 安装所需的Python库
安装 Flask 作为后端服务器框架,并使用 PyWebView 在桌面窗口中显示内容。
在你的终端中输入以下命令来安装这两个库:
pip install Flask pywebview
步骤 2:安装并构建 CoreUI 模板
2.1 安装 Node.js 以及 npm
如果你还没有安装 Node.js 和 npm 这两个工具,可以从官网下载并安装。
下面是如何在你的系统上安装它们的步骤。 Windows 版本:下载安装器:
- 访问官方的Node.js下载页面。
- 点击 Windows安装程序 (.msi) 链接以安装 长期支持(LTS) 版本,推荐大多数用户使用。
启动安装程序
- 在您的
下载
文件夹中找到下载的.msi
文件。 - 双击该安装文件以开始安装过程。
按照安装向导的操作提示,
- 点击Next以继续。
- 勾选许可协议并点击Next。
- 选择目标文件夹或使用默认设置,然后点击Next。
- 在Custom Setup选项卡,确保所有组件都被选中(建议使用默认设置),然后点击Next。
- 可选地,您可以调整设置,例如将Node.js添加到您的系统路径(默认已启用)。
- 点击Install来开始安装。
- 如果出现用户账户控制提示,请点击Yes以继续安装。
- 安装完成后,点击Finish按钮。
检查安装:
- 打开 命令行 或 PowerShell。
- 运行以下命令以检查 Node.js 和 npm 是否已安装:
在命令行中输入以下命令:
node -v
npm -v
此处的node
和npm
分别为node版本号
和npm版本号
。
例如,命令应显示已安装的版本如下:
v18.18.2
9.8.1
对于macOS用户
点击下载安装程序:
- 访问 Node.js 的官方下载页面。
- 点击 macOS 安装包 (.pkg) 链接(位于 LTS 版本 下载区域)。
运行安装程序:
- 在您的
Downloads
文件夹里找到刚刚下载的.pkg
文件。 - 然后双击它来开始安装。
请按照以下安装步骤操作:步骤如下:
- 在介绍屏幕上点击 继续。
- 阅读许可协议文本,点击 继续 ,然后点击 同意。
- 选择安装的目标位置并点击 继续。
- 点击 安装 开始安装过程。
- 可能需要您输入管理员密码;输入密码并点击 安装软件。
- 安装完成后,点击 关闭 按钮。
检查安装:
- 打开 终端应用 (你可以在应用列表里找到“实用工具”,然后点击“终端”)。
- 输入下面的命令:
运行 `node -v` 可以查看 Node.js 的版本,而 `npm -v` 则可以查看 npm 的版本。
这些命令应该显示已安装的版本信息。
2.2 克隆这个 CoreUI 代码库从你的项目目录 (coreui_pywebview_app
) 中克隆 CoreUI 仓库。
如何使用 Git:
# 克隆CoreUI仓库到子目录
git clone https://github.com/coreui/coreui-free-bootstrap-admin-template.git coreui-template
如果没有 Git,你可以从 CoreUI GitHub 仓库 下载 ZIP 包,并将其解压缩到您的项目目录中的 coreui-template
文件夹中。
进入 coreui-template
目录,并使用 npm 安装依赖。
# 进入CoreUI模板目录
cd coreui-template (使用cd命令进入CoreUI模板目录)
# 安装依赖包
npm install (使用npm安装依赖包)
这个命令读package.json
文件,然后将所需的包安装在node_modules
目录里。
构建用于生产的精简优化模板:
# 构建生产版本
npm run build
这个命令将 SCSS 文件编译为 CSS,并将 JavaScript 文件打包,然后将编译的资源输出至指定的 dist
目录。
构建完成后,你应该能看到位于 coreui-template
文件夹内的 dist
目录,里面包含编译后的 HTML、CSS 和 JS 文件。
coreui-template 文件夹/
├── dist/
│ ├── index.html
│ ├── base/
│ │ ├── accordion.html
│ │ ├── breadcrumb.html
│ │ └── [其余文件]...
│ ├── buttons/
│ │ ├── buttons.html
│ │ ├── button-group.html
│ │ └── [其余文件]...
│ ├── assets/
│ ├── css/
│ ├── js/
│ └── vendors/
├── node_modules/
├── src/
├── package.json
└── [其他文件]...
...
步骤 3:用 Python 脚本整理构建输出
为了自动化从dist
目录移动和更新文件到我们Flask应用相应位置的过程,我们将用两个Python脚本来实现。
copy_files.py
: 将编译后的资源复制到templates
和static
目录下。update_templates.py
: 更新 HTML 模板,使其正确引用静态文件和路由。
copy_files.py
脚本
在你的项目根目录(coreui_pywebview_app
)下创建一个新的名为 copy_files.py
的文件,并粘贴下面的代码。
# copy_files.py
import os
import shutil
def copy_files():
# 定义路径
project_root = os.getcwd()
coreui_dist = os.path.join(project_root, 'coreui-template', 'dist')
templates_dir = os.path.join(project_root, 'templates')
static_dir = os.path.join(project_root, 'static')
# 检查源目录是否存在
if not os.path.exists(coreui_dist):
print(f"源目录不存在: {coreui_dist}")
return
# 如果不存在则创建 'templates' 和 'static' 目录(如果它们不存在的话)
os.makedirs(templates_dir, exist_ok=True)
os.makedirs(static_dir, exist_ok=True)
# 将 HTML 文件和非特定目录复制到 'templates' 目录
for item in os.listdir(coreui_dist):
src_path = os.path.join(coreui_dist, item)
dst_path = os.path.join(templates_dir, item)
if os.path.isfile(src_path) and src_path.endswith('.html'):
shutil.copy2(src_path, dst_path)
print(f"已复制文件 {src_path} 至 {dst_path}")
elif os.path.isdir(src_path):
if item not in ['assets', 'css', 'js', 'vendors']:
# 将此目录复制到 'templates'
if os.path.exists(dst_path):
shutil.rmtree(dst_path)
print(f"已移除目录 {dst_path}")
shutil.copytree(src_path, dst_path)
print(f"已复制目录 {src_path} 至 {dst_path}")
# 需要复制到 'static' 目录的资源目录列表
asset_dirs = ['assets', 'css', 'js', 'vendors']
for asset_dir in asset_dirs:
src_dir = os.path.join(coreui_dist, asset_dir)
dst_dir = os.path.join(static_dir, asset_dir)
if os.path.exists(src_dir):
# 如果目标目录已存在,先删除它
if os.path.exists(dst_dir):
shutil.rmtree(dst_dir)
print(f"已移除目录 {dst_dir}")
# 复制该目录
shutil.copytree(src_dir, dst_dir)
print(f"{src_dir} 已复制至 {dst_dir}")
else:
print(f"源目录不存在: {src_dir}")
if __name__ == '__main__':
copy_files()
- 脚本会把
coreui-template/dist
目录里的所有.html
文件和除了assets
,css
,js
,vendors
之外的子目录复制到templates
目录。 - 它还会将这些资产目录(
assets
,css
,js
,vendors
)复制到static
目录。 - 在复制之前,它会先删除目标目录中已存在的所有子目录,以避免文件冲突。
copy_files.py
脚本。
请确保您的虚拟环境已激活,然后运行脚本。
运行一下 python copy_files.py
(这是一个复制文件的脚本).
预期的输出结果是:
复制了文件 /path/to/coreui-template/dist/index.html,到 /path/to/templates/index.html,复制了文件夹 /path/to/coreui-template/dist/base 到 /path/to/templates/base,复制了文件夹 /path/to/coreui-template/dist/buttons 到 /path/to/templates/buttons,等等,复制 /path/to/coreui-template/dist/assets 到 /path/to/static/assets,复制 /path/to/coreui-template/dist/css 到 /path/to/static/css,复制 /path/to/coreui-template/dist/js 到 /path/to/static/js,复制 /path/to/coreui-template/dist/vendors 到 /path/to/static/vendors
3.3 创建 update_templates.py
脚本
脚本用于更新模板文件,请按照指示编写该脚本。
在项目根目录下新建一个名为 update_templates.py
的文件,并粘贴如下代码。
# update_templates.py
import os
import re
def update_template(file_path):
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
# 正则表达式用于查找指向静态文件的src、href 和 xlink:href 属性
pattern = re.compile(r'''(?P<attr>(src|href|xlink:href))=(["'])(?!\{\{)(?!https?:\/\/)(?!\/\/)(?P<path>[^"'>{%][^"']*)\3''')
def replace_match(match):
attr = match.group('attr')
quote = match.group(3)
path = match.group('path')
# 如果已经使用了 url_for,则跳过
if '{{ url_for' in path:
return match.group(0)
# 跳过占位符和特殊方案(如javascript:、mailto: 和 tel:)
if path.startswith(('#', 'javascript:', 'mailto:', 'tel:')):
return match.group(0)
# 处理路径中的片段标识符(如#)
if '#' in path:
path, fragment = path.split('#', 1)
fragment = '#' + fragment
else:
fragment = ''
# 对.html文件进行特殊处理
if path.endswith('.html'):
# 如果路径为 'index.html'、'./' 或 'index',则使用 url_for('index')
if path in ('index.html', './', 'index'):
new_path = "{{ url_for('index') }}"
else:
# 对于其他 .html 文件,使用 url_for('serve_page', path='...')
new_path = "{{ url_for('serve_page', path='%s') }}" % path
else:
# 对静态文件,使用 url_for('static', filename='...')
new_path = "{{ url_for('static', filename='%s') }}" % path.replace('\\', '/')
# 重构属性,使用新的路径和任何片段标识符
return '%s=%s%s%s%s' % (attr, quote, new_path, fragment, quote)
new_content, count = pattern.subn(replace_match, content)
if count > 0:
with open(file_path, 'w', encoding='utf-8') as f:
f.write(new_content)
print(f"更新了 {file_path},共替换了 {count} 处.")
else:
print(f"在 {file_path} 中无需替换.")
def main():
templates_dir = 'templates'
# 递归遍历模板目录
for root, dirs, files in os.walk(templates_dir):
for file in files:
if file.endswith('.html'):
file_path = os.path.join(root, file)
update_template(file_path)
if __name__ == '__main__':
main()
**
- 脚本更新了
templates
目录及其子目录内所有的 HTML 文件。 - 它使用正则表达式搜索所有的
src
和href
属性。 - 对于静态资源(CSS、JS、图片),它将路径用
{{ url_for('static', filename='...') }}
包裹。 - 对于链接到其他 HTML 模板的路径,它修改
href
属性以使用 Flask 路由: index.html
的链接被替换为{{ url_for('index') }}
。- 其他
.html
文件使用{{ url_for('serve_page', path='filename.html') }}
进行链接引用。 - 脚本避免更改
data-*
属性以防止 JavaScript 问题。
update_templates.py
运行一下脚本。
python update_templates.py # 运行更新模板的Python脚本
预计的结果是:
更新了 templates/index.html,共替换了 25 次。
更新了 templates/base/accordion.html,共替换了 10 次。
更新了 templates/buttons/buttons.html,共替换了 15 次。
...
3.5 检查文件是否已经更新
你的项目的结构现在应该是这样的。
coreui_pywebview_app/
├── app.py
├── copy_files.py
├── update_templates.py
├── templates/
│ ├── index.html
│ ├── base/
│ │ ├── accordion.html
│ │ ├── breadcrumb.html
│ │ └── [...](其他文件和目录)
│ ├── buttons/
│ │ ├── buttons.html
│ │ ├── button-group.html
│ │ └── [...](其他文件和目录)
│ └── [...](其他 HTML 文件和目录)
├── static/
│ ├── assets/
│ ├── css/
│ ├── js/
│ └── vendors/
├── coreui-template/
└── venv/
打开一个 HTML 文件,例如打开 templates/index.html
文件,并检查静态文件路径和链接是否已经更新。
更新后的HTML示例:
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<a class="nav-link" href="{{ url_for('index') }}">首页</a>
<a class="nav-link" href="{{ url_for('serve_page', path='colors.html') }}">颜色</a>
<a class="nav-link" href="{{ url_for('serve_page', path='base/accordion.html') }}">折叠面板</a>
第 5 步:创建名为 app.py
的文件
在你的项目根目录下创建一个名为 app.py
的文件,并将以下内容写入文件。
# app.py
from flask import Flask, render_template
import threading
import webview
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
# 添加其他页面的路由:
@app.route('/<path:path>')
def serve_page(path):
try:
return render_template(path)
except:
return render_template('404.html'), 404
def start_server():
app.run(host='127.0.0.1', port=5000, debug=False)
if __name__ == '__main__':
# 启动Flask服务器于单独线程
server = threading.Thread(target=start_server)
server.daemon = True
server.start()
# 创建PyWebView窗口,并加载Flask应用
window = webview.create_window('CoreUI Python App', 'http://127.0.0.1:5000', width=1024, height=768)
# 启动PyWebView,启用调试模式
webview.start(debug=True)
- Flask应用搭建: 我们创建一个基本的Flask应用,并设置与CoreUI模板中的页面相对应的路由。
- PyWebView整合: 我们使用PyWebView创建一个加载Flask应用的原生窗口。
- 错误处理:
serve_page
路由尝试渲染请求的模板页面,如果模板未找到,则返回404错误页面。
确保虚拟环境已经启动。
适用于 Windows PowerShell:
.\venv\Scripts\Activate.ps1
激活虚拟环境的PowerShell脚本
在 Unix/macOS 的终端里:
# 激活 venv 环境
6.2 开始应用
运行一下 app.py
脚本吧。
你可以运行命令 python app.py
来启动应用程序。
会弹出一个 PyWebView 窗口,显示用 CoreUI Bootstrap 5 深色主题装饰的 Flask 应用程序。
试试侧边栏中的链接:
- 依次点击“仪表盘”,“颜色”,和“字体”以验证它们是否正常工作。
- 展开“基础”和“按钮”菜单项,并点击子项,如“折叠面板”和“按钮”。
- 确保页面加载时没有404错误页面。
说明:在app.py
中的webview.start()
函数里设置debug=True
,这样可以开启调试模式,这样你可以在PyWebView窗口中使用右键菜单和浏览器开发者工具。这样用户可以访问标准浏览器的右键菜单,包括后退按钮等导航选项。
如果您希望阻止访问开发者工具和右键菜单,可以具体来说,将 app.py
中的 debug=True
参数注释或删除。您可以注释或删除 app.py
文件中的 debug=True
参数,并移除或修改 webview.start()
函数调用中的调试参数。
# 启动 PyWebView 应用程序,关闭调试模式
webview.start()
通过这种方式,应用程序将没有右键菜单和开发者工具,提供一个更受控的环境。
第七步:常见问题排查
问题: 点击侧边栏链接时出现404错误症状:
- 点击“Base”和“Buttons”之类的项会显示404错误页面。
- 像
base/accordion.html
这样的页面找不到。 - 子页面(如
base/accordion.html
)也未找到。
原因如下:
templates
目录缺少子页面的模板文件。update_templates.py
脚本没有处理子目录下的内容。
解决办法:
- 更新
**copy_files.py**
和**update_templates.py**
脚本如下所示,处理子目录,并递归处理HTML文件。 - 移除或修改该
**< base>**
标签在**index.html**
中以避免路径问题。
data-*
属性修改不当的问题
症状如下:
- JavaScript功能出问题了。
- 下拉菜单和弹出框无法正常使用。
原因:
update_templates.py
脚本不小心改了data-*
相关的属性。
解决办法:
- 更新
**update_templates.py**
文件以避免修改**data-***
属性。 - 请手动修正您模板中的任何
**data-***
属性。
症状有:
- 样式表和脚本没有被加载。
- 应用程序看起来没有样式。
解决办法:
- 确保所有 HTML 模板中的静态文件路径都使用了
**url_for('static', filename='...')**
函数。 - 确保
**static**
目录包含了从 CoreUI 的**dist**
目录复制的所有必要资源。 - 检查
**static**
目录中的文件结构是否与 HTML 文件中的路径匹配。 - 清除浏览器缓存或使用无痕/隐私窗口。
感谢您阅读这篇文章。我希望这篇文章对您有所帮助和启发。如果您有任何问题,或者想要推荐新的Python代码示例或未来教程的主题,请随时联系我。您的反馈和建议总是很受欢迎!
编程愉快!
C. C. Python编程
共同学习,写下你的评论
评论加载中...
作者其他优质文章