您当前的位置:首页 > 计算机 > 编程开发 > Python

python --pywebview、flaskwebgui开发桌面程序

时间:08-16来源:作者:点击数:
CDSY,CDSY.XYZ

python --pywebview、flaskwebgui开发桌面程序

pywebview

装包

pip install pywebview==3.7.2

官文

https://pywebview.flowrl.com/guide/interdomain.html#invoke-python-from-javascript

案例

https://pywebview.flowrl.com/examples/fullscreen.html

实操

import webview
from flask import Flask, render_template, jsonify, request
import json
from functools import wraps

app = Flask(__name__, template_folder='./static', static_folder='./static', static_url_path='')


def verify_token(function):
    @wraps(function)
    def wrapper(*args, **kwargs):
        data = json.loads(request.data)
        token = data.get('token')
        if token == webview.token:
            return function(*args, **kwargs)
        else:
            raise Exception('Authentication error')

    return wrapper


@app.route('/')
def index():
    return render_template('index.html')


@app.route('/backstage/api/login/', methods=['POST'])
def login():
    print(request.data)
    data = json.loads(request.data)
    user = data.get('username')
    pwd = data.get('password')

    if user != 'test' or pwd != 'test':
        print({'code': '4013', 'msg': '用户名或密码错误'}, jsonify({'code': '4013', 'msg': '用户名或密码错误'}))
        return jsonify({'code': '4013', 'msg': '用户名或密码错误'})

    groups = {"首页": [], "业务菜单": ["3D模型", "画图展示", "业务3"], "系统设置": ["用户管理", "系统日志"]}
    roles = {"首页": ["读"], "3D模型": ["读", "写"], "业务2": ["读", "写"], "业务3": ["读", "写"],
             "用户管理": ["读", "写"], "系统日志": ["读", "写"]}

    return jsonify({'code': '0', 'data': {'groups': groups, 'roles': roles}, 'msg': 'ok'})


@app.route('/get_usr_info', methods=['GET'])
@verify_token
def get_usr_info():
    return jsonify({'code': '0', 'data': []})


if __name__ == '__main__':
    chinese = {
        'global.quitConfirmation': u'确定关闭?',
    }

    window = webview.create_window(
        title='云收单',
        url=app,
        width=900,
        height=620,
        # frameless=True,
        # easy_drag=True,
        # hidden=True,
        transparent=True,
    )

    webview.start(localization=chinese, debug=True, http_server=True)
    注意: 如果要修改flask运行端口为固定则去源码找serving.py 53行修改为指定端口即可;
    注意2: 如新版本出错
    	RuntimeError: cannot call null pointer pointer from cdata 'int(*)(void *, int)'
    	pip install pythonnet==2.5.2

控制窗口事件

import json
import webview
from flask import Flask, render_template
from flask_cors import CORS
import uuid

app = Flask(__name__, template_folder='./static', static_folder='./static', static_url_path='')
CORS(app, supports_credentials=True)


class Windows(object):
    '''窗口事件'''

    _window = None

    @property
    def w(self):
        return self._window

    @w.setter
    def w(self, value):
        self._window = value

    def minimize(self):
        print('调用最小化窗口')
        self._window.minimize()

    def destroy(self):
        print('销毁窗口')
        self._window.destroy()


@app.route('/')
def index():
    return render_template('index.html')


@app.route('/api_minimize', methods=['GET', ])
def api_minimize():
    _w.minimize()
    return json.dumps({'code': 0})


@app.route('/kill', methods=('GET',))
def kill():
    _w.destroy()


window = webview.create_window(
    title='问卷侠题库系统',
    url=app,
    width=1360,
    height=800,
    text_select=True,
    resizable=False,
    frameless=True,
    confirm_close=True
)
_w = Windows()
_w.w = window
webview.start(debug=True, http_server=True)

flaskwebgui

装包: pip install flaskwebgui

github:

https://github.com/ClimenteA/flaskwebgui/tree/master/examples/

实例:

from flask import Flask
from flask import render_template
from flaskwebgui import FlaskUI

app = Flask(__name__, static_folder='./static', template_folder='./static', static_url_path='')
ui = FlaskUI(app, width=500, height=500)


@app.route("/")
def hello():
    return render_template('index.html')


@app.route("/home", methods=['GET'])
def home():
    return render_template('index.html')


if __name__ == "__main__":
    ui.run()

结构:

在这里插入图片描述

打包多进程失效或异常问题

重复启动主进程问题

if __name__ == '__main__':
    multiprocessing.freeze_support()

自定义封装桌面程序

import logging
import os
import signal
import subprocess as sps
import tempfile

