The Artima Developer Community
Sponsored Link

Agile Buzz Forum
Fun With MenuButtons

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 MenuButtons Posted: May 25, 2007 2:21 PM
Reply to this message Reply

This post originated from an RSS feed registered with Agile Buzz by James Robertson.
Original Post: Fun With MenuButtons
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 take our knowledge of Menus and apply it to the MenuButton

Design

We'll make a MenuButton, fill it with a menu of Look names, and then, when a look is selected, we'll change to that look. We'll cache the current look on startup, and make sure to reset it when we close our window.

As always, we start with a subclass of UserInterface:

	Smalltalk defineClass: #MenuButtonWork
		superclass: #{Widgetry.UserInterface}
		indexedType: #none
		private: false
		instanceVariableNames: 'originalLook menuButton '
		classInstanceVariableNames: ''
		imports: 'private Widgetry.*'
		category: '(none)'

Capture The Flag

To make sure we capture the look that is in place when we open our window, we override the #initialize method:

	initialize

		originalLook := Screen default defaultWidgetPolicy lookPolicyClass.
		super initialize.

Don't forget that call to super initialize!

Next we create a #hookupWindow method. In it we subscribe to the Closing Announcement of the window, and tell it to send a message to us when the window is being closed:

	hookupWindow

		self mainWindow when: Closing send: #resetLookIfNeeded to: self.

Finally we write the #resetLookIfNeeded method to reset the look back to the original if it has changed:

	resetLookIfNeeded

		originalLook == Screen default defaultWidgetPolicy lookPolicyClass
			ifFalse: [originalLook installLookPreferences]

This also shows how one changes the current look programmatically. All one has to do is send UILookPolicy. Wrapper has 7 looks: Default, Mac, MacOSX, Motif, Win95, Win98 and WinXP. Default is a very old look, which some have called the Smalltalk look. The only meaningful difference between the Win95 and Win98 look is how toolbar buttons look and act.

Wrapper supports only 4 looks: MacOSX, Win9x, Motif and WinXP. The Win9x look is in effect a Windows 98 look. Widgetry does not have a "classic" Mac look, and it finally puts to rest the Default look.

Each look is associated with an existing Wrapper look policy: MacOSX with MacOSXLookPolicy, Win9x with Win95LookPolicy, Motif with MotifLookPolicy and WinXP with WinXPLookPolicy. Whereas each of these has both Widgetry and Wrapper code in them, there is no sharing of that code. Thus, changing the look will affect both Wrapper and Widgetry, but it allows the removal of Wrapper methods in the future.

When one changes the look, Widgetry automatically will update all widgets, whereas Wrapper required you to write code to tear down the old widgets and rebuild them. This has been a complaint about our tools for some time. If someone changed the look in the settings, not all of the tools would change to match the new selected look. Over the years, the Tools team has updated the Launcher, Workspace and RefactoringBrowser to do the changes required, but still, other tools do not. With Widgetry, no one has to worry about it. It just happens.

The Work

A MenuButton is used when you have a fixed set of selections, and no requirement to dynamically enter a selection (as is possible with a DropDownList).

Here is our #createInterface method:

	createInterface

		menuButton := MenuButton new.
		menuButton frame: (FractionalFrame
			fractionLeft: 0.1
			right: 0.9
			top: 0.1
			bottom: 0.3).
		self addComponent: menuButton

If we execute MenuButtonWork open, here is what we see:

Fill It Up

Next we want to fill our MenuButton with a Menu. We use a regular Menu, just like we do for our work the last two times. To tell a MenuButton what menu to use when activated, we send the method #dropDownMenu: to the MenuButton, and pass our menu as the parameter.

As always, we put our configuring methods in the #hookupInterface method:

	hookupInterface

		| menu |
		menu := Menu new.
		menu addMenuItem: ((MenuItem label: 'WinXP Look') id: WinXPLookPolicy).
		menu addMenuItem: ((MenuItem label: 'Win9x Look') id: Win95LookPolicy).
		menu addMenuItem: ((MenuItem label: 'Motif Look') id: MotifLookPolicy).
		menu addMenuItem: ((MenuItem label: 'MacOSX Look') id: MacOSXLookPolicy).
		menuButton dropDownMenu: menu

Here is what it looks like, once we re-open our window, and press the button:

And here is what it looks like after we select one of the items in the menu::

There are a couple of things you'll notice here. When the MenuButton has focus, you can hit the down arrow key, and the menu will open. From there, using the arrow keys will highlight successive menu items. Pressing the Escape key or the Space key, closes the menu without choosing a menu item. Pressing Enter chooses a menu item.

The size of the drop down menu is always the full width of the MenuButton, or the minimum width to show the menu, which ever is larger. So if you make the window wider (and we used a FractonalFrame, so the MenuButton will get wider also), then the resulting menu will get bigger, to match the width of the MenuButton.

If you resize the window to it's narrowest, then the menu will make sure it can be fully shown, and actually be wider than the MenuButton:

Dance The Dance

You may have noticed that for the ID for each menu item, I gave it the actual Look policy class. Again, like we did with RadioButtons, we can use anything which can be uniquely identified.

We did this because now we want to watch for MenuItemSelected Announcement in our MenuButton. Once that is announced, the actual MenuItem will be in the Announcement. With that, we can simply send #installLookPreferences to the ID in the MenuItem:

	hookupInterface

		| menu |
		menu := Menu new.
		menu addMenuItem: ((MenuItem label: 'WinXP Look') id: WinXPLookPolicy).
		menu addMenuItem: ((MenuItem label: 'Win9x Look') id: Win95LookPolicy).
		menu addMenuItem: ((MenuItem label: 'Motif Look') id: MotifLookPolicy).
		menu addMenuItem: ((MenuItem label: 'MacOSX Look') id: MacOSXLookPolicy).
		menuButton dropDownMenu: menu.
		menuButton when: MenuItemSelected do: 
			[:announcement | announcement item id installLookPreferences]

Yes, its just that simple!

Notice that the announcement is optionally sent as a parameter to the #when:do: block. All we have to do is send the right message

And here is what it looks like after we choose each item:

Now, even if we change the look, and close the window, the original look will re-install itself

Extra Credit

For fun, and to show that automatic changes really do take place, let's add a few more widgets and watch them change:

	createInterface

		| radioButton checkBox spinButton |
		menuButton := MenuButton new.
		menuButton frame: (FractionalFrame
			fractionLeft: 0.1
			right: 0.9
			top: 0.1
			bottom: 0.3).
		self addComponent: menuButton.
		spinButton := SpinButton new.
		spinButton frame: (FractionalFrame
			fractionLeft: 0.05
			right: 0.95
			top: 0.5
			bottom: 0.65).
		self addComponent: spinButton.
		checkBox := CheckBox withLabelString: 'Check Box'.
		checkBox frame: (FractionalFrame
			fractionLeft: 0.05
			right: 0.35
			top: 0.75
			bottom: 0.9).
		self addComponent: checkBox.
		radioButton := RadioButton withLabelString: 'Radio Button'.
		radioButton frame: (FractionalFrame
			fractionLeft: 0.45
			right: 0.95
			top: 0.75
			bottom: 0.9).
		self addComponent: radioButton.

And here are the results:

Isn't that pretty?

And So It Goes
Sames

Read: Fun With MenuButtons

Topic: Smalltalk Daily 5/22/07: Using File Dialogs Previous Topic   Next Topic Topic: They've been wrong forever

Sponsored Links



Google
  Web Artima.com   

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