实现基于节点的图形界面?

时间:2009-03-14 04:16:37

标签: python user-interface directed-graph

我想实现一个节点接口,基本上是DAG,其中每个节点对其输入连接执行操作,并输出一些东西(可以连接到另一个节点)

一些示例应用程序:


作为第一个目标,我希望只有2个节点的图形应用程序。一个简单输出一个固定数字的“数字”和一个“加”节点,它取两个输入并输出两者的总和。

正如人们已经回答的那样,我粗略地想知道如何在代码中表示数据,例如在Python中寻找伪代码:

class Number:
    def __init__(self, value):
        self.value = value

    def eval(self):
        return self.value

class Add:
    def __init__(self, input1, input2):
        self.input1 = input1
        self.input2 = input2

    def eval(self):
        return self.input1.eval() + self.input2.eval()


a = Number(20)
b = Number(72)

adder = Add(a, b)
print adder.eval()

我如何围绕此包装自定义GUI?像下面这样的东西,但略少手绘!

nodal UI mockup

我从哪里开始?我目前打算用Objective-C / Cocoa编写它,尽管我对其他语言的建议不仅仅是开放。

7 个答案:

答案 0 :(得分:4)

我首先建模一些基本接口(在OOP意义上,而不是GUI意义上)。在我看来,你将拥有一个Node,它将接受一组输入和一个输出。您没有说明数据类型有多宽,但您需要一些合适的方法来表示您的输入/输出。对于你的第一个目标,这可能是一个整数。

在一些通用的C风格OOP语言中(希望它有意义):

class Node<T> {
    Node<T>[] inputs;
    T eval();
}

class AdderNode extends Node<int> {
    int eval() {
        int accum = 0;
        for (inputs : i)
            accum += i.eval();
        return i;
    }
}

class ConstNode<int I> extends Node<int> {
    int eval() { return I; }
}

AdderNode a;
a.inputs.add(ConstNode<2>());
a.inputs.add(ConstNode<3>());
a.eval();

你可以通过用一些抽象类,泛型或接口替换int来扩展它。当然,实际执行情况将根据实际语言而有所不同。

答案 1 :(得分:2)

我将从有趣的操作建模开始。最终你会将它们连接到用户界面,但那是方向盘和油门踏板,而不是发动机。

您尝试构建的内容与编程语言有很多共同之处:变量,值,类型,表达式,评估等。许多隐喻都适用,可能会提供一些指导。

如果您使用的是.NET 3.5,则可以选择Expression Trees,它允许您在运行时表示和编译代码表达式。

例如,为您的第一个目标建模:

using System.Linq.Expressions;

ConstantExpression theNumber2 = Expression.Constant(2);
ConstantExpression theNumber3 = Expression.Constant(3);

BinaryExpression add2And3 = Expression.Add(theNumber2, theNumber3);

要调用表达式,我们需要使用方法包装add2And3。这是通过lambda表达式完成的:

Expression<Func<int>> add2And3Lambda = Expression.Lambda<Func<int>>(add2And3);

Func<int>表示不带参数并返回int的方法。在C#中,add2And3Lambda表示的代码为:

() => 2 + 3

所以我们所拥有的是一个表达式树,其根是一个方法。因为方法是 callable ,所以我们可以将树编译成底层委托类型的实例:

Func<int> add2And3Func = add2And3Lambda.Compile();

现在我们可以调用我们构建的代码:

int theNumber5 = add2And3Func();

支持.NET语言可用的每个表达式。

想象一下,图表中的每个节点都与Expression相关联。这可能会让您了解表达树的强大功能以及它们如何帮助您完成此任务。

答案 2 :(得分:1)

所有节点系统都有共同点,它们描述了一种函数式编程语言。函数接受多个参数并返回单个结果,无论其设计目的是什么。一些例子:

  • 图形:模糊(图像,内核,半径) - &gt;图像

  • 数学:添加(数字,数字) - &gt;编号

  • 关系:过滤器(表,谓词) - &gt;表

基本上归结为像Func<object[], object>(C#)这样的函数签名。

您将面临如何使节点系统持久化的问题。您是否希望仅通过一个其他节点(树)或多个节点(图形)使节点的结果可用作参数?

树的示例,直接具有子节点的参数:

Add(
  Multiply(
    Constant(5),
    Constant(4)
  ),
  Multiply(
    Constant(5),
    Constant(3)
  )
)

图表示例,将所有节点存储在列表中并仅使用引用:

A := Constant(5)
B := Constant(4)
C := Constant(3)

D := Func(Multiply, A, B)
E := Func(Multiply, A, C)

F := Func(Add, D, E)

答案 3 :(得分:1)

我发现了一些关于在Cocoa中实现这样一个接口的有用信息:

答案 4 :(得分:0)

也许bwise有兴趣吗?

this page的下半部分显示了使用bwise创建一个乘以两个数字作为输入的乘法块的示例。

答案 5 :(得分:0)

我实现了一个像你在这个项目中描述的执行图: GRSFramework

可以找到源代码here

目前,我正致力于在项目ExecutionGraph中发布更好,更清洁的此系统版本 它也可能对你很感兴趣。

然后还有来自Google的TensorFlow库,它实现了类似的系统TensorFlow

答案 6 :(得分:0)

我在研究类似的解决方案时偶然发现了这个问题。 最近我在github上发现了一个不错的项目https://github.com/nodebox/nodebox 这似乎正是你要找的。至少有一个人可以从项目中提取和采用编辑器组件。

此致 斯蒂芬