The Artima Developer Community
Sponsored Link

Agile Buzz Forum
Fun With ResizingSplitters

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
James Robertson

Posts: 29924
Nickname: jarober61
Registered: Jun, 2003

David Buck, Smalltalker at large
Fun With ResizingSplitters Posted: Jun 15, 2007 11:41 AM
Reply to this message Reply

This post originated from an RSS feed registered with Agile Buzz by James Robertson.
Original Post: Fun With ResizingSplitters
Feed Title: Pollock
Feed URL: http://www.cincomsmalltalk.com/rssBlog/pollock-rss.xml
Feed Description: Pollock - the next VW GUI
Latest Agile Buzz Posts
Latest Agile Buzz Posts by James Robertson
Latest Posts From Pollock

Advertisement

Today we show how to work with ResizingSplitters, and along the way, show a TreeView feature and create a mini browser.

Design

We'll put a TreeView in the upper left of our window, and fill it with the Pane hierarchy, then put a ListBox in the upper right of our window, and fill that with method selectors for the selected class in the TreeView. Then we'll put a TextEdit across the bottom, and when you select a method selector, we'll display the method source. We'll put a ResizingSplitter vertically between the TreeView and the List, and a horizontal ResizingSplitter between the top two panes (TreeView and ListBox) and the TextEdit at the bottom.

As always, we start with a subclass of UserInterface:

	Smalltalk defineClass: #ResizingSplitterWork
		superclass: #{Widgetry.UserInterface}
		indexedType: #none
		private: false
		instanceVariableNames: 'treeView listBox textEdit horizontalSplitter verticalSplitter'
		classInstanceVariableNames: ''
		imports: 'private Widgetry.*'
		category: '(none)'

Before we get on to our usual #createInterface, we'll make our main window open a bit bigger to fit all the stuff we're going to put into it:

	hookupWindow

		self mainWindow frame specifiedSize: 300 @ 400.

Now, we'll create our main widgets, and lay them out:

	createInterface

		treeView := TreeView new.
		treeView frame: (FractionalFrame
			fractionLeft: 0
			right: 0.5
			top: 0
			bottom: 0.5).
		(treeView frame)
			bottomOffset: -2;
			rightOffset: -2.
		self addComponent: treeView.
		listBox := ListBox new.
		listBox frame: (FractionalFrame
			fractionLeft: 0.5
			right: 1
			top: 0
			bottom: 0.5).
		(listBox frame)
			leftOffset: 2;
			bottomOffset: -2.
		self addComponent: listBox.
		textEdit := TextEdit new.
		textEdit frame: (FractionalFrame
			fractionLeft: 0
			right: 1
			top: 0.5
			bottom: 1).
		textEdit frame topOffset: 2.
		self addComponent: textEdit

And here is what it looks like when we execute ResizingSplitterWork open:

Not very exciting. However, you do see where the offsets I added to the frames leaves room for our ResizingSplitters.

Hair Jell

Next we create our two ResizingSplitters. By default, ResizingSplitters will display horizontally, so the first thing we'll do in our #hookupInterface is make the vertical ResizingSplitter, well, vertical!

	createInterface

		treeView := TreeView new.
		treeView frame: (FractionalFrame
			fractionLeft: 0
			right: 0.5
			top: 0
			bottom: 0.5).
		(treeView frame)
			bottomOffset: -2;
			rightOffset: -2.
		self addComponent: treeView.
		listBox := ListBox new.
		listBox frame: (FractionalFrame
			fractionLeft: 0.5
			right: 1
			top: 0
			bottom: 0.5).
		(listBox frame)
			leftOffset: 2;
			bottomOffset: -2.
		self addComponent: listBox.
		textEdit := TextEdit new.
		textEdit frame: (FractionalFrame
			fractionLeft: 0
			right: 1
			top: 0.5
			bottom: 1).
		textEdit frame topOffset: 2.
		self addComponent: textEdit.
		horizontalSplitter := ResizingSplitter new.
		horizontalSplitter frame: (FractionalFrame
			fractionLeft: 0
			right: 1
			top: 0.5
			bottom: 0.5).
		(horizontalSplitter frame)
			topOffset: -2;
			bottomOffset: 2.
		self addComponent: horizontalSplitter.
		verticalSplitter := ResizingSplitter new.
		verticalSplitter frame: (FractionalFrame
			fractionLeft: 0.5
			right: 0.5
			top: 0
			bottom: 0.5).
		(verticalSplitter frame)
			leftOffset: -2;
			rightOffset: 2;
			bottomOffset: -2.
		self addComponent: verticalSplitter

	hookupInterface

		verticalSplitter beVertical

