使用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创建一个虚拟环境有助于将项目的依赖关系隔离。
对于 Windows PowerShell 来说,
python -m venv venv  # 创建一个虚拟环境
.\venv\Scripts\Activate.ps1  # 激活虚拟环境对于 Unix/macOS 终端用户来说,
    python3 -m venv venv  # 创建虚拟环境
    source venv/bin/activate  # 激活虚拟环境安装 Flask 作为后端服务器框架,并使用 PyWebView 在桌面窗口中显示内容。
在你的终端中输入以下命令来安装这两个库:
pip install Flask pywebview如果你还没有安装 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点击下载安装程序:
- 访问 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
    └── [其他文件]...
    ...为了自动化从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/vendorsupdate_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 次。  
...你的项目的结构现在应该是这样的。
    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>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 环境运行一下 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编程
共同学习,写下你的评论
评论加载中...
作者其他优质文章
 
                 
            
 
			 
					 
					