Hi, I
am having a problem with a Dataset on one of my canvases. The Dataset has 3 fields, selection (a checkbox) and two
display only text fields. On one of my canvases the checkbox will not accept a check
when clicked but, the other one works correctly. On the map I have the selection aspect defined as follows ………
selectedRow isSelected If I get rid of the isSelected the checkbox accepts the check
when clicked but, I really need isSelected. Any ideas would be appreciated!! Thanks Michael Gross Blue Heron Consulting _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
What is the best way to create a widget for drawing graphics? I essentially need to recreate the functionality of the Digitalk Smalltalk/V GraphPane.
-It needs to allow arbitrary drawing of graphics -It must support scrollbars -It must allow for the capturing of mouse and keyboard events -It needs to redraw damage automatically It sure would be great if VisualWorks would come with a ready to use widget that does all this. I'm looking for the most straightforward way to do this. Should I create a subclass of View with my drawing functions and a companion Spec class? Does the View somehow get an event which can be used to trigger a redraw? Do I create a Controller to manage the keyboard and mouse events? Is there is a really simple example I can crib some code from? -Carl Gundel http://www.libertybasic.com http://www.runbasic.com _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Have a peek at 'GF/ST Demo' parcel,
GFDemoLauncher open. CubeInterface open. etc -Boris -----Original Message----- From: [hidden email] [mailto:[hidden email]] On Behalf Of Carl Gundel Sent: Thursday, July 21, 2011 11:17 PM To: VWNC Subject: [vwnc] [7.8] Best way to create a GraphPane What is the best way to create a widget for drawing graphics? I essentially need to recreate the functionality of the Digitalk Smalltalk/V GraphPane. -It needs to allow arbitrary drawing of graphics -It must support scrollbars -It must allow for the capturing of mouse and keyboard events -It needs to redraw damage automatically It sure would be great if VisualWorks would come with a ready to use widget that does all this. I'm looking for the most straightforward way to do this. Should I create a subclass of View with my drawing functions and a companion Spec class? Does the View somehow get an event which can be used to trigger a redraw? Do I create a Controller to manage the keyboard and mouse events? Is there is a really simple example I can crib some code from? -Carl Gundel http://www.libertybasic.com http://www.runbasic.com _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Yeah, I looked at that thanks.
Too many moving parts. I'll give another try. -Carl Gundel Liberty BASIC for Windows - http://www.libertybasic.com Run BASIC, easy web programming - http://www.runbasic.com On Jul 22, 2011, at 3:16 AM, "Boris Popov, DeepCove Labs" <[hidden email]> wrote: > Have a peek at 'GF/ST Demo' parcel, > > GFDemoLauncher open. > CubeInterface open. > etc > > -Boris > > -----Original Message----- > From: [hidden email] [mailto:[hidden email]] On > Behalf Of Carl Gundel > Sent: Thursday, July 21, 2011 11:17 PM > To: VWNC > Subject: [vwnc] [7.8] Best way to create a GraphPane > > What is the best way to create a widget for drawing graphics? I > essentially need to recreate the functionality of the Digitalk > Smalltalk/V GraphPane. > > -It needs to allow arbitrary drawing of graphics -It must support > scrollbars -It must allow for the capturing of mouse and keyboard events > -It needs to redraw damage automatically > > It sure would be great if VisualWorks would come with a ready to use > widget that does all this. > > I'm looking for the most straightforward way to do this. Should I > create a subclass of View with my drawing functions and a companion Spec > class? Does the View somehow get an event which can be used to trigger > a redraw? Do I create a Controller to manage the keyboard and mouse > events? > > Is there is a really simple example I can crib some code from? > > -Carl Gundel > http://www.libertybasic.com > http://www.runbasic.com > _______________________________________________ > vwnc mailing list > [hidden email] > http://lists.cs.uiuc.edu/mailman/listinfo/vwnc > > _______________________________________________ > vwnc mailing list > [hidden email] > http://lists.cs.uiuc.edu/mailman/listinfo/vwnc _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by Carl Gundel
On Jul 21, 2011, at 8:16 PM, Carl Gundel wrote: > What is the best way to create a widget for drawing graphics? I essentially need to recreate the functionality of the Digitalk Smalltalk/V GraphPane. > > -It needs to allow arbitrary drawing of graphics > -It must support scrollbars > -It must allow for the capturing of mouse and keyboard events > -It needs to redraw damage automatically > > It sure would be great if VisualWorks would come with a ready to use widget that does all this. > > I'm looking for the most straightforward way to do this. Should I create a subclass of View with my drawing functions and a companion Spec class? Does the View somehow get an event which can be used to trigger a redraw? Do I create a Controller to manage the keyboard and mouse events? > > Is there is a really simple example I can crib some code from? 1) Make a new subclass of VisualPart (CarlsView). 2) Add a #displayOn: method. Look at examples. You get a GC, and draw with it. 3) Implement a #preferredBounds method. This should return a zero origin rectangle showing the current size of your view. Many people cheat and just use 'Screen default bounds'. In your case, where you want to be able to put it inside of a scroller, you probably want to be more precise. 4) add the methods #getEventHandler (just return self), #handleEvent (steal the one line implementation from ClickableGraphic), and #handlerForMouseEvent: (ClickableGraphic has a good simple example of this too). 5) For any (mouse) event you want to capture, add arbitrary method(s) (single arg or no arg) with a tag like <event: #MouseMove> and then do your code in there. Most of the results in a 'Browse senders of #event:' will show examples of different event types and how to do interesting things with the event object that may be passed to your method (if it's not unary). You want the ones with the little keyboard/pointer icon. I would recommend reading the 'Event Reactions' section in the 7.8 release notes. 6) If you want to do keyboard events too, you add the same arbitrary tagged method for either the #KeyDown or #KeyUp event types. But you have to add a number of methods to your VisualPart to do the keyboard dance. For the whole list of them, see the release notes for 7.8, under the section 'Focus Navigation API'. Most of these do things like return true, false, or nil. I wish the above were even simpler, not requiring as many "scaffolding" methods to be implemented, but that's the tradeoffs of having to live in a backwards compatible world. You can alternately do it the "classic" MVC way, by making your CarlsView a subclass of View rather than a VisualPart and creating a CarlsController, figure out what your model is, etc. There's an example of how to make View/Controller pair in the chapter 5 of the GUIDevGuide. I prefer the "new" approach personally, I've done a lot lot lot lot of SketchController approach since 1992. You should not need to make a new Spec class, unless you want to be able to use the UIPainter to paint your views. Even then, you can just use the ArbitraryViewSpec to specify instances of your custom views. HTH -- Travis Griggs Objologist Light travels faster than sound. This is why some people appear bright until you hear them speak... _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Thanks Travis,
Do I then also need to implement a CarlsSpec class and add methods to the UILookPolicy class in order to use my View subclass, or is there some shortcut? -Carl Gundel http://www.libertybasic.com http://www.runbasic.com On Jul 22, 2011, at 12:45 PM, Travis Griggs wrote: > > On Jul 21, 2011, at 8:16 PM, Carl Gundel wrote: > >> What is the best way to create a widget for drawing graphics? I essentially need to recreate the functionality of the Digitalk Smalltalk/V GraphPane. >> >> -It needs to allow arbitrary drawing of graphics >> -It must support scrollbars >> -It must allow for the capturing of mouse and keyboard events >> -It needs to redraw damage automatically >> >> It sure would be great if VisualWorks would come with a ready to use widget that does all this. >> >> I'm looking for the most straightforward way to do this. Should I create a subclass of View with my drawing functions and a companion Spec class? Does the View somehow get an event which can be used to trigger a redraw? Do I create a Controller to manage the keyboard and mouse events? >> >> Is there is a really simple example I can crib some code from? > > 1) Make a new subclass of VisualPart (CarlsView). > 2) Add a #displayOn: method. Look at examples. You get a GC, and draw with it. > 3) Implement a #preferredBounds method. This should return a zero origin rectangle showing the current size of your view. Many people cheat and just use 'Screen default bounds'. In your case, where you want to be able to put it inside of a scroller, you probably want to be more precise. > 4) add the methods #getEventHandler (just return self), #handleEvent (steal the one line implementation from ClickableGraphic), and #handlerForMouseEvent: (ClickableGraphic has a good simple example of this too). > 5) For any (mouse) event you want to capture, add arbitrary method(s) (single arg or no arg) with a tag like <event: #MouseMove> and then do your code in there. Most of the results in a 'Browse senders of #event:' will show examples of different event types and how to do interesting things with the event object that may be passed to your method (if it's not unary). You want the ones with the little keyboard/pointer icon. I would recommend reading the 'Event Reactions' section in the 7.8 release notes. > 6) If you want to do keyboard events too, you add the same arbitrary tagged method for either the #KeyDown or #KeyUp event types. But you have to add a number of methods to your VisualPart to do the keyboard dance. For the whole list of them, see the release notes for 7.8, under the section 'Focus Navigation API'. Most of these do things like return true, false, or nil. > > I wish the above were even simpler, not requiring as many "scaffolding" methods to be implemented, but that's the tradeoffs of having to live in a backwards compatible world. > > You can alternately do it the "classic" MVC way, by making your CarlsView a subclass of View rather than a VisualPart and creating a CarlsController, figure out what your model is, etc. There's an example of how to make View/Controller pair in the chapter 5 of the GUIDevGuide. > > I prefer the "new" approach personally, I've done a lot lot lot lot of SketchController approach since 1992. > > You should not need to make a new Spec class, unless you want to be able to use the UIPainter to paint your views. Even then, you can just use the ArbitraryViewSpec to specify instances of your custom views. > > HTH > > -- > Travis Griggs > Objologist > Light travels faster than sound. This is why some people appear bright until you hear them speak... > > > > _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Oh, I didn't notice your comment about the ArbitraryViewSpec class. I'll give that a try.
Thanks, -Carl On Jul 22, 2011, at 5:38 PM, Carl Gundel wrote: > Thanks Travis, > > Do I then also need to implement a CarlsSpec class and add methods to the UILookPolicy class in order to use my View subclass, or is there some shortcut? > > -Carl Gundel > http://www.libertybasic.com > http://www.runbasic.com > > On Jul 22, 2011, at 12:45 PM, Travis Griggs wrote: > >> >> On Jul 21, 2011, at 8:16 PM, Carl Gundel wrote: >> >>> What is the best way to create a widget for drawing graphics? I essentially need to recreate the functionality of the Digitalk Smalltalk/V GraphPane. >>> >>> -It needs to allow arbitrary drawing of graphics >>> -It must support scrollbars >>> -It must allow for the capturing of mouse and keyboard events >>> -It needs to redraw damage automatically >>> >>> It sure would be great if VisualWorks would come with a ready to use widget that does all this. >>> >>> I'm looking for the most straightforward way to do this. Should I create a subclass of View with my drawing functions and a companion Spec class? Does the View somehow get an event which can be used to trigger a redraw? Do I create a Controller to manage the keyboard and mouse events? >>> >>> Is there is a really simple example I can crib some code from? >> >> 1) Make a new subclass of VisualPart (CarlsView). >> 2) Add a #displayOn: method. Look at examples. You get a GC, and draw with it. >> 3) Implement a #preferredBounds method. This should return a zero origin rectangle showing the current size of your view. Many people cheat and just use 'Screen default bounds'. In your case, where you want to be able to put it inside of a scroller, you probably want to be more precise. >> 4) add the methods #getEventHandler (just return self), #handleEvent (steal the one line implementation from ClickableGraphic), and #handlerForMouseEvent: (ClickableGraphic has a good simple example of this too). >> 5) For any (mouse) event you want to capture, add arbitrary method(s) (single arg or no arg) with a tag like <event: #MouseMove> and then do your code in there. Most of the results in a 'Browse senders of #event:' will show examples of different event types and how to do interesting things with the event object that may be passed to your method (if it's not unary). You want the ones with the little keyboard/pointer icon. I would recommend reading the 'Event Reactions' section in the 7.8 release notes. >> 6) If you want to do keyboard events too, you add the same arbitrary tagged method for either the #KeyDown or #KeyUp event types. But you have to add a number of methods to your VisualPart to do the keyboard dance. For the whole list of them, see the release notes for 7.8, under the section 'Focus Navigation API'. Most of these do things like return true, false, or nil. >> >> I wish the above were even simpler, not requiring as many "scaffolding" methods to be implemented, but that's the tradeoffs of having to live in a backwards compatible world. >> >> You can alternately do it the "classic" MVC way, by making your CarlsView a subclass of View rather than a VisualPart and creating a CarlsController, figure out what your model is, etc. There's an example of how to make View/Controller pair in the chapter 5 of the GUIDevGuide. >> >> I prefer the "new" approach personally, I've done a lot lot lot lot of SketchController approach since 1992. >> >> You should not need to make a new Spec class, unless you want to be able to use the UIPainter to paint your views. Even then, you can just use the ArbitraryViewSpec to specify instances of your custom views. >> >> HTH >> >> -- >> Travis Griggs >> Objologist >> Light travels faster than sound. This is why some people appear bright until you hear them speak... >> >> >> >> > > > _______________________________________________ > vwnc mailing list > [hidden email] > http://lists.cs.uiuc.edu/mailman/listinfo/vwnc _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Travis, thanks for all your help.
Okay I've spent some time trying to make this work. I created my own subclass of VisualPart called GraphPanePart. I open a window and try to draw a circle in it like so: | builder graphPaneSpec graphPane | builder := UIBuilder new. builder window: ApplicationWindow new. builder add: (WindowSpec label: 'my window'). graphPane := GraphPanePart new. graphPaneSpec := ArbitraryViewSpec new source: [ :param | graphPane ]; layout: (10@10 extent: 250@150); name: 'graphics'; hasHorizontalScrollBar: true; hasVerticalScrollBar: true. builder add: graphPaneSpec. builder openWithExtent: 300@200. (Circle center: 50@50 radius: 25) displayStrokedOn: graphPane graphicsContext. The window opens and all seems well enough but I get an error when it tries to draw the circle: Here is a script for creating a window with the above. I get a DNU #graphicsContextFor: What's happening is that my GraphPanePart doesn't have a container, and the component for my ArbitraryViewSpec is an instance of ArbitraryView, not my GraphPanePart. What am I missing? Thanks! -Carl Gundel http://www.libertybasic.com http://www.runbasic.com On Jul 22, 2011, at 7:54 PM, Carl Gundel wrote: > Oh, I didn't notice your comment about the ArbitraryViewSpec class. I'll give that a try. > > Thanks, > > -Carl > > On Jul 22, 2011, at 5:38 PM, Carl Gundel wrote: > >> Thanks Travis, >> >> Do I then also need to implement a CarlsSpec class and add methods to the UILookPolicy class in order to use my View subclass, or is there some shortcut? >> >> -Carl Gundel >> http://www.libertybasic.com >> http://www.runbasic.com >> >> On Jul 22, 2011, at 12:45 PM, Travis Griggs wrote: >> >>> >>> On Jul 21, 2011, at 8:16 PM, Carl Gundel wrote: >>> >>>> What is the best way to create a widget for drawing graphics? I essentially need to recreate the functionality of the Digitalk Smalltalk/V GraphPane. >>>> >>>> -It needs to allow arbitrary drawing of graphics >>>> -It must support scrollbars >>>> -It must allow for the capturing of mouse and keyboard events >>>> -It needs to redraw damage automatically >>>> >>>> It sure would be great if VisualWorks would come with a ready to use widget that does all this. >>>> >>>> I'm looking for the most straightforward way to do this. Should I create a subclass of View with my drawing functions and a companion Spec class? Does the View somehow get an event which can be used to trigger a redraw? Do I create a Controller to manage the keyboard and mouse events? >>>> >>>> Is there is a really simple example I can crib some code from? >>> >>> 1) Make a new subclass of VisualPart (CarlsView). >>> 2) Add a #displayOn: method. Look at examples. You get a GC, and draw with it. >>> 3) Implement a #preferredBounds method. This should return a zero origin rectangle showing the current size of your view. Many people cheat and just use 'Screen default bounds'. In your case, where you want to be able to put it inside of a scroller, you probably want to be more precise. >>> 4) add the methods #getEventHandler (just return self), #handleEvent (steal the one line implementation from ClickableGraphic), and #handlerForMouseEvent: (ClickableGraphic has a good simple example of this too). >>> 5) For any (mouse) event you want to capture, add arbitrary method(s) (single arg or no arg) with a tag like <event: #MouseMove> and then do your code in there. Most of the results in a 'Browse senders of #event:' will show examples of different event types and how to do interesting things with the event object that may be passed to your method (if it's not unary). You want the ones with the little keyboard/pointer icon. I would recommend reading the 'Event Reactions' section in the 7.8 release notes. >>> 6) If you want to do keyboard events too, you add the same arbitrary tagged method for either the #KeyDown or #KeyUp event types. But you have to add a number of methods to your VisualPart to do the keyboard dance. For the whole list of them, see the release notes for 7.8, under the section 'Focus Navigation API'. Most of these do things like return true, false, or nil. >>> >>> I wish the above were even simpler, not requiring as many "scaffolding" methods to be implemented, but that's the tradeoffs of having to live in a backwards compatible world. >>> >>> You can alternately do it the "classic" MVC way, by making your CarlsView a subclass of View rather than a VisualPart and creating a CarlsController, figure out what your model is, etc. There's an example of how to make View/Controller pair in the chapter 5 of the GUIDevGuide. >>> >>> I prefer the "new" approach personally, I've done a lot lot lot lot of SketchController approach since 1992. >>> >>> You should not need to make a new Spec class, unless you want to be able to use the UIPainter to paint your views. Even then, you can just use the ArbitraryViewSpec to specify instances of your custom views. >>> >>> HTH >>> >>> -- >>> Travis Griggs >>> Objologist >>> Light travels faster than sound. This is why some people appear bright until you hear them speak... >>> >>> >>> >>> >> >> >> _______________________________________________ >> vwnc mailing list >> [hidden email] >> http://lists.cs.uiuc.edu/mailman/listinfo/vwnc > > > _______________________________________________ > vwnc mailing list > [hidden email] > http://lists.cs.uiuc.edu/mailman/listinfo/vwnc _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Here's some code for the visual part that draws your circle:
-------------------------------------- Smalltalk defineClass: #GraphPanePart superclass: #{Graphics.VisualPart} indexedType: #none private: false instanceVariableNames: '' classInstanceVariableNames: '' imports: '' category: ''! !GraphPanePart methodsFor: 'bounds accessing'! preferredBounds ^0 @ 0 extent: 1000 @ 800! ! !GraphPanePart methodsFor: 'displaying'! displayOn: aGraphicsContext aGraphicsContext paint: ColorValue red. (Circle center: 50@50 radius: 25) displayStrokedOn: aGraphicsContext! ! -------------------------------------- Now, you can define an application model and use the GraphPanePart: -------------------------------------- Smalltalk defineClass: #GraphPaneApplicationModel superclass: #{UI.ApplicationModel} indexedType: #none private: false instanceVariableNames: 'graphPane ' classInstanceVariableNames: '' imports: '' category: ''! !GraphPaneApplicationModel class methodsFor: 'interface specs'! windowSpec "Tools.UIPainter new openOnClass: self andSelector: #windowSpec" <resource: #canvas> ^#(#{UI.FullSpec} #window: #(#{UI.WindowSpec} #label: 'Unlabeled Canvas' #bounds: #(#{Graphics.Rectangle} 860 480 1060 680 ) ) #component: #(#{UI.SpecCollection} #collection: #( #(#{UI.ArbitraryComponentSpec} #layout: #(#{Graphics.LayoutFrame} 5 0 5 0 -5 1 -5 1 ) #name: #graphPane #flags: 11 #component: #graphPane ) ) ) )! ! !GraphPaneApplicationModel methodsFor: 'accessing'! graphPane ^graphPane ifNil: [graphPane := GraphPanePart new]! ! -------------------------------------- With these two classes defined you can evaluate "GraphPaneApplicationModel open". John Brant _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Thanks John. My own windows are all generated dynamically and can have any arbitrary number of buttons, listboxes, graphPanes, etc. so I can't do exactly what you suggest, but your example showed me what I needed to make it work:
spec component: GraphPanePart new I was stuck on trying to make the #source: setter work for me, and it almost does. I want everyone here to know that I do work very hard to figure this stuff out before I bother to post here. I appreciate all the help. Thanks again. -Carl Gundel http://www.libertybasic.com http://www.runbasic.com On Jul 23, 2011, at 5:07 PM, John Brant wrote: > Here's some code for the visual part that draws your circle: > -------------------------------------- > Smalltalk defineClass: #GraphPanePart > superclass: #{Graphics.VisualPart} > indexedType: #none > private: false > instanceVariableNames: '' > classInstanceVariableNames: '' > imports: '' > category: ''! > > !GraphPanePart methodsFor: 'bounds accessing'! > > preferredBounds > ^0 @ 0 extent: 1000 @ 800! ! > > !GraphPanePart methodsFor: 'displaying'! > > displayOn: aGraphicsContext > aGraphicsContext paint: ColorValue red. > (Circle center: 50@50 radius: 25) displayStrokedOn: aGraphicsContext! ! > -------------------------------------- > > Now, you can define an application model and use the GraphPanePart: > -------------------------------------- > Smalltalk defineClass: #GraphPaneApplicationModel > superclass: #{UI.ApplicationModel} > indexedType: #none > private: false > instanceVariableNames: 'graphPane ' > classInstanceVariableNames: '' > imports: '' > category: ''! > > !GraphPaneApplicationModel class methodsFor: 'interface specs'! > > windowSpec > "Tools.UIPainter new openOnClass: self andSelector: #windowSpec" > > <resource: #canvas> > ^#(#{UI.FullSpec} > #window: > #(#{UI.WindowSpec} > #label: 'Unlabeled Canvas' > #bounds: #(#{Graphics.Rectangle} 860 480 1060 680 ) ) > #component: > #(#{UI.SpecCollection} > #collection: #( > #(#{UI.ArbitraryComponentSpec} > #layout: #(#{Graphics.LayoutFrame} 5 0 5 0 -5 1 -5 1 ) > #name: #graphPane > #flags: 11 > #component: #graphPane ) ) ) )! ! > > !GraphPaneApplicationModel methodsFor: 'accessing'! > > graphPane > ^graphPane ifNil: [graphPane := GraphPanePart new]! ! > -------------------------------------- > > With these two classes defined you can evaluate > "GraphPaneApplicationModel open". > > > John Brant > _______________________________________________ > vwnc mailing list > [hidden email] > http://lists.cs.uiuc.edu/mailman/listinfo/vwnc _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by John Brant-2
I've been having a *really* frustrating time with Wrapper, and I'm no neophyte (I'm a Smalltalker since 1988). My application isn't a typical application where the views can all be created using the UI Painter tool, so maybe I'm unusual. However Smalltalk should be really, really easy for generating dynamic user interfaces, and other Smalltalks that I've used were much easier for this sort of thing. The unfinished Widgetry platform is a *lot* easier than Wrapper.
Here's my suggestion. I'm sure it would be much easier to use if Cincom would just carve off a couple of man weeks and write a cookbook/constructionist style tutorial for how to do everything in Wrapper from first principles to advanced techniques. Or maybe it would suffice to just start a blog where the tutorial could be written one short article per week and then published as a PDF once there is enough material. Thanks to the community for the all help I've received! -Carl Gundel http://www.libertybasic.com http://www.runbasic.com _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
It shouldn't be ALL that difficult.
We build business applications (customer, client, order -- a few thousand such) and we also have Gantt Charts and rectangular displays of personnel scheduling that provides right-click menus on the rectangles. I subclassed ScrollingView which has a displayOn: method which finds the domain object to display and says domainObject displayOn: aGc Then the domainObject displays lines, polylines, text etc -- most of those things are pretty simple and follow some pretty consistent patterns. Interaction was a bit more effort but I just looked at other classes -- we can click, type etc. We do NOT draw because we don't have to. The trickiest part was fly-over help on the rectangles in our personnel scheduling system. I guess cincom could build a pattern, but we actually have 3 (photo images, rectangles and line graphs) each was built from the ground up because it was easier. On Jul 23/11 6:03 PM, Carl Gundel wrote: > I've been having a *really* frustrating time with Wrapper, and I'm no neophyte (I'm a Smalltalker since 1988). My application isn't a typical application where the views can all be created using the UI Painter tool, so maybe I'm unusual. However Smalltalk should be really, really easy for generating dynamic user interfaces, and other Smalltalks that I've used were much easier for this sort of thing. The unfinished Widgetry platform is a *lot* easier than Wrapper. > > Here's my suggestion. I'm sure it would be much easier to use if Cincom would just carve off a couple of man weeks and write a cookbook/constructionist style tutorial for how to do everything in Wrapper from first principles to advanced techniques. Or maybe it would suffice to just start a blog where the tutorial could be written one short article per week and then published as a PDF once there is enough material. > > Thanks to the community for the all help I've received! > > -Carl Gundel > http://www.libertybasic.com > http://www.runbasic.com > _______________________________________________ > vwnc mailing list > [hidden email] > http://lists.cs.uiuc.edu/mailman/listinfo/vwnc -- Dennis Smith +1 416.798.7948 Cherniak Software Development Corporation Fax: +1 416.798.0948 509-2001 Sheppard Avenue East [hidden email] Toronto, ON M2J 4Z8 sip:[hidden email] Canada http://www.CherniakSoftware.com Entrance off Yorkland Blvd south of Sheppard Ave east of the DVP _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
On Jul 23, 2011, at 10:20 PM, Dennis Smith wrote: > It shouldn't be ALL that difficult. Maybe not, but it hasn't come easy for me. There's a lot to know. Some of it is easy enough. > <snip> > > I guess cincom could build a pattern, but we actually have 3 (photo > images, rectangles and line graphs) each was built from the ground up > because it was easier. Perhaps part of what has made this hard for me is the start/stop way I've had to approach this because project, but there is no documentation for the way this was done. I dug pretty hard in the image for examples but couldn't find anything clear. I search the net but there wasn't much there. People here were a great help. -Carl Gundel http://www.libertybasic.com http://www.runbasic.com _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by Carl Gundel
Second that completely.
After leaving professional Smalltalking, I played around with VW for some private pet projects, but quickly canned those for Java. Coming from VS (and in part, VA), the GUI system should be euphemistically called weird, and it is not documented at all. Just compare what VW offers as documentation with what Java/SWT offers. The latter doesnt have too much documentation, either, but there are snippets which show at least basic things which is enough for common GUIs. -- Claus Kick "Wenn Sie mich suchen: Ich halte mich in der Nähe des Wahnsinns auf. Genauer gesagt auf der schmalen Linie zwischen Wahnsinn und Panik. Gleich um die Ecke von Todesangst, nicht weit weg von Irrwitz und Idiotie." "If you are looking for me: I am somewhere near to lunacy. More clearly, on the narrow path between lunacy and panic. Right around the corner of fear of death, not far away from idiocy and insanity." -----Ursprüngliche Nachricht----- Von: "Carl Gundel" <[hidden email]> Gesendet: 24.07.2011 00:03:31 An: VWNC <[hidden email]> Betreff: [vwnc] Suggestion for Cincom >I've been having a *really* frustrating time with Wrapper, and I'm no neophyte (I'm a Smalltalker since 1988). My application isn't a typical application where the views can all be created using the UI Painter tool, so maybe I'm unusual. However Smalltalk should be really, really easy for generating dynamic user interfaces, and other Smalltalks that I've used were much easier for this sort of thing. The unfinished Widgetry platform is a *lot* easier than Wrapper. > >Here's my suggestion. I'm sure it would be much easier to use if Cincom would just carve off a couple of man weeks and write a cookbook/constructionist style tutorial for how to do everything in Wrapper from first principles to advanced techniques. Or maybe it would suffice to just start a blog where the tutorial could be written one short article per week and then published as a PDF once there is enough material. > >Thanks to the community for the all help I've received! > >-Carl Gundel >http://www.libertybasic.com >http://www.runbasic.com >_______________________________________________ >vwnc mailing list >[hidden email] >http://lists.cs.uiuc.edu/mailman/listinfo/vwnc _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by Carl Gundel
Sorry it was not my intent to reflect on your difficulties -- just to
point out a) what I did b) yes a pattern could be built I would love to take a stab at a pattern -- but don't have the time right now. I cannot believe there is not someone out there who would like to do that?? It would have saved me days of learning and playing On Jul 23/11 11:06 PM, Carl Gundel wrote: > On Jul 23, 2011, at 10:20 PM, Dennis Smith wrote: > >> It shouldn't be ALL that difficult. > Maybe not, but it hasn't come easy for me. There's a lot to know. Some of it is easy enough. > >> <snip> >> >> I guess cincom could build a pattern, but we actually have 3 (photo >> images, rectangles and line graphs) each was built from the ground up >> because it was easier. > Perhaps part of what has made this hard for me is the start/stop way I've had to approach this because project, but there is no documentation for the way this was done. I dug pretty hard in the image for examples but couldn't find anything clear. I search the net but there wasn't much there. People here were a great help. > > -Carl Gundel > http://www.libertybasic.com > http://www.runbasic.com > _______________________________________________ > vwnc mailing list > [hidden email] > http://lists.cs.uiuc.edu/mailman/listinfo/vwnc -- Dennis Smith +1 416.798.7948 Cherniak Software Development Corporation Fax: +1 416.798.0948 509-2001 Sheppard Avenue East [hidden email] Toronto, ON M2J 4Z8 sip:[hidden email] Canada http://www.CherniakSoftware.com Entrance off Yorkland Blvd south of Sheppard Ave east of the DVP _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by Carl Gundel
Great suggestion Carl. If nothing else ever comes of this, I want to at least explain some things and try to set some terms straight. And throw in some history. I'll probably bug Steve Dahl to read this and throw in his two cents if he cares to, since I have a huge respect for his historical insight to the process over the years. Hopefully it helps shed some light. I expect it may get longish.
- Let's try to get a definition on what "Wrapper" is The VisualWorks GUI framework is often labeled "Wrapper" in whole. I do not think this is correct, and I think it further confuses the pitfalls. Before VisualWorks existed, there was ObjectWorks. ObjectWorks had a GUI/Widget framework that was based on the simple idea of a view tree (views with subviews, panes with sub panes, windows with sub windows, it's an old idea across many environments that we put different names on). It had two particular specializations beyond the everyday view tree implementation found in many languages and tool kits. It took an interesting approach to nesting in the view tree. Rather than doing as X or other environments had done and say "every thing is a window, and windows have child windows", it had refined class types for different tree element types. Tree elements that had multiple arbitrary children, were reified with CompositePart. Those that were terminal or leaf nodes, usually fell under the View type. And there was a special type for elements that held one distinguished child, for which the element provided a service for. These fell under the type of Wrapper. At the time, there was actually really only two particular types of Wrapper use cases. The first was that "layout" information was provided by a Wrapper object. So a view tree that had a parent and some arbitrary children, would include a Wrapper around each child to provide its layout facilities for the parent. The other was that it was used to put borders around widgets (BorderedWrappers were actually usually LayoutWrapp! ers as well). This was specialization one. The other was the use of the MVC pattern as prototyped by Trygve Reenskaug. It is interesting to note that what MVC means bounces all over the place as you move from language to language, even sometimes from Smalltalk to Smalltalk. The ObjectWorks one, for better or worse, really is about as close as you get to what Trygve originally did at Xerox PARC in 1979. This was specialization two. The above is what I think of as Wrapper. In ObjectWorks, we built user interfaces programmatically, with methods. You learned how the above worked, and made it do what you needed. It actually worked pretty well, for what it was. I recently did some support work for software I wrote in 1992 using this stuff. Large complex UIs doing engineering design work. It's actually still being used in production. -- Problems with Wrapper In retrospect, there were two general errors (IMO) that took place with what I've described as Wrapper. Error One was that so much excitement ensued over the MVC pattern and the change/update pattern that drove it, that *everything* was slowly beat into it. MVC demoes well. It solved/s the fun problem of shared state between widgets. You make a slider and an input field, and point them at the same model and "ta da! it's like magic! it just all works." But somewhere, the knowledge/wisdom/experience about how and where to apply the pattern died. It just became a way of life. Everything had to be expressed as an MVC triad. It meant lots of whiteboard diagrams, and asking yourself "now is that model, or is that view, or is that controller responsibility?" When you got the buckets right things worked out pretty well. But often, it's overkill too. And is more complicated to use than good ol' callback patterns. As widgets get composite and complex, the pattern doesn't scale that well. And many did not know how to say "ok, it's time to put that aside and use good ol' messages." The fr! ameworks obsession with the pattern certainly didn't help with this problem. The other was the use of Wrappers for layout. I'm not opposed to Wrappers in general. They're a general pattern that transcend widget trees. We create an object that "wraps" another object with additional state and behavior. But you don't generally want to split essential state of an object into delegatable parts with a linear wrapper pattern. Layout *IS* an essential state of where a widget lives in a view tree. It wasn't bad to split it into a separate object. It was bad to make it a Wrapper and abuse the view tree to retain a reference to it. An instance variable on VisualPart (the common superclass of all view tree elements) would have worked better and caused less confusion. The idea of placing one widget around another to provide additional decoration, say bordering, or scrolling, is not so bad. It was the use of it for layout that I think was the big error. It made the view tree instantly 2x the number of elements with 50% doing one job, and the 50% doing the other. Much of what I've been trying to mold in place is a departure from these ideas. I'm not trying to get rid of either of them, because a) backwards compatibility is important to customers b) they're not universally bad. The Panel work is an attempt to figure out how to do layout in the view tree, without using LayoutWrappers, and also have some more flexibility than we have today. And some of the new Announcement based widgets can use models, but aren't required to. -- What do we call the other stuff then? In the mid-late 90's, one of the biggest perceived threats to ParcPlace Smalltalk's existence, was the rapid hype around "4GLs". Delphi was one of the big ones I remember. VisualBasic of course. To compete in this arena, ParcPlace built a UI layer on top of the original Wrapper one. This is dramatically different. Where the above was a framework for programmers to program UIs, the new stuff was about visually laying stuff out, not really having to know much about what you were doing, and it all just working. ParcPlace wasn't alone in this, Digitalk tried it's own solution to the hype with "Parts". There are a couple of basic components that make what I would call "Builder." Builder was composed of a 3 basic things: ApplicationModels, UIBuilders, and Specs. The idea was that you could kind of throw some glue code in a bucket called your Application, and then other tools would be used to create various Spec objects. A UIBuilder would assemble the specs into a live incarnation of Wrapper derived objects wired to your Application. The hope was that as a programmer, the only realm you worked in was that of the ApplicationModel. The UIBuilder and Specs were meant to be a black box. Metaphorically, I find it instructional to think of the UIBuilder as a "compiler" and the Specs as "input files." Trevor Hopkins book was probably the most in depth exploration of how to approach the Builder framework. The "Builder" framework was a huge win for ParcPlace Smalltalk. The product was renamed as VisualWorks. And it allowed them to gain some rather large contracts (read, cash flow) because they could now compete in the 4GL space. -- Issues with "Builder" Over the years, I've drawn a couple of observations with Builder. Five main ones. One. The black box thing didn't work out so well. For a variety of reasons, it turned out that people basically had to get to know how Builders and Specs worked. The Builder wasn't written as a good example of reusable Smalltalk Objects. It wasn't supposed to have to. It was a black box compiler. When that didn't pan out, people began doing really interesting things with it. Lots of encapsulation violation. It's like what happens when people start doing interesting things in C programs to exploit some secret knowledge of how a particular compiler works. Except worse, because you could modify/extend/subclass the compiler in this case. Two. Applications hold Builders. The whole point of MVC was separation of model state and presentation. ApplicationModels didn't really follow that idea. And to accomplish it, they used what was left of the Builder after it had filled it's compiler role. This would be like writing a C program that referenced intermediate object files produced by the C compiler to figure out where data was and how to interact with it. It creates retention problems. It means the Builder has a schizophrenic life cycle (I'm a compiler! No, I'm really tripped out Dictionary!). Three. More Wrappers. The idea of using a wrapper pattern isn't bad. But when you build your design around the idea that for any of one set of objects to be real, they need another type of object to wrap them, in every single instance, it's not really a wrapper anymore. It's really just one glump of state that you've broken into two behaviors. We ended up with WidgetStateWrappers. Ideas which really should have just become APIs that all view tree elements responded to (enablement, visibility, etc), were implemented using another layer of Wrappers. These just made the view tree is unapproachable problem worse. Four. Wrapper was not kept up to date, but instead behavior was put in the Builder. For example, when the keyboard tab navigation stuff was added, it was not added to the original Wrapper framework. Instead, the implementors relied on Builder objects to get things set up correctly. Repeated choices like this, meant that it became more and more difficult to programmatically use core Wrapper objects, without at least reverse engineering how Builder was doing it. And Builder was a compiler, not meant as a human understandable set of Objects. Look at any of the UILookPolicy>>blahWidget:into: methods. They're all many lines long. Adding widgets to a view tree should never have been allowed to get this complex. Even if you reverse engineered what Builder was doing, you were left with a lot of work (reminds me of X11/Motif) to do to get standard things done. Five. Knowledge of how to use Wrapper programmatically faded. Over time, the amount of us that cut our teeth on ObjectWorks Wrapper naturally attritted. As docs were updated, various "how to" recipes were replaced with Builder equivalents. What this meant, was that you had a reduced amount of experience about when to put the Builder framework aside, and just use Wrapper directly. Wrapper is far easier (IMO) to manipulate programmatically than Builder. This leads to questions like Carls, where it's not clear that to do what he wants, he probably wants to avoid using Builders at all. Or how to take advantage of Builder when it makes sense and mix the two. The "skinned" widgets that we've done so far for the next VW release (whatever st11a ends up being called), attempt to fix some of these issues. They can be generated with Builder, because there's a huge investment in Specs that people have built up. But they don't use WidgetStateWrappers. They can be hooked to models (because that's what the Builder does), but don't have to be. And we write class side example methods for them that prove to ourselves that we can generate them relatively simply without needing builders and specs. They don't have controllers. We're also trying to make automatic some things, such as the KeyboardProcessor stuff that originally was bootstrapped from Builder. While the API is wider than I'd like on a widget basis, we were able to remove rafts of code in builder when this went in. Every blahWidget:into: was able to be trimmed down some. And you can programmatically assemble widgets without needing Builder and and the keyboard navigation will just work. -- Conclusion My intent here was to paint a picture of what's happened and why we're where we're at. And hopefully to put some of the terms in a big picture of how the stuff fits together from a 10000 ft level. And own up to what we see as issues and want to fix. And indicate where we're trying to chip away at the issues. Carl, if you keep the questions coming, I'll be glad to try and make Blogs out of them. The small direct recipe questions (like your recent one) are the easiest to do such with. I don't mean to point any fingers at anyone with any of this. It is what it is. All programmers make mistakes, which are only obvious in hindsight. -- Travis Griggs Objologist I multiply all time estimates by pi, to account for running around in circles. _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
This is perhaps the clearest, most accurate description of the UI problems (and solutions) in VW that I've read in, well, at least a decade. It's also nice to see these *real* problems being addressed -- "chipping away" is exactly how this needs to happen.
BTW, the biggest mistake with Wrapper that I've found isn't even the widget state stuff (although that's quite gruesome, too). It's that VisualParts generally didn't even know their positions within their container. I think that assuming their origins are always at 0@0 (except when they're not) produced one of the rankest code reeks I've ever smelled. The goal was noble: remove the need for VisualParts to have to deal with translation. Unfortunately, they're things that are part of a presentation hierarchy. Of course (in hindsight) they have to understand ideas about their placement. So... I'm hoping TranslatingWrapper disappears. And bounds/preferredBounds/etc. that always have 0@0 as their origin... a giant clue that preferredExtent is the word you're looking for. I'm also happy that the pluggable notion is coming back after being smothered (unnecessarily) by builders for so long. How can you do dependency injection without it? One final hint: In AI/robotics/etc. a common fundamental pattern is to separate planning and execution. Maybe the layout mechanism can use that notion so that instead of top-down or bottom-up propagation of layout one first figures out a plan for placing everything in the hierarchy (proposedBounds:?), then positions everything, then redraws any affected parts, double-buffered. It's kind of hard to get it wrong that way, and huge categories of bugs, twitching, and circular dependency disappear by design. -----Original Message----- From: [hidden email] [mailto:[hidden email]] On Behalf Of Travis Griggs Sent: Tuesday, July 26, 2011 6:26 PM To: VWNC NC Cc: vw dev list Subject: Re: [vwnc] Suggestion for Cincom Great suggestion Carl. If nothing else ever comes of this, I want to at least explain some things and try to set some terms straight. And throw in some history. I'll probably bug Steve Dahl to read this and throw in his two cents if he cares to, since I have a huge respect for his historical insight to the process over the years. Hopefully it helps shed some light. I expect it may get longish. - Let's try to get a definition on what "Wrapper" is The VisualWorks GUI framework is often labeled "Wrapper" in whole. I do not think this is correct, and I think it further confuses the pitfalls. Before VisualWorks existed, there was ObjectWorks. ObjectWorks had a GUI/Widget framework that was based on the simple idea of a view tree (views with subviews, panes with sub panes, windows with sub windows, it's an old idea across many environments that we put different names on). It had two particular specializations beyond the everyday view tree implementation found in many languages and tool kits. It took an interesting approach to nesting in the view tree. Rather than doing as X or other environments had done and say "every thing is a window, and windows have child windows", it had refined class types for different tree element types. Tree elements that had multiple arbitrary children, were reified with CompositePart. Those that were terminal or leaf nodes, usually fell under the View type. And there was a special type for elements that held one distinguished child, for which the element provided a service for. These fell under the type of Wrapper. At the time, there was actually really only two particular types of Wrapper use cases. The first was that "layout" information was provided by a Wrapper object. So a view tree that had a parent and some arbitrary children, would include a Wrapper around each child to provide its layout facilities for the parent. The other was that it was used to put borders around widgets (BorderedWrappers were actually usually LayoutWrapp! ers as well). This was specialization one. The other was the use of the MVC pattern as prototyped by Trygve Reenskaug. It is interesting to note that what MVC means bounces all over the place as you move from language to language, even sometimes from Smalltalk to Smalltalk. The ObjectWorks one, for better or worse, really is about as close as you get to what Trygve originally did at Xerox PARC in 1979. This was specialization two. The above is what I think of as Wrapper. In ObjectWorks, we built user interfaces programmatically, with methods. You learned how the above worked, and made it do what you needed. It actually worked pretty well, for what it was. I recently did some support work for software I wrote in 1992 using this stuff. Large complex UIs doing engineering design work. It's actually still being used in production. -- Problems with Wrapper In retrospect, there were two general errors (IMO) that took place with what I've described as Wrapper. Error One was that so much excitement ensued over the MVC pattern and the change/update pattern that drove it, that *everything* was slowly beat into it. MVC demoes well. It solved/s the fun problem of shared state between widgets. You make a slider and an input field, and point them at the same model and "ta da! it's like magic! it just all works." But somewhere, the knowledge/wisdom/experience about how and where to apply the pattern died. It just became a way of life. Everything had to be expressed as an MVC triad. It meant lots of whiteboard diagrams, and asking yourself "now is that model, or is that view, or is that controller responsibility?" When you got the buckets right things worked out pretty well. But often, it's overkill too. And is more complicated to use than good ol' callback patterns. As widgets get composite and complex, the pattern doesn't scale that well. And many did not know how to say "ok, it's time to put that aside and use good ol' messages." The fr! ameworks obsession with the pattern certainly didn't help with this problem. The other was the use of Wrappers for layout. I'm not opposed to Wrappers in general. They're a general pattern that transcend widget trees. We create an object that "wraps" another object with additional state and behavior. But you don't generally want to split essential state of an object into delegatable parts with a linear wrapper pattern. Layout *IS* an essential state of where a widget lives in a view tree. It wasn't bad to split it into a separate object. It was bad to make it a Wrapper and abuse the view tree to retain a reference to it. An instance variable on VisualPart (the common superclass of all view tree elements) would have worked better and caused less confusion. The idea of placing one widget around another to provide additional decoration, say bordering, or scrolling, is not so bad. It was the use of it for layout that I think was the big error. It made the view tree instantly 2x the number of elements with 50% doing one job, and the 50% doing the other. Much of what I've been trying to mold in place is a departure from these ideas. I'm not trying to get rid of either of them, because a) backwards compatibility is important to customers b) they're not universally bad. The Panel work is an attempt to figure out how to do layout in the view tree, without using LayoutWrappers, and also have some more flexibility than we have today. And some of the new Announcement based widgets can use models, but aren't required to. -- What do we call the other stuff then? In the mid-late 90's, one of the biggest perceived threats to ParcPlace Smalltalk's existence, was the rapid hype around "4GLs". Delphi was one of the big ones I remember. VisualBasic of course. To compete in this arena, ParcPlace built a UI layer on top of the original Wrapper one. This is dramatically different. Where the above was a framework for programmers to program UIs, the new stuff was about visually laying stuff out, not really having to know much about what you were doing, and it all just working. ParcPlace wasn't alone in this, Digitalk tried it's own solution to the hype with "Parts". There are a couple of basic components that make what I would call "Builder." Builder was composed of a 3 basic things: ApplicationModels, UIBuilders, and Specs. The idea was that you could kind of throw some glue code in a bucket called your Application, and then other tools would be used to create various Spec objects. A UIBuilder would assemble the specs into a live incarnation of Wrapper derived objects wired to your Application. The hope was that as a programmer, the only realm you worked in was that of the ApplicationModel. The UIBuilder and Specs were meant to be a black box. Metaphorically, I find it instructional to think of the UIBuilder as a "compiler" and the Specs as "input files." Trevor Hopkins book was probably the most in depth exploration of how to approach the Builder framework. The "Builder" framework was a huge win for ParcPlace Smalltalk. The product was renamed as VisualWorks. And it allowed them to gain some rather large contracts (read, cash flow) because they could now compete in the 4GL space. -- Issues with "Builder" Over the years, I've drawn a couple of observations with Builder. Five main ones. One. The black box thing didn't work out so well. For a variety of reasons, it turned out that people basically had to get to know how Builders and Specs worked. The Builder wasn't written as a good example of reusable Smalltalk Objects. It wasn't supposed to have to. It was a black box compiler. When that didn't pan out, people began doing really interesting things with it. Lots of encapsulation violation. It's like what happens when people start doing interesting things in C programs to exploit some secret knowledge of how a particular compiler works. Except worse, because you could modify/extend/subclass the compiler in this case. Two. Applications hold Builders. The whole point of MVC was separation of model state and presentation. ApplicationModels didn't really follow that idea. And to accomplish it, they used what was left of the Builder after it had filled it's compiler role. This would be like writing a C program that referenced intermediate object files produced by the C compiler to figure out where data was and how to interact with it. It creates retention problems. It means the Builder has a schizophrenic life cycle (I'm a compiler! No, I'm really tripped out Dictionary!). Three. More Wrappers. The idea of using a wrapper pattern isn't bad. But when you build your design around the idea that for any of one set of objects to be real, they need another type of object to wrap them, in every single instance, it's not really a wrapper anymore. It's really just one glump of state that you've broken into two behaviors. We ended up with WidgetStateWrappers. Ideas which really should have just become APIs that all view tree elements responded to (enablement, visibility, etc), were implemented using another layer of Wrappers. These just made the view tree is unapproachable problem worse. Four. Wrapper was not kept up to date, but instead behavior was put in the Builder. For example, when the keyboard tab navigation stuff was added, it was not added to the original Wrapper framework. Instead, the implementors relied on Builder objects to get things set up correctly. Repeated choices like this, meant that it became more and more difficult to programmatically use core Wrapper objects, without at least reverse engineering how Builder was doing it. And Builder was a compiler, not meant as a human understandable set of Objects. Look at any of the UILookPolicy>>blahWidget:into: methods. They're all many lines long. Adding widgets to a view tree should never have been allowed to get this complex. Even if you reverse engineered what Builder was doing, you were left with a lot of work (reminds me of X11/Motif) to do to get standard things done. Five. Knowledge of how to use Wrapper programmatically faded. Over time, the amount of us that cut our teeth on ObjectWorks Wrapper naturally attritted. As docs were updated, various "how to" recipes were replaced with Builder equivalents. What this meant, was that you had a reduced amount of experience about when to put the Builder framework aside, and just use Wrapper directly. Wrapper is far easier (IMO) to manipulate programmatically than Builder. This leads to questions like Carls, where it's not clear that to do what he wants, he probably wants to avoid using Builders at all. Or how to take advantage of Builder when it makes sense and mix the two. The "skinned" widgets that we've done so far for the next VW release (whatever st11a ends up being called), attempt to fix some of these issues. They can be generated with Builder, because there's a huge investment in Specs that people have built up. But they don't use WidgetStateWrappers. They can be hooked to models (because that's what the Builder does), but don't have to be. And we write class side example methods for them that prove to ourselves that we can generate them relatively simply without needing builders and specs. They don't have controllers. We're also trying to make automatic some things, such as the KeyboardProcessor stuff that originally was bootstrapped from Builder. While the API is wider than I'd like on a widget basis, we were able to remove rafts of code in builder when this went in. Every blahWidget:into: was able to be trimmed down some. And you can programmatically assemble widgets without needing Builder and and the keyboard navigation will just work. -- Conclusion My intent here was to paint a picture of what's happened and why we're where we're at. And hopefully to put some of the terms in a big picture of how the stuff fits together from a 10000 ft level. And own up to what we see as issues and want to fix. And indicate where we're trying to chip away at the issues. Carl, if you keep the questions coming, I'll be glad to try and make Blogs out of them. The small direct recipe questions (like your recent one) are the easiest to do such with. I don't mean to point any fingers at anyone with any of this. It is what it is. All programmers make mistakes, which are only obvious in hindsight. -- Travis Griggs Objologist I multiply all time estimates by pi, to account for running around in circles. _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by Carl Gundel
Great analysis, Travis!!
And a promising outlook on the way ahead. (Albeit the progress is painfully slow - 4 years after dropping Widgetry, which started 6 years before that, having similar goals based on similar reasoning....). To be more constructive, I think it is important to formulate explicit goals in order to get a clear vision of what should be achieved from the end-users (programmers) perspective. On my list of the most pressing needs are: - being able to create dynamic UIs: build it programmatically and manipulate them programmatically (mostly add and remove widgets and change their properties (layout, appearance, responsitivity) easily (the last point works mostly ok in the current framework). - having a clear handle on the update mechanism to avoid excessive updates (as can be seen today with the browser and the debugger which repaint several times as response to a user action). This has more to do with MVC and less with how the updates are delivered (change/update or announcements). My principle: one user action should result in exactly one UI update! - no flickering. This is more low-level (how widgets are painted) and has nothing to do with the last point (when widgets are painted). Widgetry did this almost right (except for the grid) and it would be nice if people could look at that for inspiration instead of ignoring everything Sames did... - probably other important goals others will add to the list... Cheers (hoping that Cincom will assign appropriate resources to this important and long overdue update of the product), Christian > -----Ursprüngliche Nachricht----- > Von: [hidden email] [mailto:[hidden email]] > Im Auftrag von Travis Griggs > Gesendet: Mittwoch, 27. Juli 2011 03:00 > An: VWNC NC > Cc: vw dev list > Betreff: Re: [vwnc] Suggestion for Cincom > > > Great suggestion Carl. If nothing else ever comes of this, I want to at least > explain some things and try to set some terms straight. And throw in some > history. I'll probably bug Steve Dahl to read this and throw in his two cents if > he cares to, since I have a huge respect for his historical insight to the process > over the years. Hopefully it helps shed some light. I expect it may get longish. > > - Let's try to get a definition on what "Wrapper" is > > The VisualWorks GUI framework is often labeled "Wrapper" in whole. I do > not think this is correct, and I think it further confuses the pitfalls. Before > VisualWorks existed, there was ObjectWorks. ObjectWorks had a > GUI/Widget framework that was based on the simple idea of a view tree > (views with subviews, panes with sub panes, windows with sub windows, it's > an old idea across many environments that we put different names on). It > had two particular specializations beyond the everyday view tree > implementation found in many languages and tool kits. > > It took an interesting approach to nesting in the view tree. Rather than doing > as X or other environments had done and say "every thing is a window, and > windows have child windows", it had refined class types for different tree > element types. Tree elements that had multiple arbitrary children, were > reified with CompositePart. Those that were terminal or leaf nodes, usually > fell under the View type. And there was a special type for elements that held > one distinguished child, for which the element provided a service for. These > fell under the type of Wrapper. At the time, there was actually really only > two particular types of Wrapper use cases. The first was that "layout" > information was provided by a Wrapper object. So a view tree that had a > parent and some arbitrary children, would include a Wrapper around each > child to provide its layout facilities for the parent. The other was that it was > used to put borders around widgets (BorderedWrappers were actually > usually LayoutWrapp! > ers as well). This was specialization one. > > The other was the use of the MVC pattern as prototyped by Trygve > Reenskaug. It is interesting to note that what MVC means bounces all over > the place as you move from language to language, even sometimes from > Smalltalk to Smalltalk. The ObjectWorks one, for better or worse, really is > about as close as you get to what Trygve originally did at Xerox PARC in 1979. > This was specialization two. > > The above is what I think of as Wrapper. > > In ObjectWorks, we built user interfaces programmatically, with methods. > You learned how the above worked, and made it do what you needed. It > actually worked pretty well, for what it was. I recently did some support work > for software I wrote in 1992 using this stuff. Large complex UIs doing > engineering design work. It's actually still being used in production. > > -- Problems with Wrapper > > In retrospect, there were two general errors (IMO) that took place with what > I've described as Wrapper. > > Error One was that so much excitement ensued over the MVC pattern and > the change/update pattern that drove it, that *everything* was slowly beat > into it. MVC demoes well. It solved/s the fun problem of shared state > between widgets. You make a slider and an input field, and point them at the > same model and "ta da! it's like magic! it just all works." But somewhere, the > knowledge/wisdom/experience about how and where to apply the pattern > died. It just became a way of life. Everything had to be expressed as an MVC > triad. It meant lots of whiteboard diagrams, and asking yourself "now is that > model, or is that view, or is that controller responsibility?" When you got the > buckets right things worked out pretty well. But often, it's overkill too. And is > more complicated to use than good ol' callback patterns. As widgets get > composite and complex, the pattern doesn't scale that well. And many did > not know how to say "ok, it's time to put that aside and use good ol' > messages." The fr! > ameworks obsession with the pattern certainly didn't help with this > problem. > > The other was the use of Wrappers for layout. I'm not opposed to Wrappers > in general. They're a general pattern that transcend widget trees. We create > an object that "wraps" another object with additional state and behavior. But > you don't generally want to split essential state of an object into delegatable > parts with a linear wrapper pattern. Layout *IS* an essential state of where a > widget lives in a view tree. It wasn't bad to split it into a separate object. It > was bad to make it a Wrapper and abuse the view tree to retain a reference > to it. An instance variable on VisualPart (the common superclass of all view > tree elements) would have worked better and caused less confusion. The > idea of placing one widget around another to provide additional decoration, > say bordering, or scrolling, is not so bad. It was the use of it for layout that I > think was the big error. It made the view tree instantly 2x the number of > elements with 50% doing one job, and the 50% doing the other. > > Much of what I've been trying to mold in place is a departure from these > ideas. I'm not trying to get rid of either of them, because a) backwards > compatibility is important to customers b) they're not universally bad. The > Panel work is an attempt to figure out how to do layout in the view tree, > without using LayoutWrappers, and also have some more flexibility than we > have today. And some of the new Announcement based widgets can use > models, but aren't required to. > > -- What do we call the other stuff then? > > In the mid-late 90's, one of the biggest perceived threats to ParcPlace > Smalltalk's existence, was the rapid hype around "4GLs". Delphi was one of > the big ones I remember. VisualBasic of course. To compete in this arena, > ParcPlace built a UI layer on top of the original Wrapper one. This is > dramatically different. Where the above was a framework for programmers > to program UIs, the new stuff was about visually laying stuff out, not really > having to know much about what you were doing, and it all just working. > ParcPlace wasn't alone in this, Digitalk tried it's own solution to the hype with > "Parts". > > There are a couple of basic components that make what I would call > "Builder." Builder was composed of a 3 basic things: ApplicationModels, > UIBuilders, and Specs. The idea was that you could kind of throw some glue > code in a bucket called your Application, and then other tools would be used > to create various Spec objects. A UIBuilder would assemble the specs into a > live incarnation of Wrapper derived objects wired to your Application. The > hope was that as a programmer, the only realm you worked in was that of > the ApplicationModel. The UIBuilder and Specs were meant to be a black > box. > > Metaphorically, I find it instructional to think of the UIBuilder as a "compiler" > and the Specs as "input files." > > Trevor Hopkins book was probably the most in depth exploration of how to > approach the Builder framework. > > The "Builder" framework was a huge win for ParcPlace Smalltalk. The product > was renamed as VisualWorks. And it allowed them to gain some rather large > contracts (read, cash flow) because they could now compete in the 4GL > space. > > -- Issues with "Builder" > > Over the years, I've drawn a couple of observations with Builder. Five main > ones. > > One. The black box thing didn't work out so well. For a variety of reasons, it > turned out that people basically had to get to know how Builders and Specs > worked. The Builder wasn't written as a good example of reusable Smalltalk > Objects. It wasn't supposed to have to. It was a black box compiler. When > that didn't pan out, people began doing really interesting things with it. Lots > of encapsulation violation. It's like what happens when people start doing > interesting things in C programs to exploit some secret knowledge of how a > particular compiler works. Except worse, because you could > modify/extend/subclass the compiler in this case. > > Two. Applications hold Builders. The whole point of MVC was separation of > model state and presentation. ApplicationModels didn't really follow that > idea. And to accomplish it, they used what was left of the Builder after it had > filled it's compiler role. This would be like writing a C program that referenced > intermediate object files produced by the C compiler to figure out where > data was and how to interact with it. It creates retention problems. It means > the Builder has a schizophrenic life cycle (I'm a compiler! No, I'm really > tripped out Dictionary!). > > Three. More Wrappers. The idea of using a wrapper pattern isn't bad. But > when you build your design around the idea that for any of one set of > objects to be real, they need another type of object to wrap them, in every > single instance, it's not really a wrapper anymore. It's really just one glump of > state that you've broken into two behaviors. We ended up with > WidgetStateWrappers. Ideas which really should have just become APIs that > all view tree elements responded to (enablement, visibility, etc), were > implemented using another layer of Wrappers. These just made the view > tree is unapproachable problem worse. > > Four. Wrapper was not kept up to date, but instead behavior was put in the > Builder. For example, when the keyboard tab navigation stuff was added, it > was not added to the original Wrapper framework. Instead, the > implementors relied on Builder objects to get things set up correctly. > Repeated choices like this, meant that it became more and more difficult to > programmatically use core Wrapper objects, without at least reverse > engineering how Builder was doing it. And Builder was a compiler, not meant > as a human understandable set of Objects. Look at any of the > UILookPolicy>>blahWidget:into: methods. They're all many lines long. Adding > widgets to a view tree should never have been allowed to get this complex. > Even if you reverse engineered what Builder was doing, you were left with a > lot of work (reminds me of X11/Motif) to do to get standard things done. > > Five. Knowledge of how to use Wrapper programmatically faded. Over time, > the amount of us that cut our teeth on ObjectWorks Wrapper naturally > attritted. As docs were updated, various "how to" recipes were replaced > with Builder equivalents. What this meant, was that you had a reduced > amount of experience about when to put the Builder framework aside, and > just use Wrapper directly. Wrapper is far easier (IMO) to manipulate > programmatically than Builder. This leads to questions like Carls, where it's > not clear that to do what he wants, he probably wants to avoid using Builders > at all. Or how to take advantage of Builder when it makes sense and mix the > two. > > The "skinned" widgets that we've done so far for the next VW release > (whatever st11a ends up being called), attempt to fix some of these issues. > They can be generated with Builder, because there's a huge investment in > Specs that people have built up. But they don't use WidgetStateWrappers. > They can be hooked to models (because that's what the Builder does), but > don't have to be. And we write class side example methods for them that > prove to ourselves that we can generate them relatively simply without > needing builders and specs. They don't have controllers. > > We're also trying to make automatic some things, such as the > KeyboardProcessor stuff that originally was bootstrapped from Builder. > While the API is wider than I'd like on a widget basis, we were able to remove > rafts of code in builder when this went in. Every blahWidget:into: was able to > be trimmed down some. And you can programmatically assemble widgets > without needing Builder and and the keyboard navigation will just work. > > -- Conclusion > My intent here was to paint a picture of what's happened and why we're > where we're at. And hopefully to put some of the terms in a big picture of > how the stuff fits together from a 10000 ft level. And own up to what we see > as issues and want to fix. And indicate where we're trying to chip away at the > issues. > > Carl, if you keep the questions coming, I'll be glad to try and make Blogs out > of them. The small direct recipe questions (like your recent one) are the > easiest to do such with. > > I don't mean to point any fingers at anyone with any of this. It is what it is. All > programmers make mistakes, which are only obvious in hindsight. > > -- > Travis Griggs > Objologist > I multiply all time estimates by pi, to account for running around in circles. > > > > > _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by Travis Griggs-4
Hey Travis,
thanks a lot for your elaborate description of the history and future of Wrapper. I much enjoyed the read. IMO, the incremental, evolutionary development path you are taking is right. Although I often feel I would so much love to ditch backwards compatibility with the 80's and 90's once and forever and come up with a new clean, lean and modern Smalltalk altogether. Something solid and snappy that is appealing to new customers, rather than just pleasing existing ones. But as the fate of Widgetry witnesses, this does not seem to be an option. > When that didn't pan out, people began doing really interesting > things with it. Lots of encapsulation violation. Yep, me for instance. Desperately seeking for a way to extend the GUI framework and add MacOS X faithful look and feel, I had to. I even had to extend UIBuilder itself. Mine is full of overrides and extension now. I will probably have a hard time once I start porting to the latest VW release. > Ideas which really should have just become APIs that all view tree > elements responded to (enablement, visibility, etc), were > implemented using another layer of Wrappers. Sounds familiar to me. Adding new classes instead of re-thinking and refactoring APIs seems to be very common among Smalltalkers. The extreme ease of creating new behavior in Smalltalk is it's biggest threat at the same time. IMHO, Smalltalk systems tend to grow too fast ("type while you think"), building up a complexity that might still look clean and beautiful, but that gets out of proportion quickly. Just recently I had to move portions of my product to C++ and design a new system layer down there. While dealing with the lack of true object orientation was a major pain, it forced me to plan more carefully, think twice before creating a new class, and take care of the life cycle of each object from the very fist bits being constructed to the last lights-out destruction (thanks to RAII techniques, this was not as bad as I expected). Now this lead to the weird situation where I feel that my C++ code is more robust, stable and clean than its Smalltalk counterparts. Knowing for sure that something is bulletproof however, comes at a cost: It takes more careful planning and a strict discipline, two things I became too lazy for during the many years of Smalltalk, because it always "just works" anyway. I wish there were more immediately noticeable incentives for sticking to discipline in Smalltalk. Some development mode that throws everything at you that isn't right, that forces you to think twice. Andre -- On 27.07.2011, at 01:25, Travis Griggs wrote: > Great suggestion Carl. If nothing else ever comes of this, I want to > at least explain some things and try to set some terms straight. And > throw in some history. I'll probably bug Steve Dahl to read this and > throw in his two cents if he cares to, since I have a huge respect > for his historical insight to the process over the years. Hopefully > it helps shed some light. I expect it may get longish. [...] _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by Travis Griggs-4
Wrappers are an example of the "Decorator" design pattern, and was how
I learned the pattern. In fact, in the first version of "Design Patterns", the pattern was called "Wrapper", but we found that the word "Wrapper" was used in different ways by different people, so we decided that the pattern needed a new name. I think Erich Gamma was the one who proposed that pattern. (He proposed most of them.) I don't know whether he learned it from Smalltalk, but I wouldn't be surprised. Decorator is great for adding optional features to an object. Positioning is not optional for visual objects. One of the things that annoyed me about Wrapper was how every visual object would end up surrounded by a cloud of wrappers. When I inspected them, I always had to pass through the cloud to see what was going on. I thought that an inspector that was better designed for wrappers could have helped. It has been a few years since I have used VisualWorks, so maybe that has happened already. I programmed in Smalltalk 80 Release 2.4, then in ObjectWorks for Smalltalk 1 and 2 and VisualWorks 1, 2, 3, and 5. I have only used 7 a little, mostly using Squeak for the past 5 years. ObjectWorks was where the original Smalltalk-80 MVC was replaced with MVC plus Wrappers. In the original Smalltalk 80, the View class was huge. I had thought about how to refactor it into several smaller classes, and had realized that the Composite pattern would help a lot. One of my students had built a prototype (I think for Tektronix Smalltalk). I was very impressed with how ObjectWorks did it. Pushing the ability to have children into a subclass made the superclass simpler and made the overall design safer. At first, I was also very impressed with Wrappers, since they also allowed individual classes to be smaller, but making classes small is not the only thing that is important. Design is about trade-offs. > It took an interesting approach to nesting in the view tree. Rather than doing as X or other environments had done and say "every thing is a window, and windows have child windows", it had refined class types for different tree element types. Tree elements that had multiple arbitrary children, were reified with CompositePart. Those that were terminal or leaf nodes, usually fell under the View type. Leaf nodes were not all Views. In general, there were VisualParts and VisualComponents, one of which knew their parent and one of which did not. The Visuals that knew their parents could change their state (and notify their parents so they could be redrawn) while the Visuals whose state never changed did not need to know their parents. I have always assumed that this was an optimization. Even though most visual classes need to know their parents, there are a lot of instances that that never change their appearance, and I think the original designers were concerned about saving memory. A lot of people were trying to run ObjectWorks on 4 meg or 8 meg computers. In retrospect, it was probably not a good idea. -Ralph Johnson _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Free forum by Nabble | Edit this page |