Now it looks like this:

I know... its barely different. However, you should be able to see the splitters and their default raised look. If one moves the mouse over one of the splitters, the cursor will change appropriately to a horizontal or vertical resizing cursor. Also, you can move the splitters, but the result will be ugly:

This is because only the splitters themselves are moving. Just putting them there doesn't do anything.

3... 2... 1... Contact!

We have to tell our ResizingSplitters which panes to control. To do this, we simply tell each splitter the IDs of each pane it should control with the appropriate configuration method. We haven't given our panes explicit ID names, but fortunately Widgetry automatically assigns IDs to each pane when we add them with the #addComponent: method. All we have to do is send ID to the pane to get the generated ID. Thus with a bit of clever programming we never even have to know:

	hookupInterface

		verticalSplitter beVertical.
		horizontalSplitter aboveWidgets: (Array 
			with: treeView id
			with: verticalSplitter id
			with: listBox id).
		horizontalSplitter belowWidgets: (Array
			with: textEdit id).
		verticalSplitter leftWidgets: (Array
			with: treeView id).
		verticalSplitter rightWidgets: (Array
			with: listBox id).

And this is what it looks like with some resizing done:

If we had given the widgets IDs, our code could have been simpler, such as #(#thisPane #thatPane #otherPane). I leave it up to you to decide if you want to do that or not.

That's all there really is to ResizingSplitters, but that's not much fun... So the rest is all:

Extra Credit

We'll give our TreeView the Pane hierarchy telling it to initially expand the root and have it not show lines, and then fill in the list when a class is chosen, and then fill in the textEdit when a method is chosen. We'll make the textEdit word wrapped, and add vertical scrollbars all around:

	hookupInterface

		| tree |
		verticalSplitter beVertical.
		horizontalSplitter aboveWidgets: (Array 
			with: treeView id
			with: verticalSplitter id
			with: listBox id).
		horizontalSplitter belowWidgets: (Array
			with: textEdit id).
		verticalSplitter leftWidgets: (Array
			with: treeView id).
		verticalSplitter rightWidgets: (Array
			with: listBox id).
		tree := Tree
			on: Pane
			childrenBlock: 
				[:value | value subclasses 
					asSortedCollection: [:each :other | each name < other name]].
		treeView tree: tree.
		tree expandRoot.
		treeView showLines: false.
		treeView when: SelectionChanged send: #fillInMethods to: self.
		listBox when: SelectionChanged send: #showSource to: self.
		textEdit wordWrapped: true.
		textEdit verticalScrollbar: true.
		listBox verticalScrollbar: true.
		treeView verticalScrollbar: true

	fillInMethods

		treeView selection isNil 
			ifTrue: [listBox list: ObservedList new]
			ifFalse: [listBox list: treeView selection selectors asSortedCollection]
			
	showSource

		treeView selection ifNil: [textEdit model value: UIText new].
		listBox selection ifNil:  [textEdit model value: UIText new].
		listBox selection ifNotNil:
			[:value | textEdit model value: (treeView selection sourceMethodAt: value)]

And here is what that looks like with things selected and so on:

Isn't that pretty?

And So It Goes
Sames

Read: Fun With ResizingSplitters

Topic: Smalltalk Daily 6/13/07: Adding Columns to a Dataset Previous Topic   Next Topic Topic: Is FeedBurner Having Scaling Problems?

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use