import win32con
import win32gui
import win32print
from flask import Flask, redirect
from flask_cors import CORS
from flaskwebgui import FlaskUI


class BaseFlaskUI(FlaskUI):

    def find_chrome_win(self):

        import winreg as reg
        reg_path = r'SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\chrome.exe'

        chrome_path = None
        last_exception = None

        for install_type in reg.HKEY_CURRENT_USER, reg.HKEY_LOCAL_MACHINE:
            try:
                reg_key = reg.OpenKey(install_type, reg_path, 0, reg.KEY_READ)
                chrome_path = reg.QueryValue(reg_key, None)
                reg_key.Close()
            except WindowsError as e:
                last_exception = e
            else:
                if chrome_path and len(chrome_path) > 0:
                    break
        if not chrome_path:
            edge_path = "C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"
            return edge_path
        logging.info(f'{chrome_path}')
        return chrome_path

    def get_real_resolution(self):
        """获取真实的分辨率"""
        hdc = win32gui.GetDC(0)
        return win32print.GetDeviceCaps(hdc, win32con.DESKTOPHORZRES), \
               win32print.GetDeviceCaps(hdc, win32con.DESKTOPVERTRES)

    def open_chromium(self):
        logging.info(f"Opening browser at {self.localhost}")

        temp_profile_dir = os.path.join(tempfile.gettempdir(), "flaskwebgui")

        if self.browser_path:
            width, height = self.get_real_resolution()
            width = (width - 1750) // 2
            height = (height - 850) // 2
            if self.fullscreen:
                launch_options = ["--start-fullscreen"]
            elif self.maximized:
                launch_options = ["--start-maximized"]
            else:
                launch_options = [f"--window-size={self.width},{self.height}"]

            options = [
                          self.find_chrome_win(),
                          f"--user-data-dir={temp_profile_dir}",
                          "--new-window",
                          "--no-first-run",
                          f"--window-position={width},{height}",
                          "--disable-desktop-notifications"
                      ] + launch_options + [f'--app={self.localhost}']

            sps.Popen(options, stdout=sps.PIPE, stderr=sps.PIPE, stdin=sps.PIPE)

        else:
            import webbrowser
            webbrowser.open_new(self.localhost)


app = Flask(__name__, template_folder='./static', static_folder='./static', static_url_path='')
CORS(app, supports_credentials=True)

ui = BaseFlaskUI(app, close_server_on_exit=True, width=1750, height=850, port=8001)


@app.route('/kill', methods=('GET',))
def kill():
    print('调用用户退出')
    handle = os.getpid()
    print(f'pid={handle}')
    os.kill(handle, signal.SIGABRT)


@app.route('/', methods=('GET',))
def index():
    return redirect('http://8.140.142.128:8000/static/index.html#/login')


if __name__ == '__main__':
    ui.run()

# app = Flask(__name__, template_folder='./static', static_folder='./static', static_url_path='')
#
#
# @app.route('/')
# def index():
#     return redirect('http://8.140.142.128:8000/static/index.html#/login')
#
#
# @app.route('/kill')
# def kill():
#     print('调用用户退出')
#     handle = os.getpid()
#     print(f'pid={handle}')
#     os.kill(handle, signal.SIGABRT)
#
#
# def get_real_resolution():
#     """获取真实的分辨率"""
#     hdc = win32gui.GetDC(0)
#     return win32print.GetDeviceCaps(hdc, win32con.DESKTOPHORZRES), \
#            win32print.GetDeviceCaps(hdc, win32con.DESKTOPVERTRES)
#
#
# if __name__ == '__main__':
#     chinese = {
#         'global.quitConfirmation': u'您确定要关闭吗?',
#     }
#
#     window = webview.create_window(
#         title='船舶管理',
#         url=app,
#         width=1750,
#         height=850,
#         # transparent=True,
#         text_select=True,
#         confirm_close=True
#     )
#     print(get_real_resolution())
#     window_hwnd: list = []
#     win32gui.EnumWindows(lambda _hwd, param: param.append(_hwd), window_hwnd)
#     status = False
#     for hwd in window_hwnd:
#         if win32gui.GetWindowText(hwd) == '船舶管理':
#             width, height = get_real_resolution()
#             print(f'激活窗口:{width};{height}')
#             win32gui.ShowWindow(hwd, win32con.SW_MAXIMIZE)
#             win32gui.MoveWindow(hwd, (width - 1750) // 2, (height - 850) // 2, 1750, 850, True)
#             status = True
#             break
#
#     if not status:
#         webview.start(localization=chinese, debug=False, http_server=True)
CDSY,CDSY.XYZ
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