我目前正在开发一个需要渲染数学表达式(从乳胶)并且需要某种本机gui的应用程序(即使它仅使用gtk,然后在webkit中渲染html).
我进行了一些研究,并确定一种简单的方法是使用webkit加载网页并使用像MathJax这样的JavaScript库来渲染数学.
之所以选择这种方式而不是其他解决方案,还有其他一些原因,例如,我有相当多的使用python开发Web应用程序的经验(尽管有一段时间),缺乏使用本机GUI的经验以及它提供的可移植性.
对于Web应用程序框架,我选择使用flask,因为它是我最熟悉的框架.
问题是此应用程序最好通过gtk(即使只是使用webkit渲染html)也需要具有自己的本机GUI,并且最好也不应将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
)
谢谢任何帮助,不胜感激!
解决方法:
我最终找到了自己的解决方案(但可以接受更好的解决方案).
首先,加载页面非常简单. 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应用.最好的办法是将应用程序切换回Flask实例而不是WebViewFlask实例.这又是一个普通的Webapp.