The Artima Developer Community
Sponsored Link

Agile Buzz Forum
How To Create A Custom Widget - Select And Show Date

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
How To Create A Custom Widget - Select And Show Date Posted: Nov 19, 2004 12:02 AM
Reply to this message Reply

This post originated from an RSS feed registered with Agile Buzz by James Robertson.
Original Post: How To Create A Custom Widget - Select And Show Date
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 add behavior so that when one selects a date in the grid, it closes the drop down, assigns the date to the calendar's model, and displays it in the input field portion of our Calendar.


Simple Changes

We don't need to do too much to accomplish today's goals. First, we need to subscribe to the #cellSelected: event of the grid:

	CalendarAgent>>addCalendarGridTo: aForm 
		| grid |
		grid := Grid new.
		grid foregroundColorAction: [:cell | self foregroundColorFor: cell].
		grid frame: (FractionalFrame fractionLeft: 0 right: 1 top: 0 bottom: 1).
		grid frame
			leftOffset: 5;
			rightOffset: -5;
			bottomOffset: -5;
			topOffset: 25.
		grid list: self currentMonthModel.
		self addColumnsTo: grid.
		grid selectByCells.
		grid when: #cellSelected: send: #selectDateAt: to: self.
		grid 
			columnHeader: true;
			allowColumnResizing: false;
			allowColumnReordering: false;
			allowRowResizing: false;
			allowSorting: false;
			displayExtendedRowLines: true.
		aForm addComponent: grid

This event, when triggered sends the cell location as a point, to our method of choice, here named #selectDateAt:. Here's that method:

	CalendarAgent>>selectDateAt: aPoint
		| newDate |
		newDate := (dropDown paneAt: #(#Form1 #Grid1)) list at: aPoint.
		pane model value: newDate.

The ObservedTwoDList knows how to handle either points or integers sent to it's #at: method. If we send an integer, it gives us the array of values for the row associated with that integer. If we send it a point, it gives us just the value of that element.

Next we want to close the drop down when the selection is complete. This we want to happen when the mouse is released on the selection. The #cellSelected: action takes place before the mouse is released, in other words, on mouse down. Fortunately, there is an event that occurs on mouse up for any selection type; #selectionChangeFinished. So we'll hook to that event as follows:

	CalendarAgent>>addCalendarGridTo: aForm 
		| grid |
		grid := Grid new.
		grid foregroundColorAction: [:cell | self foregroundColorFor: cell].
		grid frame: (FractionalFrame fractionLeft: 0 right: 1 top: 0 bottom: 1).
		grid frame
			leftOffset: 5;
			rightOffset: -5;
			bottomOffset: -5;
			topOffset: 25.
		grid list: self currentMonthModel.
		self addColumnsTo: grid.
		grid selectByCells.
		grid when: #cellSelected: send: #selectDateAt: to: self.
		grid when: #selectionChangeFinished send: #closeDropDown to: self.
		grid 
			columnHeader: true;
			allowColumnResizing: false;
			allowColumnReordering: false;
			allowRowResizing: false;
			allowSorting: false;
			displayExtendedRowLines: true.
		aForm addComponent: grid

Here is the #closeDropDown method:

	CalendarAgent>>closeDropDown
		pane topPane sensor addMetaInput: (CloseEvent new window: dropDown)

Now, this might seem fairly obtuse. Here's the deal. Our goal is to make the drop down window close after all processing is done to the grid and anything else on the drop down. If we simply send #close to the drop down (you can try it), you'll be interrupting a flow of code that does things like highlight the selected item and other things. So, sending #close isn't good. Thus, by adding a system close event targeted to the drop down, to the event queue of the main window (not the dropDown), we know that it won't get processed until all other events are done.

In the future, Pollock will likely support a more direct API for queuing these kind of things. For now, it does the trick, and will work even in the face of future API additions.

So, if we open our Calendar tester (CalendarTest new openWindowWithCalendar), open the drop down, select a date (with or without navigating) everything looks nice. If we don't pick "Today" as our selection, in the grid, the next time we open the drop down, it is now focused on the month and date we selected the last time we opened the drop down.


Displaying The Selected Date

Now all we have to do is make it so whenever we select a new target date, that date shows up in the input field portion of our Calendar. We'll start by adding a method to Calendar to subscribe to the #changed event on our model:

	Calendar>>setModelEvent
		model when: #changed send: #updateDateDisplay to: self

Then we add this to our #getDefaultModel method:

	Calendar>>setDefaultModel
		model := Date today asObservedValue.
		self setModelEvent

Finally, we create an #updateDateDisplay method:

	Calendar>>updateDateDisplay
		self displayPart model value: self model value shortPrintString

With all that, now when we select the date in the grid, we get the new date displayed in the input field part of our Calendar. The shortPrintString is already an internationalized value, so we're all set to go.


Details

One thing we're missing is that when we open our Calendar, it doesn't display the current model value. We just need to call updateDateDisplay during initialization for this to happen:

	Calendar>>initialize
		super initialize.
		self interiorDecoration: self getInteriorDecoration.
		self createDisplayPart.
		self updateDateDisplay

Lastly, to be complete, we need to add our own #model: method. This is a subclass responsibility method, and we haven't made one yet. We do this in case we want to have some special model object instead of an ObservedValue on a Date. Here that method:

	Calendar>>model: aValue
		model ifNotNil: [model removeAllActionsWithReceiver: self].
		model := aValue.
		self setModelEvent

Note that we make sure that we remove only the events on the old model if they are targeted to the Calendar itself. This makes sure we don't release events on that model object that might, for instance, be domain objects of some kind, with other receivers. We don't want to mess with those, only our events.

The above is published as version 1.15 in the Package named "Pollock-Calendar" on the Cincom public repository.

Next time we'll make it so if a user enters some date in the input field, it updates all the right values in our Calendar.


And So It Goes
Sames

Read: How To Create A Custom Widget - Select And Show Date

Topic: Sun can't be pleased with this Previous Topic   Next Topic Topic: Recording design decisions

Sponsored Links



Google
  Web Artima.com   

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