问题
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 StringMorph
s 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