如何将Python Flask应用程序加载到GTK Webview(Webkit)中

3
我目前正在开发一个应用程序,需要呈现数学表达式(从latex中)并需要具有某种本地GUI(即使只是使用gtk,然后在webkit中呈现html)。
我进行了一些研究,并决定使用webkit加载网页,并使用像MathJax这样的JavaScript库来呈现数学公式是一种简单的方法。我选择以这种方式处理的其他原因是:我有相当多的Python Web应用程序开发经验(虽然是一段时间以前),缺乏本地GUI的经验以及它提供的可移植性。
对于Web应用程序框架,我选择使用flask,因为我最熟悉它。
问题是这个应用程序需要拥有自己的本地GUI,最好通过gtk(即使只是在webkit中呈现html),并且最好不要附加到某个套接字上的http服务器。
所以我的问题是,除了运行flask的服务器之外,是否有任何方法可以做到这一点?
import gtk
import webkit

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return "<h1>Hello World!</h1>"

if __name__ == '__main__': 
    window = gtk.Window()

    webview = webkit.WebView()

    webview.load_string(
        app.load_from_uri('/'),
        "text/html",
        "utf-8",
        '/'
    )

    window.add(webview) 
    window.show_all() 

app.load_from_uri('/')仅作为示例用于加载Flask应用程序的给定URI的网页的方式。但是,由于这只是一个示例,那么在实际代码中如何执行app.load_from_uri('/')呢?

另外,是否有任何方法可以覆盖用户单击链接时的操作,使其执行以下操作:

def link_clicked(uri):
    webview.load_string(
        app.load_from_uri(uri),
        "text/html",
        "utf-8",
        uri
    )

非常感谢您的帮助!

1个回答

3

我自己找到了解决方法(但也欢迎更好的方法)。

首先,加载页面非常容易。Flask提供了一种测试应用程序的方式,主要是设置所有东西以便WSGI能够处理请求。这正是我所需要的,所以我就像这样使用它:

from flask import Flask
class WebViewFlask(Flask):
    """
    Adds the ability to load a uri without the
    need of a HTTP server.
    """
    def load_from_uri(self, uri):
        """
        Loads a uri without a running HTTP server.
        """
        with self.test_client() as c:
            response = c.get(uri)
            return response.data, response.mimetype

第二部分,覆盖“当用户点击链接时”的操作,稍微有些棘手。
import os
import webkit
class FlaskAppView(webkit.WebView):
    """
    Loads pages for flask apps into a WebView.
    """
    def __init__(self, flask_app, *args, **kwargs):
        # Protocol for flask app, by default file:// is used
        # so a protocol is defined here to prevent that.
        self.PROTOCOL = 'flask://' 

        super(webkit.WebView, self).__init__(*args, **kwargs)

        self._flask_app = flask_app

        # Register new navigation handler.
        self.connect(
            "navigation-policy-decision-requested",
            self._nav_request
        )

        # For navigation handler.
        self.prev_uri = None

        # Redefine open like this as when using super
        # an error like this occurs:
        #   AttributeError: 'super' object has no attribute 'open'
        self._open = self.open
        self.open = self.open_

    def _nav_request(self, view, frame, net_req, nav_act, pol_dec):
        """
        WebView navigation handler for Flask apps.
        """
        # Get the uri
        uri = net_req.get_uri()

        # In order for flask apps to use relative links
        # the protocol is removed and it is made into an absolute
        # path.
        if uri.startswith(self.PROTOCOL):
            # In this case it is not relative but
            # it needs to have it's protocol removed
            uri = uri[len(self.PROTOCOL):]

        elif not self.prev_uri.endswith(uri):
            # It is relative and self.prev_uri needs to
            # be appended.
            uri = os.path.normpath(os.path.join(self.prev_uri, uri))

        # This is used to prevent an infinite recursive loop due
        # to view.load_string running this function with the same
        # input.
        if uri == self.prev_uri:
            return False

        self.prev_uri = uri

        # Create response from Flask app.
        response = app.load_from_uri(uri) + ('utf-8', uri)

        # Load response.
        view.load_string(*response)

        # Return False to prevent additional
        # handlers from running.
        return False

    def open_(self, uri):
        """
        Prepends protocol to uri for webkit.WebView.open.
        """
        self._open(self.PROTOCOL + uri)

基本上,一个新的导航事件处理程序被注册,其中包含一些代码,以允许成功的递归和支持相对路径。
总之,只需将上面的代码中的Flask替换为WebViewFlask,将WebView替换为FlaskAppView,就可以使一切正常运行。
结果是:在没有任何服务器的情况下,在webkit.WebView中加载了一个flask应用程序。最好的事情是,只需将app切换回Flask的实例而不是WebViewFlask,它就变成了一个普通的webapp。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接