【问题标题】:code with to-word and to-path in Red language红色语言中带有 to-word 和 to-path 的代码
【发布时间】:2017-09-24 13:27:16
【问题描述】:

我正在尝试使用 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 的错误。问题出在哪里?

【问题讨论】:

    标签: user-interface rebol red


    【解决方案1】:

    您的错误在于尝试使用“/”字符创建单词。

    >> 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。另外,我永远不会喜欢 fld1 或 tout 之类的名字(这是一个实际的词!),但会坚持下去。

    动态命名选择器

    正如我上面提到的,你总是最好从单词开始而不是字符串,就像在 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 的加载值)。

    邻近选择器

    我现在担心的是我们有很多新词在流传,我们需要x 和y。所以让我们回到邻近的概念。

    当您查看您的组合视图规范时:

    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-id 和field-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
        ]
    ]
    

    【讨论】:

    • 它不工作。在填写字段并单击按钮时,我得到*** Script Error: path face/parent/pane/fld1A/text is not valid for none! type; *** Where: get; *** Stack: view do-events do-actor do-safe (即使 fld1A 和 fld2A 中都有数字)。
    • @rnso 正如我所说,这里的问题比你问的要多。
    • 我不想使用数字来查找字段,因为如果存在大量字段,并且添加或删除任何中间字段,则所有数字都必须更改。我们能否获得由我尝试的相同函数创建的不同行的唯一字段名称?
    • 如果必须创建许多相同类型的 gui 对象,最好的方法是什么?我们可以在这里做面向对象的编程吗?
    • 重新。数字:您可以使用第一部分。命名字段,尽管我仍然倾向于反对它。词总是会成为中间人,除了字段之外,你最终会管理很多名称。 wrt。面向对象——绝对是,尽管你必须小心克隆人脸对象的方式。
    【解决方案2】:

    真正的挑战

    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。但是这个你可以自己做。

    【讨论】:

    • to-word 和 to-path 哪里不起作用?谁声称的?
    • @rnso 面是当前显示的对象,如果当前显示的是屏幕面之一 (system/view/screens) 的子级或后代。孩子只是一个面部对象,它是或驻留在设置为face/parent/pane 的块中。 the Red documentation 很好地涵盖了这一点
    猜你喜欢
    • 2020-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-28
    • 1970-01-01
    • 1970-01-01
    • 2016-12-16
    • 1970-01-01
    相关资源
    最近更新 更多