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

荒凉一梦 提交于 2019-12-11 12:48:39

问题


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 ;)


回答1:


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.




回答2:


working with Canvas and its drawing API is mostly about implementing your own base Morphs. If you want to build a GUI, you can try to use existing Morphs as building blocks.

Just like Debugger/Inspector don't implement their own list morphs, you can use existing classes. LazyListMorphs are used by PluggableListMorphs. You can plugin a model that provides the list and some selectors for list selection behavior.

|list listMorph|
list := Smalltalk allClasses.
listMorph := PluggableListMorph on:list list:#yourself selected:nil changeSelected:nil.
listMorph openInHand

This is a simple example. In a real world application, you would implement a model class that provides the list (see Inspector or other tools).

If you want to list dictionary contents, you can built a multicolumn listMorph for both "sublists" (keys, values), another multicolumn example:

|listOfLists listMorph|
listOfLists := { (1 to:100) asArray . (1 to:100) collect:[:x | x * x]}.
listMorph := PluggableMultiColumnListMorph on:listOfLists list:#yourself     selected:nil changeSelected:nil.
listMorph openInHand


来源:https://stackoverflow.com/questions/34475268/how-to-display-the-contents-of-a-dictionary-in-a-morph-in-smalltalk

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!