将信息从Javascript应用程序发送到包含PyQt应用程序

时间:2014-04-30 06:05:59

标签: javascript python pyqt qwebview

我正在使用PyQt应用程序,该应用程序在QWebView中使用d3显示交互式网络。当用户点击该网络中的节点时,我想将节点的ID从Javascript应用程序发送到PyQt应用程序。我试图让它与pyqtSlot装饰器一起工作,但我遇到了问题。

当我第一次将HTML加载到QWebView并公开ConnectionContainer时,我可以从Javascript成功调用Python中的change_page方法。当我尝试在click事件处理程序中调用该方法时," container",Javascript中的Python对象的名称似乎不再存在并导致错误。

如何存储此Python对象以便鼠标事件处理程序可以看到它?

Python代码:

from PyQt4.Qt import (QStandardItem, QStandardItemModel, Qt, QFont,
    QWebView, pyqtSlot, QObject)
from calibre.ebooks.oeb.display.webview import load_html

class TOCView (QWebView):

def __init__(self, *args):
    QWebView.__init__(self, *args)

    self.container = ConnectionContainer()
    self.page().mainFrame().addToJavaScriptWindowObject("container", self.container)
    self.load_network()

def set_manager(self, manager):
    self.container.manager = manager

def load_network(self):
    path = 'C:/Users/Emily/Documents/Spring 2014/MART510 eBook Research/book_renderer.html'
    load_html(path, self, codec=getattr(path, 'encoding', 'utf-8'), mime_type=getattr(path,
    'mime_type', 'text/html'))

class ConnectionContainer(QObject):

def __init__(self):
    QObject.__init__(self)
    self.manager = None

def set_manager(self, manager):
    self.manager = manager

@pyqtSlot(float)
def change_page(self, page):
    print ("changed page")
    if self.manager is not None:
        self.manager.goto_page(page)

HTML / Javascript代码:

  <!DOCTYPE html> 
  <meta charset="utf-8">
  <body> 
 <style> 
.link {  
stroke: #666;
opacity: 0.6;
stroke-width: 1.5px; 
} 
.node circle { 
stroke: #fff; 
opacity: 0.6;
stroke-width: 1.5px; 
} 
text { 
font: 7px serif; 
opacity: 0.6;
pointer-events: none; 
} 
</style> 

<script src=d3.v3.min.js></script>

<script> 
d3.json("eBookGraph.json", dataLoaded)

function dataLoaded(data) {
        var links = data.links
        var nodes = data.nodes

    // Compute the distinct nodes from the links.
    links.forEach(function(link) {
        link.source = nodes[link.source] || 
        (nodes[link.source] = {name: link.source});
        link.target = nodes[link.target] || 
        (nodes[link.target] = {name: link.target});
        link.value = +link.value;
    });

    var width = 500
    height = 500;

    var force = d3.layout.force() 
        .nodes(d3.values(nodes)) 
        .links(links) 
        .size([width, height]) 
        .linkDistance(50) 
        .charge(-200) 
        .on("tick", tick) 
        .start(); 

    var svg = d3.select("body")
        .append("svg")
          .attr({
            "width": "100%",
            "height": "100%"
          })
          .attr("viewBox", "0 0 " + width + " " + height )
          .attr("preserveAspectRatio", "xMidYMid meet")
          .attr("pointer-events", "all")
        .call(d3.behavior.zoom().on("zoom", redraw));

    var vis = svg
        .append('svg:g');

    function redraw() {
      vis.attr("transform",
          "translate(" + d3.event.translate + ")"
          + " scale(" + d3.event.scale + ")");
    }

    var link = svg.selectAll(".link") 
        .data(force.links()) 
        .enter().append("line") 
        .attr("class", "link")
        .style("opacity", 0.4); 

    var node = svg.selectAll(".node") 
        .data(force.nodes()) 
        .enter().append("g") 
        .attr("class", "node") 
        .on("mouseover", mouseover) 
        .on("mouseout", mouseout) 
        .on("click", click)
        .on("dblclick", dblclick)
        .call(force.drag); 

    node.append("circle") 
        .attr("r", 8)
        .style("fill", "#3182bd");

    node.append("text") 
        .attr("x", 12) 
        .attr("dy", ".35em") 
        .attr("page", function(d) { return d.id; })
        .style("fill", "#000000")
        .text(function(d) { return d.title; });

    function tick() { 
        link 
        .attr("x1", function(d) { return d.source.x; }) 
        .attr("y1", function(d) { return d.source.y; }) 
        .attr("x2", function(d) { return d.target.x; }) 
        .attr("y2", function(d) { return d.target.y; }); 

        node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); 
    }

    // "change page" printed to console here
    container.change_page(1.0)

    function mouseover() { 
    } 

    function mouseout() { 
    } 

    function click() {
        pageNum = d3.select(this).select("text").attr("page")
        alert(pageNum)

        // error here
        container.change_page(pageNum)
        alert("4")
    }

    function dblclick() {
    }
}



</script>
 </body>

1 个答案:

答案 0 :(得分:0)

事实证明,我需要在HTML完成加载后公开容器对象。

class TOCView (QWebView):

    def __init__(self, *args):
        QWebView.__init__(self, *args)

        self.manager = None
        self.loadFinished.connect(self.load_finished)
        self.load_network()

    def load_finished(self):
        self.page().mainFrame().addToJavaScriptWindowObject("container", self)

    def set_manager(self, manager):
        self.manager = manager

    def load_network(self):
        path = 'C:/Users/Emily/Documents/Spring 2014/MART510 eBook Research/book_renderer.html'
        load_html(path, self, codec=getattr(path, 'encoding', 'utf-8'), mime_type=getattr(path,
        'mime_type', 'text/html'))

    @pyqtSlot(float)
    def change_page(self, page):
        print ("changed page: " + str(page))
        if self.manager is not None:
            self.manager.goto_page(page)