Search code examples
user-interfacesmalltalksqueak

How to display the contents of a dictionary in a morph in smalltalk?


Because I don't seem to be able to find some predefined Morph that can display the contents of a Dictionary, I decided I'd better stop looking and wanted to create my own Morph. I found a nice description how to start with some nice example code to get me started, but quite soon I got to the problem that I don't seem to manage to draw text or anything like that on a canvas.

I created a class

Morph subclass: #DictionaryView
    instanceVariableNames: 'dictionary'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'StatisticsTool'

and I wanted to override drawOn as follows:

drawOn: aCanvas

    | x y |
    x := 0.
    y := 0.
    dictionary associationsDo: [ :assoc |
        aCanvas drawString: assoc key at: x@y.
        aCanvas drawString: assoc value at: x+10@y.
        y := y + 10. ].

I know this is not exactly the best piece of code (I have no idea yet how I should take into account the longest string etc, but I got to this point where I don't even really want to think about that anymore), but I just wanted to get something displayed. Unfortunately, this does not seem to work when I try

d := Dictionary new.
d at: 'test1' put: 5.
d at: 'test2' put: 23.
d at: 'test3' put: 514.

view := DictionaryView new.
view dictionary: d.
view openInWorld.

I get an Error: Instances of SmallInteger are not indexable

I don't know what to do anymore. I actually don't have time to write these long questions or to look a whole week for something like this. This all makes me very nervous and impatient and therefore I would like to excuse myself for the direct way of asking:

How can I display a dictionary in Smalltalk so that I can use it in a GUI?

PS: any tips on coping with stress are also welcome ;)


Solution

  • The source of your error is here

        aCanvas drawString: **assoc key** at: x@y.
        aCanvas drawString: **assoc value** at: x+10@y.
    

    There's no guarantee that any of them will be string (and in your case the values are numbers), so you have to convert them manually

        aCanvas drawString: assoc key printString at: x@y. "or asString"
        aCanvas drawString: assoc value printString at: x+10@y.
    

    You should be able to debug this kind of problem quite easily.

    Regarding the width of string, you can ask a font for the length of a string.

    Preferences standardDefaultTextFont heightOfString: 'hello'
    

    Update:

    You can also simply convert all the values to StringMorphs and compose them together.

    DictionaryView>>dictionary: aDictionary
        | container keys values |
        (container := Morph new)
            layoutPolicy: TableLayout new;
            listDirection: #leftToRight.
        (keys := Morph new) layoutPolicy: TableLayout new.
        (values := Morph new) layoutPolicy: TableLayout new.
        aDictionary
            associationsDo:
                [ :assoc | 
                keys addMorph: assoc key printString asMorph.
                values addMorph: assoc value printString asMorph ].
        container
            addMorph: keys;
            addMorph: values.
        self addMorph: container
    

    (of course remove the #drawOn: method as it will be no longer needed)

    Obviously there's a lot of room for improvement, but that's out of the scope of this Q&A.

    Alternatively you can use the MulticolumnLazyListMorph widget.