2

我在 a 中有字符串namelist,它们对应于应用程序中的变量和字段名称。

该函数应该从 namelist 中读取字符串,添加一个“f”来获取 field_names,然后将变量值放入相应的字段中。

我尝试了以下代码,它没有给出任何错误,但也不起作用:

namelist: ["var1" "var2"]
var1: 5
var2: 10

process: [
    repeat i length? namelist [
        (to-set-path compose rejoin [namelist/:i "f/text"] (to-word namelist/:i))
    ]
]

lay: layout [ 
    text "Values to appear here: "
    var1f: field "a"
    var2f: field "b"

    button "Click" [do process]
]

view lay
4

3 回答 3

6

作为一般观点:将字符串转换为 WORD!s (eg to-word "foo")很容易。但是,很难神奇地制作那个单词!参考绑定到“你的意思的变量”。这样做的狡猾原因与没有范围有关。看:

是否有关于 Rebol 和 Red 中定义范围的总体解释

因此,无论如何,您要尝试做的事情都会有点狡猾。有更好的方法。但是为了避免不问问题,我将解释这里发生的事情以及如何以您尝试的方式解决它。

更正版本仅用于教学目的。请以另一种方式进行。

compose rejoin [namelist/:i "f/text"]

REJOIN 应用于块,并合并内容,结果类型松散地基于第一个元素。 (这是一个有问题的操作,但历史上在 Rebol 代码中很流行。)

因为namelist/:i是一个字符串,所以您的 REJOIN 将生成一个字符串......并且这个字符串最终将被传递给 COMPOSE。但是 COMPOSE 旨在应用于 BLOCK!s...并其中搜索带括号的组,评估它们,同时不理会其余代码。这是一种块模板系统,对其他类型的输入没有影响......所以你会得到相同的字符串。

因此,TO-SET-PATH 被输入了一个字符串!(例如“var1f/text”)。我什至不知道路径转换接受字符串。我发现此操作的行为令人费解,因为它显然会加载字符串,然后使其成为长度为 1 SET-PATH! 的奇异元素。

>> p: to-set-path "foo/bar"
== foo/bar: ;-- huh? really, did that work?

>> type? p
== set-path! ;-- ok, good, I guess.

>> length? p
== 1 ;-- wait, what?

>> type? first p
== path! ;-- a PATH! inside a SET-PATH!...?

>> length? first p
== 2

>> type? first first p
== word!

>> foo: 10
>> get first first p
== 10 ;-- well, at least it's bound

那不是那种 SET-PATH!你要; 你想要一个 SET-PATH!有2个字!元素。转换一个块!到 SET-PATH!将是这样做的一种方式。

to-set-path compose [(load rejoin [namelist/:i "f"]) text]

现在我们看到 COMPOSE 被正确使用了,它会在括号内运行评估,并且不理会这个text词。这会生成一个包含 2 个元素的块,可以轻松地将其转换为 SET-PATH!。我使用 LOAD 而不是 TO-WORD 来处理连接到纯单词转换无法做到的实际变量的一些“魔力”。但这只是一种解决方法——不是确定的事情,而且并不总是问题的答案。

但是产生一个 SET-PATH!并不意味着它运行。如果我说:

s: to-set-word "x"
probe type? s

没有设置字!被执行,它只是生成。在这种情况下,存储在变量 s 中。但是如果我没有将它存储在一个变量中,那么评估产品就会被丢弃......如果我写1 + 1 print "hi". 要执行 SET-PATH!,您需要将它放在一个上下文中,它将被组合成源代码并进行评估。

(注意:Ren-C 有一个称为 EVAL 的原语,它可以即时执行此操作,例如eval (quote x:) 10将 10 分配给 x。)

但在 Red 中,您需要执行以下操作:

namelist: ["var1" "var2"]
var1: 5
var2: 10

process: [
    repeat i length? namelist [
        do probe compose [
            (to-set-path compose [(load rejoin [namelist/:i "f"]) text])
            to-string
            (load namelist/:i)
        ]
    ]
]

lay: layout [ 
    text "Values to appear here: "
    var1f: field "a"
    var2f: field "b"

    button "Click" [do process]
]

view lay

现在您的外部 COMPOSE 正在构建一个 3 元素块,其中第一个元素将是 SET-PATH!,第二个元素是 WORD!这实际上是单独将您的整数转换为字符串,第三个是单词!将被评估为相关的整数。该块的 DO 将具有分配效果。

我把你to-word namelist/:i改成load namelist/:i. 同样,出于我提到的原因...... TO-WORD 本身并没有“绑定”。

我在那里留下了一个 PROBE,这样你就可以看到构建和执行的内容:

