为了账号安全,请及时绑定邮箱和手机立即绑定

用Python和CoreUI Bootstrap 5打造桌面应用:一步一步教你实现

标签:
Python Bootstrap

使用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 模板)。
  • 具备 PythonWeb 开发(如 HTML、CSS)的基本知识。
  • 随 Python 一起安装的 pip 包管理器。
  • 已安装 Git(用于克隆仓库)。
  • 对于 Windows 用户,需要熟悉命令提示符或 PowerShell。
第一步:创建项目目录并设置虚拟环境
1.1 创建一个项目文件夹。

打开你的终端或命令提示符,并为你的项目新建一个目录。

在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

此处的nodenpm分别为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 文件夹中。

2.3 安装依赖项

进入 coreui-template 目录,并使用 npm 安装依赖。

    # 进入CoreUI模板目录  
    cd coreui-template (使用cd命令进入CoreUI模板目录)  

    # 安装依赖包  
    npm install (使用npm安装依赖包)

这个命令读package.json文件,然后将所需的包安装在node_modules目录里。

构建CoreUI模板

构建用于生产的精简优化模板:

# 构建生产版本  
npm run build

这个命令将 SCSS 文件编译为 CSS,并将 JavaScript 文件打包,然后将编译的资源输出至指定的 dist 目录。

2.5 验证构建输出

构建完成后,你应该能看到位于 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: 将编译后的资源复制到 templatesstatic 目录下。
  • update_templates.py: 更新 HTML 模板,使其正确引用静态文件和路由。
3.1 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 文件和除了 assetscssjsvendors 之外的子目录复制到 templates 目录。
  • 它还会将这些资产目录(assetscssjsvendors)复制到 static 目录。
  • 在复制之前,它会先删除目标目录中已存在的所有子目录,以避免文件冲突。
3.2 运行一下 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 文件。
  • 它使用正则表达式搜索所有的 srchref 属性。
  • 对于静态资源(CSS、JS、图片),它将路径用 {{ url_for('static', filename='...') }} 包裹。
  • 对于链接到其他 HTML 模板的路径,它修改 href 属性以使用 Flask 路由:
  • index.html 的链接被替换为 {{ url_for('index') }}
  • 其他 .html 文件使用 {{ url_for('serve_page', path='filename.html') }} 进行链接引用。
  • 脚本避免更改 data-* 属性以防止 JavaScript 问题。
.4 运行 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错误页面。
步骤六:运行应用
6.1 请确保虚拟环境已经激活并处于活动状态

确保虚拟环境已经启动。

适用于 Windows PowerShell:

    .\venv\Scripts\Activate.ps1

激活虚拟环境的PowerShell脚本

在 Unix/macOS 的终端里:

# 激活 venv 环境
6.2 开始应用

运行一下 app.py 脚本吧。

你可以运行命令 python app.py 来启动应用程序。

步骤6.3 查看申请

会弹出一个 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编程

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消