Making GUI objects in Red language

2019-03-06 16:20发布

问题:

I have following simple code for a small panel:

view [
    t: text "label"
    f: field
    button "Click here" [t/text: f/text]    ]

But I have to make 2 of them and put them on one window. I want to create single object class and make 2 objects out of it. I see that objects can be created as follows:

obj: object [
    view [
        t: text "label"
        f: field
        button "Click here" [t/text: f/text] ]  ]

view [
    obj
    obj     ]

But I get following error:

*** Script Error: VID - invalid syntax at: [obj obj]
*** Where: do
*** Stack: view layout cause-error 

How can this be done? Thanks for your help.

Edit: I tried with do but could manage only with does:

  myview: object [
      show: does [view[
        below
        t: text "1st time"
        f: field "Enter value"
        button "Click here" [f/text "clicked"]
        area] ] ]

  myview/show

  print "READY TO SHOW 2nd OBJECT: "
  myview2: copy myview
  myview2/show

回答1:

I want to create single object class and make 2 objects out of it.

There is no object class system in Red, so you should really try first to grasp the basic Red concepts before trying more complex GUI constructs. Red is a very flexible data-oriented language, so you can use that to your advantage by, for example, building parametrized block templates, and assembling them to form a correct block of VID code. Here is an example:

make-row: func [label [string!] but-label [string!]][
    compose [
        t: text (label)
        f: field
        b: button (but-label) [face/extra/1/text: face/extra/2/text]
        do [b/extra: reduce [t f]]
    ]
]

view compose [
    (make-row "label" "Click") return
    (make-row "label2" "Click2")
]

Understanding the face tree (analog to the HTML DOM, just way simpler), is an important part of mastering Red's GUI system. As there is no much documentation yet (you can start with http://docs.red-lang.org), you are welcome to ask live questions on red/help Gitter room.



回答2:

To work with objects instead of in the VID dialect, replace view with layout:

lay: layout [
    t: text "label"
    f: field
    button "Click here" [t/text: f/text]
]

view lay

You can then inspect it like any other object: ?? lay.

For example, to access the contents of lay with pane:

>> ? lay/pane/1

However, a more useful function may be dump-face:

>> dump-face lay
 Type: window Style: none Offset: 833x548 Size: 270x45 Text: "Red: untitled"
     Type: text Style: text Offset: 10x10 Size: 80x24 Text: "label"
     Type: field Style: field Offset: 100x10 Size: 80x24 Text: none
     Type: button Style: button Offset: 190x9 Size: 70x25 Text: "Click here"
== make object! [
    type: 'window
    offset: 833x548
 ...

panels are useful to group objects together:

>> dump-face blay: layout [p: panel button "hi"]
 Type: window Style: none Offset: none Size: 292x220 Text: none
     Type: panel Style: panel Offset: 10x10 Size: 200x200 Text: none
     Type: button Style: button Offset: 220x9 Size: 62x25 Text: "hi"
== make object! [
    type: 'window
    offset: none
    ...

But it's probably easier to use the VID dialect with compose to build up stuff first.

See also this question



回答3:

I guess what you are looking for are styles and not objects in order to create a layout. Until now there is no official stylize function in Red. But you can create your layout dynamically like this

view repeat i 2 [
    tname: to-word rejoin ['t i]
    fname: to-word rejoin ['f i]
    append v: [] compose/deep [ 
        (to-set-word tname) text "label"
        (to-set-word fname) field
        button "click here"   [
          (to-set-path  compose [(tname) text])  
          (to-path  compose [(fname) text])
        ] 
    ] 
]

You can just append a predefined block of words many times to the block you want to view and you will get repeated elements.

 txt_btn: [
    t: text "label"
    f: field
    button "Click here" [t/text: f/text] 
 ] 
 view append append [] txt_btn txt_btn

The problem arises as you refer to a named element in your block. But a word can not point to more than one element of the repeated elements, therefore the usage of compose in the complete solution in order to create unique names.

Maybe there is a bug in Red because I thought compose/deep would also do parentheses deep inside and not need more compose –