使用红色语言的to-word和to-path代码

时间:2017-09-24 13:27:16

标签: user-interface rebol red

我正在尝试使用compose:

通过单个函数创建2个面板
make-panel: func [sentchar][
     probe compose/deep [
        text "N1:"    
        (to-set-word rejoin["fld1" sentchar ":"]) field    ; TO BE NAMED fld1A and fld1B for 2 panels
        text "N2: "   
        (to-set-word rejoin["fld1" sentchar ":"]) field    ; TO BE NAMED fld2A and fld2B for 2 panels      
        text "Product: "    
        (to-set-word rejoin ["txt_out" sentchar ":"]) text    ; TO BE NAMED txt_outA and txt_outB for 2 panels
        button "Get product" [ 
           x: to-path to-word (rejoin ["face/parent/pane/fld1" sentchar "/text"])
           y: to-path to-word (rejoin ["face/parent/pane/fld2" sentchar "/text"])
           (to-set-path (to-path rejoin ["face/parent/pane/txt_out" sentchar "text"] )) 
                form multiply get x get y  ]  ] ]

view compose [
    (make-panel "A") return 
    (make-panel "B") return ]

然而,即使我尝试过不同的组合,我也会遇到关于to-word和to-path的错误。问题在哪里?

2 个答案:

答案 0 :(得分:5)

您的错误是尝试使用" /"创建一个单词。字符。

>> to-word "foo/bar"
*** Syntax Error: invalid character in: "foo/bar"
*** Where: to
*** Stack: to-word  

我的第二个倾向是你不应该使用字符串来组成值引用 - 如果没有别的东西你会失去约束力。可以尝试以下方法:

to path! compose [face parent pane (to word! rejoin ["fld2" sentchar]) text]

我的第一个倾向是你过度复杂,但这超出了你的问题的范围。

更新

我将尝试解决此代码中的一些其他问题:

命名

关于make-panel的说明 - 由于您没有制作panel,这只是一个误称,只是将一些元素规格组合在一起。出于本答案的目的,我将使用名称make-row。此外,我永远不会喜欢fld1tout这个名字(这是一个真实的词!)但会坚持不懈。

动态命名选择器

正如我上面提到的,你总是更好地从单词和字符串开始,如在Rebol / Red中,单词在评估期间获取上下文 - 从字符串加载的单词不会。例如:

make object! [
    foo: "bar"
    probe get first [foo] ; "bar"
    probe get first load "[foo]" ; error
]

在您创建三个新单词时,让我们明确地这样做:

make-row: function [row-id [string!]][
    fld1: to word! rejoin ["fld1-" row-id]
    fld2: to word! rejoin ["fld2-" row-id]
    tout: to word! rejoin ["tout-" row-id] ; note that 'tout is an English word

    ...
]

从这里开始,我们可以在规范中开始构建独特的参考资料。

make-row: func [row-id [string!] /local fld1 fld2 tout][
    fld1: to word! rejoin ["fld1-" row-id]
    fld2: to word! rejoin ["fld2-" row-id]
    tout: to word! rejoin ["tout-" row-id]

    compose/deep [
        text "N1:"
        (to set-word! fld1) field
        text "N2:"
        (to set-word! fld2) field
        text "Product:"
        (to set-word! tout) text
        button "Get Product" [
            ...
        ]
        return
    ]
]

现在我们通过此按钮操作进入粘性区域:

x: to-path to-word (rejoin ["face/parent/pane/fld1" sentchar "/text"])
y: to-path to-word (rejoin ["face/parent/pane/fld2" sentchar "/text"])
(to-set-path (to-path rejoin ["face/parent/pane/tout" sentchar "text"] )) 
     form multiply get x get y  ]  ] ]

我认为可以用伪代码表达你想要做的事情:

Product = text of product of N1 for this row * N2 for this row

