【问题标题】:Using a DOT graph as a basis for tree GUI使用 DOT 图作为树形 GUI 的基础
【发布时间】:2013-07-24 07:51:24
【问题描述】:

我想使用由 DOT(python 中的 pyDot)生成的图形作为交互式树结构 GUI 的基础,其中树中的每个节点都可以是小部件。

这棵树基本上是一个二进制莫尔斯电码树,它从顶部节点开始向下导航到所需的字母并选择它。他们要选择的节点应该是可突出显示的,并且其内容(字母)应该能够根据用户输入进行更改。

基本上,我希望将节点变成具有可调参数的全尺寸对象,这些参数会随着接口的使用而改变。谁能指出我正确的方向来做到这一点?

【问题讨论】:

    标签: python wxpython dot pygraphviz pydot


    【解决方案1】:

    我从http://wiki.wxpython.org/AnotherTutorial#wx.TreeCtrl 的演示代码开始。我添加了 build_tree、_build_tree_helper 和 build_conn_dict 方法。 dot_parser 库中感兴趣的关键方法是 edge.get_source() 和 edge.get_destination(),它们用于制作“连接”字典。

    点图存储在 dot_data 变量中。重要的是,点图不得循环;也就是说,它必须是生成树,否则 _build_tree_helper 方法将无限循环(并且在 TreeControl 中没有意义)。

    我还必须根据 https://github.com/nlhepler/pydot-py3/issues/1#issuecomment-15999052 修补 dot_parser 以使其正常工作。

    import wx
    
    from dot_parser import parse_dot_data
    
    class MyFrame(wx.Frame):
        def __init__(self, parent, id, title, **kwargs):
            self.parsed_dot = kwargs.pop("parsed_dot", None)
            wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(450, 350))
    
            hbox = wx.BoxSizer(wx.HORIZONTAL)
            vbox = wx.BoxSizer(wx.VERTICAL)
            panel1 = wx.Panel(self, -1)
            panel2 = wx.Panel(self, -1)
    
            self.tree = wx.TreeCtrl(panel1, 1, wx.DefaultPosition, (-1,-1), wx.TR_HAS_BUTTONS | wx.TR_LINES_AT_ROOT )
            self.build_tree(self.tree)
            self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged, id=1)
            self.display = wx.StaticText(panel2, -1, "",(10,10), style=wx.ALIGN_CENTRE)
            vbox.Add(self.tree, 1, wx.EXPAND)
            hbox.Add(panel1, 1, wx.EXPAND)
            hbox.Add(panel2, 1, wx.EXPAND)
            panel1.SetSizer(vbox)
            self.SetSizer(hbox)
            self.Centre()
    
        def build_conn_dict(self):
            conn_dict = {}
            if(self.parsed_dot):
                for edge in self.parsed_dot.get_edges():
                    conn_dict.setdefault(edge.get_source(), []).append(edge.get_destination())
            return conn_dict
    
        def build_tree(self, tree):
            if(self.parsed_dot):
                conn_dict = self.build_conn_dict()
                outs = set(conn_dict.keys())
                ins = reduce(lambda x, y: x | set(y), conn_dict.values(), set([]))
                roots = list(outs - ins)
                roots = dict([(root, tree.AddRoot(root)) for root in roots])
                self._build_tree_helper(tree, conn_dict, roots)
    
        def _build_tree_helper(self, tree, conn_dict = {}, roots = {}):
            new_roots = {}
            for root in roots:
                if(conn_dict.has_key(root)):
                    for sub_root in conn_dict[root]:
                        new_roots[sub_root] = tree.AppendItem(roots[root], sub_root)
            if(new_roots):
                self._build_tree_helper(tree, conn_dict, new_roots)
    
        def OnSelChanged(self, event):
            item =  event.GetItem()
            self.display.SetLabel(self.tree.GetItemText(item))
            child_text = self.tree.GetItemText(item)
            parent_text = ""
            try:
                parent = self.tree.GetItemParent(item)
                parent_text = self.tree.GetItemText(parent)
            except wx._core.PyAssertionError:
                pass
            print "child: %s, parent: %s" % (child_text, parent_text)
    
    class MyApp(wx.App):
        def OnInit(self):
            dot_data = \
            '''
            graph ""
            {
                    label="(% (EXP (% (X) (% (X) (X)))) (EXP (SIN (X))))"
                    n039 ;
                    n039 [label="%"] ;
                    n039 -> n040 ;
                    n040 [label="EXP"] ;
                    n040 -> n041 ;
                    n041 [label="%"] ;
                    n041 -> n042 ;
                    n042 [label="X"] ;
                    n041 -> n043 ;
                    n043 [label="%"] ;
                    n043 -> n044 ;
                    n044 [label="X"] ;
                    n043 -> n045 ;
                    n045 [label="X"] ;
                    n039 -> n046 ;
                    n046 [label="EXP"] ;
                    n046 -> n047 ;
                    n047 [label="SIN"] ;
                    n047 -> n048 ;
                    n048 [label="X"] ;
            }
            '''        
            parsed_dot = parse_dot_data(dot_data)
            frame = MyFrame(None, -1, "treectrl.py", parsed_dot = parsed_dot)
            frame.Show(True)
            self.SetTopWindow(frame)
            return True
    
    app = MyApp(0)
    app.MainLoop()
    

    【讨论】:

    • 虽然这很有趣,但这不是我想要的。我希望将物理树作为一个对象进行交互(例如,单击节点并移动它们等),而不仅仅是将它们可视化为 treectrl
    • 在这种情况下,您需要gephi.org。我认为它可以读取点文件等。它是用 Java 编写的,但是您可以为其获取 Jython 解释器,并在需要时使用 Python 对其进行控制。
    猜你喜欢
    • 2018-12-30
    • 1970-01-01
    • 1970-01-01
    • 2016-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-05
    相关资源
    最近更新 更多