Rebol VID MVC:如果 Rebol 不支持自定义事件,如何从模型更新多个视图?

发布于 2024-11-16 04:07:06 字数 74 浏览 3 评论 0原文

假设我有一个具有 2 个同时 VID 表单的模型/控制器。如果 Rebol 不支持自定义事件,我将如何更新指向同一模型的 2 个视图?

Let's say I have a model/controller with 2 simultaneous VID forms. How will I update my 2 views pointing to the same model if Rebol doesn't support custom events ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

青春有你 2024-11-23 04:07:06

我继续并享受了实现属性编辑器 MVC 的乐趣。

这个示例允许您直接从 GUI 动态创建模型和视图,因此它非常适合展示正在运行的系统。

当多个视图编辑相同的数据时,您会看到它们保持同步。多个模型可能各自有多个视图。

这只是一个示例,展示了在 REBOL 中构建 MVC 模式是多么容易。事实上,REBOL 中的许多结构在精神上已经是 MVC,即使它们没有明确地进行营销。

在此处输入图像描述

rebol [
    title: "MVC pattern example"
    purpose: {
        shows an example of a raw MVC pattern in REBOL
        the views can create new models and new views, showing interaction
        between separate models, views  and the controler.
    }
]

model!: context [
    data: none

    views: []

    modify: func [label value][
        set in data label value
    ]


    propagate: func [
        /only label 
        /local view
    ][
        foreach view views [
            either only [
                view/refresh/only label
            ][
                view/refresh
            ]
        ]
    ]
]