此处代码中的主要错误是您将邻近引用与命名引用混合在一起。如果您检查face/parent/pane,那里没有fld1*fld2*tout*引用,它只是一个面对象块。在您努力创造独特名称的同时,让我们暂时继续这样做。请记住,我们仍处于compose/deep操作的深处:

x: get in (fld1) 'data
y: get in (fld2) 'data
set in (tout) 'text form x * y

我们现在更加简洁,一切都应该有效(请注意'data为您提供'text的加载值。

接近选择器

我关注的是,我们有很多新的词汇,我们需要xy。因此,让我们回到接近的想法。

当您查看撰写的View规范时:

view probe compose [
    (make-row "A")
    (make-row "B")
]

您会看到您的主视图面将包含很多孩子。要查找您要点击的按钮附近的面孔,我们首先需要找到面部内的按钮。让我们这样做:

button "Get Product" [
    this: find face/parent/pane face
]

由于与该按钮相关联的前六个面孔,让我们转到这一组的开头:

button "Get Product" [
    this: skip find face/parent/pane face -6
]

现在我们可以根据接近程度进行计算:

button "Get Product" [
    here: find face/parent/pane face
    here/6/text: form here/2/data * here/4/data
]

轰!我们的产品只有一个here而不是rows-count * 3 + x + y。真棒!

由于我们没有生成任何其他字词,我们甚至不需要一个函数来生成我们的行,归结为以下几点:

row: [
    text "N1:" field
    text "N2: " field
    text "Product: " text 100
    button "Get product" [
        ; go back six faces from current face
        here: skip find face/parent/pane face -6
        here/6/text: form here/2/data * here/4/data
    ]
    return
]

view compose [
    (row)
    (row)
]

组选择器

由于您似乎有复杂的需求并且无法始终枚举您需要的字段,因此您可以使用extra字段将字段组合在一起。我们可以使用块来包含row-idfield-id

make-row: func [row-id][
    compose/deep [
        text "N1:" field extra [(row-id) "N1"]
        text "N2: " field extra [(row-id) "N2"]
        text "Product: " text 100 extra [(row-id) "Output"]

        button "Get product" extra (row-id) [
            ...
        ]
        return
    ]
]

view compose [
    (make-row "A") 
    (make-row "B")
]

在按钮操作中,我们可以收集与该行相关联的所有面:

faces: make map! collect [
    foreach kid face/parent/pane [
        if all [
            block? kid/extra
            face/extra = kid/extra/1
        ][
            keep kid/extra/2
            keep kid
        ]
    ]
]

这给你一张漂亮的地图!与所有相关的面和一个简单的计算:

faces/("Output")/text: form faces/("N1")/data * faces/("N2")/data

如果您只是将其用于产品,那么您甚至不需要收集:

product: 0
foreach kid face/parent/pane [
    if all [
        block? kid/extra
        face/extra = kid/extra/1
    ][
        product: product + kid/value
    ]
]

答案 1 :(得分:1)

真正的挑战

make-panel: func [sentchar][
    compose/deep [
        text "N1:"  (to-set-word rejoin['fld1 sentchar ]) field    ; TO BE NAMED fld1A and fld1B for 2 panels
        text "N2:"  (to-set-word rejoin['fld2 sentchar ]) field    ; TO BE NAMED fld2A and fld2B for 2 panels      
        text "Product: "  (to-set-word rejoin ['tout sentchar]) text    ; TO BE NAMED toutA and toutB for 2 panels
        button "Get product" [ 
            x:   ( to-path reduce   [ to-word  rejoin ["fld1" sentchar]  'text ])  
            y:    (to-path reduce   [ to-word  rejoin ["fld2" sentchar]  'text ])   
            (to-set-path reduce [to-word rejoin ["tout" sentchar] 'text])   form multiply load  x load  y
        ] 
    ]
]

view v: compose   [
    (make-panel "A") return 
    (make-panel "B") return 
]

当然,您不需要中间词 x y 。但是你可以自己做。