[var1f/text: to-string var1]
[var2f/text: to-string var2]

PROBE 是一个非常有用的工具,它输出它的参数但也传递它。您可以在代码中的各个点插入它,以更好地了解正在发生的事情。

(注意:如果您想知道为什么我不建议编写仅适用于 SET-PATH 的窄 EVAL-2 辅助操作!,那是因为这样的东西以更好的名称存在。它称为 SET。set (quote x:) 10然后尝试print x。在事实上,这就是你真正想做的事情的变体......obj: make object! [a: 10]然后......正如我所说set (in obj 'a) 20print obj/a有很多更好的方法可以去做你正在做的事情,但我试图继续专注于做这件事 -你在尝试的方式。)

于 2017-09-21T20:07:01.910 回答
5

尽管似乎解决了您面临的问题,但这并不能直接回答您的问题。它使用face/extra字段将字段关联到您的值列表:

namelist: [var1 var2]
var1: 5
var2: 10

process: function [][
    foreach face lay/pane [
        if find namelist face/extra [
            face/text: form get to word! face/extra
        ]
    ]
]

lay: layout [ 
    text "Values to appear here: "
    field "a" extra 'var1
    field "b" extra 'var2

    button "Click" [process]
]

view lay

唯一的皱纹是:它适用get于在视图规范中设置的单词——它们需要与你正在处理的值处于相同的上下文中,并且——你不能得到一个所以必须在之前lit-word!更改它to word!得到。

如果您想在地图中包含您的值,另一种方法是:

values: #(foo: 5 bar: 10)

process: function [container [object!]][
    foreach face container/pane [
        if find values face/extra [
            face/text: form select values face/extra
        ]
    ]
]

view [ 
    text "Values to appear here: "
    field "a" extra 'foo
    field "b" extra 'bar

    button "Click" [process face/parent]
]
于 2017-09-21T23:06:06.577 回答
3

第 1 步:重构

这是您的代码重新格式化并print添加了 (1) 语句:

namelist: ["var1" "var2"]
var1: 5
var2: 10

process: [
    print "process: start"      ; (1)
    repeat i length? namelist [
        (to-set-path compose rejoin [namelist/:i "f/text"] (to-word namelist/:i))
    ]
    print "process: end"        ; (1)
]

lay: layout [ 
    text "Values to appear here: "
    var1f: field "a"
    var2f: field "b"

    button "Click" [do process]
]

view lay

当我在控制台中运行它并按“单击”时,它会给出以下信息:

process: start
process: end

所以我知道至少按钮有效

第2步:调试print

现在我可以集中精力,print在代码块内移动:

process: [
    repeat i length? namelist [
        print (
            to-set-path compose rejoin [
                namelist/:i "f/text"
            ] (to-word namelist/:i)
        )
    ]
]

几乎立刻我就可以看出这里出了什么问题:

var1    ; expecting `var1f` here
var2    ;

第 3 步:我们需要更深入地了解probe

在旁边

现在,在我继续之前,请注意此代码不会访问视图块内的任何内容(因为它不起作用!)。但这里的好处是你可以忽略这一点,稍后再回来。

您需要的是一种以var1f/text编程方式访问的方法

记住这一点,这里有一个更好的方式来表达这个问题:

步骤 3a:如何objects使用不同的名称动态创建并为它们设置值?

var1f/text: 5

(给定步骤 2 中的代码)

现在,我在这里遇到了一个难题。这可能最好作为一个不同的、更简单的问题来问。

我决定继续假设你完成了这个(还有另一个答案)

笔记

在这一步中要带回家的重要事情是datatype Red 视图使用,而您正在使用的是相同的东西:red objects。没有区别(都是简单人脸对象的实例)

第4步:你完成了!还是你?

所以你可以为你的工作创建你想要的 gui,你就完成了!正确的?

但是你问自己,这是最好的方法吗?如果您想添加更多内容其他内容怎么办?

  1. 您已阅读官方 gui 文档,尤其是有关视图引擎的部分
  2. 您已经查看了vid示例并手动添加视图对象face
  3. 您已经查看了 github 上的 repo 以获取示例代码和小应用程序
  4. 您甚至尝试过旧的但稳定的rebol2

但你还是不明白吗?不要绝望,这很正常。很多东西的名称在概念上与您在其他语言中熟悉的名称相似,但在微妙的方面有所不同,这往往会使它们真正不同。最后,很多事情比你想象的要简单,但更陌生(有更深的含义)

tl;博士

  • 将您的视图代码与其他代码分开,以便于调试
  • 使用print,probedump-face调试
于 2017-09-21T20:36:48.807 回答