使用Webkit和xml、xslt 实现html风格的RichEdit试验
书接上回,继续研究WebKit 实现了梦幻中的三位一体式的XmlRichEdit
示范效果:
在View面板上的修改能体现在Edit上
同样修改了Edit 也能体现在View面板上
同时数据使用xml描述,xslt转换到html,使用webkit渲染html并响应其中的html事件
以后只要修改xml和xslt就能产生不同的效果
xml 表达 数据Model:
template.xml
<?
xml version="1.0"
?>
<? xml-stylesheet type="text/xsl" href="richedit.xsl" ?>
< document id ='doc'>
<title id ='title'>Template</title>
<text id ='text'>1234567891234</text>
</document >
<? xml-stylesheet type="text/xsl" href="richedit.xsl" ?>
< document id ='doc'>
<title id ='title'>Template</title>
<text id ='text'>1234567891234</text>
</document >
xsl 将xml转换到html:
richedit.xsl
<
xsl:stylesheet
version
="1.0"
xmlns:xsl ='http://www.w3.org/1999/XSL/Transform'>
<xsl:output method ="html" />
< xsl:template match ="document" >
< html >
< head >
< meta http-equiv ="content-type"
content ="text/html; charset=UTF-8" />
< script type ="text/javascript" >
function onChanged(e,id) { var element
=document.getElementById(id);
python.onChanged(id,element.textContent); }
</ script >
</ head >
< body >
< div >
< xsl:attribute name ='id'>
<xsl:value-of select ='@id' />
</ xsl:attribute >
< xsl:apply-templates />
</ div >
</ body >
</ html >
</ xsl:template >
< xsl:template match ="title" >
< div >
< h1 >
< xsl:attribute name ='id'>
<xsl:value-of select ='@id' />
</ xsl:attribute >
< xsl:attribute name ='contenteditable'>
<xsl:text > true </ xsl:text >
</ xsl:attribute >
< xsl:attribute name ='onkeyup'>
<xsl:text > onChanged(event,' </ xsl:text >
< xsl:value-of select ='@id' />
< xsl:text > ') </ xsl:text >
</ xsl:attribute >
< xsl:value-of select ='.' />
</ h1 >
</ div >
</ xsl:template >
< xsl:template match ="text" >
< div >
< p >
< xsl:attribute name ='id'>
<xsl:value-of select ='@id' />
</ xsl:attribute >
< xsl:attribute name ='contenteditable'>
<xsl:text > true </ xsl:text >
</ xsl:attribute >
< xsl:attribute name ='onkeyup'>
<xsl:text > onChanged(event,' </ xsl:text >
< xsl:value-of select ='@id' />
< xsl:text > ') </ xsl:text >
</ xsl:attribute >
< xsl:value-of select ='.' />
</ p >
</ div >
</ xsl:template >
</ xsl:stylesheet >
xmlns:xsl ='http://www.w3.org/1999/XSL/Transform'>
<xsl:output method ="html" />
< xsl:template match ="document" >
< html >
< head >
< meta http-equiv ="content-type"
content ="text/html; charset=UTF-8" />
< script type ="text/javascript" >
function onChanged(e,id) { var element
=document.getElementById(id);
python.onChanged(id,element.textContent); }
</ script >
</ head >
< body >
< div >
< xsl:attribute name ='id'>
<xsl:value-of select ='@id' />
</ xsl:attribute >
< xsl:apply-templates />
</ div >
</ body >
</ html >
</ xsl:template >
< xsl:template match ="title" >
< div >
< h1 >
< xsl:attribute name ='id'>
<xsl:value-of select ='@id' />
</ xsl:attribute >
< xsl:attribute name ='contenteditable'>
<xsl:text > true </ xsl:text >
</ xsl:attribute >
< xsl:attribute name ='onkeyup'>
<xsl:text > onChanged(event,' </ xsl:text >
< xsl:value-of select ='@id' />
< xsl:text > ') </ xsl:text >
</ xsl:attribute >
< xsl:value-of select ='.' />
</ h1 >
</ div >
</ xsl:template >
< xsl:template match ="text" >
< div >
< p >
< xsl:attribute name ='id'>
<xsl:value-of select ='@id' />
</ xsl:attribute >
< xsl:attribute name ='contenteditable'>
<xsl:text > true </ xsl:text >
</ xsl:attribute >
< xsl:attribute name ='onkeyup'>
<xsl:text > onChanged(event,' </ xsl:text >
< xsl:value-of select ='@id' />
< xsl:text > ') </ xsl:text >
</ xsl:attribute >
< xsl:value-of select ='.' />
</ p >
</ div >
</ xsl:template >
</ xsl:stylesheet >
python脚本 将html渲染到WebKit:
xml_utils.py
from
lxml
import
etree
def getElementById(doc,id):
return doc.xpath( " //*[@id='%s'] " % id)[0]
def XSLTransform(xml,xslt):
try :
return xslt(xml)
except Exception,e:
transform = etree.XSLT(etree.parse(xslt))
try :
return transform(xml)
except Exception,e:
root = etree.parse(xml)
return transform(root)
if __name__ == ' __main__ ' :
print XSLTransform( ' template.xml ' , ' richedit.xsl ' )
def getElementById(doc,id):
return doc.xpath( " //*[@id='%s'] " % id)[0]
def XSLTransform(xml,xslt):
try :
return xslt(xml)
except Exception,e:
transform = etree.XSLT(etree.parse(xslt))
try :
return transform(xml)
except Exception,e:
root = etree.parse(xml)
return transform(root)
if __name__ == ' __main__ ' :
print XSLTransform( ' template.xml ' , ' richedit.xsl ' )
sample.py
import
sys,locale
from lxml import etree
from PyQt4 import Qt
from PyQt4 import QtCore
from PyQt4 import QtGui
from PyQt4 import QtWebKit
import xml_utils
encoding = locale.getdefaultlocale()[ 1 ]
class PythonJS(QtCore.QObject):
__pyqtSignals__ = ( " contentChanged(const QString &,const QString &) " )
@QtCore.pyqtSignature( " QString,QString " )
def onChanged(self, id,msg):
# print msg,id
self.emit(QtCore.SIGNAL( ' contentChanged(const QString &,const QString &) ' ),id, msg)
@QtCore.pyqtSignature( "" , result = " QString " )
def message(self):
return " Message! "
class MainWindow(QtGui.QMainWindow):
def __init__ (self):
super(MainWindow,self). __init__ ()
self.update = True
self.xml = etree.parse( ' template.xml ' )
self.tabs = QtGui.QTabWidget(self)
self.browser = QtWebKit.QWebView(self.tabs)
self.edit = QtGui.QPlainTextEdit(self.tabs)
self.tabs.addTab(self.browser, ' View ' )
self.tabs.addTab(self.edit, ' Edit ' )
self.edit.setPlainText(etree.tostring(self.xml,pretty_print = True))
self.pjs = PythonJS()
self.connect(self.edit,QtCore.SIGNAL( ' textChanged() ' ),self.onTextChanged)
self.connect(self.pjs,QtCore.SIGNAL( ' contentChanged(const QString &,const QString &) ' ),self.onJSMessage)
self.connect(self.browser.page().mainFrame(),QtCore.SIGNAL( ' javaScriptWindowObjectCleared () ' ),self.onObjectClear)
html = xml_utils.XSLTransform(self.xml, ' richedit.xsl ' )
self.browser.setHtml(unicode(html))
def onJSMessage(self,id,msg):
self.html = self.browser.page().mainFrame ().toHtml()
# print unicode(self.html).encode(encoding)
self.setEditText(id,msg)
def resizeEvent(self,s):
size = self.size()
self.tabs.resize(size)
def setEditText(self,id,str,update = False):
t = self.update
self.update = update
e = xml_utils.getElementById(self.xml, id)
e.text = unicode(str)
self.edit.setPlainText(etree.tostring(self.xml,pretty_print = True))
self.update = t
def onTextChanged(self):
if self.update:
try :
self.xml = etree.fromstring(unicode(self.edit.toPlainText()) )
try :
html = xml_utils.XSLTransform(self.xml, ' richedit.xsl ' )
html = unicode(html)
if html:
self.browser.setHtml(html)
self.browser.page().mainFrame().addToJavaScriptWindowObject( ' python ' ,self.pjs)
self.browser.reload()
except Exception,e:
print e
except Exception,e:
print e
def onObjectClear(self):
self.browser.page().mainFrame().addToJavaScriptWindowObject( ' python ' ,self.pjs)
if __name__ == ' __main__ ' :
app = QtGui.QApplication(sys.argv)
frame = MainWindow()
frame.show()
sys.exit(app.exec_())
from lxml import etree
from PyQt4 import Qt
from PyQt4 import QtCore
from PyQt4 import QtGui
from PyQt4 import QtWebKit
import xml_utils
encoding = locale.getdefaultlocale()[ 1 ]
class PythonJS(QtCore.QObject):
__pyqtSignals__ = ( " contentChanged(const QString &,const QString &) " )
@QtCore.pyqtSignature( " QString,QString " )
def onChanged(self, id,msg):
# print msg,id
self.emit(QtCore.SIGNAL( ' contentChanged(const QString &,const QString &) ' ),id, msg)
@QtCore.pyqtSignature( "" , result = " QString " )
def message(self):
return " Message! "
class MainWindow(QtGui.QMainWindow):
def __init__ (self):
super(MainWindow,self). __init__ ()
self.update = True
self.xml = etree.parse( ' template.xml ' )
self.tabs = QtGui.QTabWidget(self)
self.browser = QtWebKit.QWebView(self.tabs)
self.edit = QtGui.QPlainTextEdit(self.tabs)
self.tabs.addTab(self.browser, ' View ' )
self.tabs.addTab(self.edit, ' Edit ' )
self.edit.setPlainText(etree.tostring(self.xml,pretty_print = True))
self.pjs = PythonJS()
self.connect(self.edit,QtCore.SIGNAL( ' textChanged() ' ),self.onTextChanged)
self.connect(self.pjs,QtCore.SIGNAL( ' contentChanged(const QString &,const QString &) ' ),self.onJSMessage)
self.connect(self.browser.page().mainFrame(),QtCore.SIGNAL( ' javaScriptWindowObjectCleared () ' ),self.onObjectClear)
html = xml_utils.XSLTransform(self.xml, ' richedit.xsl ' )
self.browser.setHtml(unicode(html))
def onJSMessage(self,id,msg):
self.html = self.browser.page().mainFrame ().toHtml()
# print unicode(self.html).encode(encoding)
self.setEditText(id,msg)
def resizeEvent(self,s):
size = self.size()
self.tabs.resize(size)
def setEditText(self,id,str,update = False):
t = self.update
self.update = update
e = xml_utils.getElementById(self.xml, id)
e.text = unicode(str)
self.edit.setPlainText(etree.tostring(self.xml,pretty_print = True))
self.update = t
def onTextChanged(self):
if self.update:
try :
self.xml = etree.fromstring(unicode(self.edit.toPlainText()) )
try :
html = xml_utils.XSLTransform(self.xml, ' richedit.xsl ' )
html = unicode(html)
if html:
self.browser.setHtml(html)
self.browser.page().mainFrame().addToJavaScriptWindowObject( ' python ' ,self.pjs)
self.browser.reload()
except Exception,e:
print e
except Exception,e:
print e
def onObjectClear(self):
self.browser.page().mainFrame().addToJavaScriptWindowObject( ' python ' ,self.pjs)
if __name__ == ' __main__ ' :
app = QtGui.QApplication(sys.argv)
frame = MainWindow()
frame.show()
sys.exit(app.exec_())