view!: context [
    controller: none  ; our controller

    model: none ; our model

    label: none ; what label in data does this view manipulate?

    gui:  [
        across
        space 2x10
        style separator box 275x3 edge [size: 1x1 effect: 'ibevel color: (white * .75)]
    ]

    lbl: none   ; gui face
    fld: none   ; gui face

    refresh: func [/only label][
        ; GENERATE the gui if its not been built for this view yet.
        if block? gui [
            gui: copy/deep gui
            ; add a button for each item of data in the model, clicking on them changes
            ; what the field edits.
            foreach item words-of model/data [
                append gui compose/deep bind/copy [
                    btn (to-string item) [
                        print "^/---"
                        label: (to-lit-word item) 
                        probe label
                        refresh
                    ]
                ] self
            ]
            ; we must bind because the block is being used in new objects created dynamically.
            ; if we don't bind the blocks, they stay bound to the class... important detail.
            append gui copy/deep bind/copy [
                return
                separator
                return
                lbl: h1 200 (to-string label)
                return
                fld: field [controller/modify model label face/text]
                btn "randomize" [controller/randomize model label]
                return
                pad 0x10
                separator
                return
                pad 160x0
                btn "new view" [controller/new-view (model)]
                btn "new model" [controller/new-model]
                btn "close" [unview/only gui]
            ] self
            gui: view/new layout gui
        ]

        ; refresh the gui, when its already built (including on first view)
        if any [
            none? label
            label = self/label
        ] [
            probe model/data
            probe self/label
            fld/text: copy get in model/data self/label
            lbl/text: copy to-string self/label
            show fld
            show lbl
        ]
    ]
]


controller!: context [
    models: []

    ; this just describes how the models should be built, 
    ; it could be a hard-coded in new-model()
    model-data: [sid: "0" name: "unknown" occupation: "unknown"]

    new-model: func [/local model view prev-model prev-view][
        unless empty? models [prev-model: last models]

        append models model: make model! [data: context model-data ]
        view: new-view model

        if prev-model [
            ; tweak window position which is a bit screwed up in rebol
            prev-view: last prev-model/views
            view/gui/offset/x: view/gui/offset/x  + system/view/no-resize-border/x 
            view/gui/offset/y: prev-view/gui/offset/y + prev-view/gui/size/y + system/view/no-resize-border/y 8
            show view/gui 
        ]

        model
    ]

    new-view: func [model /local view prev-view][
        probe model/data
        if not empty? model/views [
            probe length? model/views
            prev-view: last model/views
        ]
        append model/views view: make view! compose [
            model: (model) 
            label: (to-lit-word first words-of model/data) 
            controller: (self) ; here self is the controller, since we are composing 
                               ; the value within a controller function
        ]

        view/refresh
        if prev-view [
            ; tweak window position which is a bit screwed up in rebol
            view/gui/offset/x: prev-view/gui/offset/x + prev-view/gui/size/x     + system/view/no-resize-border/x 
            view/gui/offset/y: prev-view/gui/offset/y - system/view/title-size/y - system/view/no-resize-border/y - 2
            show view/gui 
        ]

        view
    ]


    ; general case "set" operation
    modify: func [model label value][
        model/modify label value
        model/propagate/only label
    ]

    ; just an example controler method
    randomize: func [
        model
        label
    ][
        modify model label random copy get in model/data label
    ]
]





ids: make controller! []

ids/new-model

do-events

I went ahead and had fun implementing a property editor MVC.

this example allows you to create models and views dynamically directly from the GUI, so its pretty good at showing the system in action.

when multiple views edit the same data, you'll see them stay in sync. multiple models may have multiple views each.

This is just an example, showing how easy it is to build MVC patterns in REBOL. in deed, many constructs in REBOL are already MVC in spirit, even if they're not explicitly marketed as such.

enter image description here

rebol [
    title: "MVC pattern example"
    purpose: {
        shows an example of a raw MVC pattern in REBOL
        the views can create new models and new views, showing interaction
        between separate models, views  and the controler.
    }
]

model!: context [
    data: none

    views: []

    modify: func [label value][
        set in data label value
    ]


    propagate: func [
        /only label 
        /local view
    ][
        foreach view views [
            either only [
                view/refresh/only label
            ][
                view/refresh
            ]
        ]
    ]
]


view!: context [
    controller: none  ; our controller

    model: none ; our model

    label: none ; what label in data does this view manipulate?

    gui:  [
        across
        space 2x10
        style separator box 275x3 edge [size: 1x1 effect: 'ibevel color: (white * .75)]
    ]

    lbl: none   ; gui face
    fld: none   ; gui face

    refresh: func [/only label][
        ; GENERATE the gui if its not been built for this view yet.
        if block? gui [
            gui: copy/deep gui
            ; add a button for each item of data in the model, clicking on them changes
            ; what the field edits.
            foreach item words-of model/data [
                append gui compose/deep bind/copy [
                    btn (to-string item) [
                        print "^/---"
                        label: (to-lit-word item) 
                        probe label
                        refresh
                    ]
                ] self
            ]
            ; we must bind because the block is being used in new objects created dynamically.
            ; if we don't bind the blocks, they stay bound to the class... important detail.
            append gui copy/deep bind/copy [
                return
                separator
                return
                lbl: h1 200 (to-string label)
                return
                fld: field [controller/modify model label face/text]
                btn "randomize" [controller/randomize model label]
                return
                pad 0x10
                separator
                return
                pad 160x0
                btn "new view" [controller/new-view (model)]
                btn "new model" [controller/new-model]
                btn "close" [unview/only gui]
            ] self
            gui: view/new layout gui
        ]

        ; refresh the gui, when its already built (including on first view)
        if any [
            none? label
            label = self/label
        ] [
            probe model/data
            probe self/label
            fld/text: copy get in model/data self/label
            lbl/text: copy to-string self/label
            show fld
            show lbl
        ]
    ]
]


controller!: context [
    models: []

    ; this just describes how the models should be built, 
    ; it could be a hard-coded in new-model()
    model-data: [sid: "0" name: "unknown" occupation: "unknown"]

    new-model: func [/local model view prev-model prev-view][
        unless empty? models [prev-model: last models]

        append models model: make model! [data: context model-data ]
        view: new-view model

        if prev-model [
            ; tweak window position which is a bit screwed up in rebol
            prev-view: last prev-model/views
            view/gui/offset/x: view/gui/offset/x  + system/view/no-resize-border/x 
            view/gui/offset/y: prev-view/gui/offset/y + prev-view/gui/size/y + system/view/no-resize-border/y 8
            show view/gui 
        ]

        model
    ]

    new-view: func [model /local view prev-view][
        probe model/data
        if not empty? model/views [
            probe length? model/views
            prev-view: last model/views
        ]
        append model/views view: make view! compose [
            model: (model) 
            label: (to-lit-word first words-of model/data) 
            controller: (self) ; here self is the controller, since we are composing 
                               ; the value within a controller function
        ]

        view/refresh
        if prev-view [
            ; tweak window position which is a bit screwed up in rebol
            view/gui/offset/x: prev-view/gui/offset/x + prev-view/gui/size/x     + system/view/no-resize-border/x 
            view/gui/offset/y: prev-view/gui/offset/y - system/view/title-size/y - system/view/no-resize-border/y - 2
            show view/gui 
        ]

        view
    ]


    ; general case "set" operation
    modify: func [model label value][
        model/modify label value
        model/propagate/only label
    ]

    ; just an example controler method
    randomize: func [
        model
        label
    ][
        modify model label random copy get in model/data label
    ]
]





ids: make controller! []

ids/new-model

do-events
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文