macdevcenter.com
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Build Your Own Blogging Application, Part 1
Pages: 1, 2

Building the Front End

Understanding Tcl/Tk and XHTML now empowers us to actually build the front end for our blogging app. We know that at a minimum, our GUI should allow the user to write entries to the blog app and exit. Since we'd like to be able to use XHTML with as little effort as possible, a menu with basic markups is also a nice convenience as well as the ability to insert images into our blog. Interestingly, the steps involved in accomplishing these basic tasks generalizes to virtually any XHTML markup we'd ever want to use. Now that you're armed with the tools to build this front end, let's get our hands dirty.

In your favorite editor, copy the following lines of code.


################################################
#Matthew Russell 30 Sep 04
################################################
#A Tcl/Tk front end for a blogging application
#that will write XHTML to the iDisk.
#This script relies on script updateBlog.sh
################################################

#create & title a frame for the widgets
frame .fr -width 10c -height 5c
wm title . "Blogging App v0.1"
pack .fr

#configure menubar on top
frame .menubar -relief raised -bd 2
pack .menubar -in .fr -fill x

#put a text widget (our editor) with y scroll
text .fr.ed -width 80 -height 20 -bg white \
	-yscrollcommand ".fr.scroll set" \
	-wrap word
scrollbar .fr.scroll -command ".fr.ed yview" 
pack .fr.scroll -side right -fill y
pack .fr.ed -side left -fill both -expand true
pack .fr -side top -fill both -expand true

#create a file menu
menubutton .menubar.file -text File \
	-underline 0 \
	-menu .menubar.file.menu

menu .menubar.file.menu

#items in file menu
.menubar.file.menu add command \
	-label "Write To Blog" \
	-command WriteToBlog 
.menubar.file.menu add command \
	-label "Write To Blog and Quit" \
	-command WriteToBlogQuit 
.menubar.file.menu add command \
	-label "Quit" \
	-command exit

#create a markup menu button
menubutton .menubar.markup -text Markup \
	-underline 0 \
	-menu .menubar.markup.menu

menu .menubar.markup.menu

#items in the markup menu
.menubar.markup.menu add command \
	-label Bold \
	-command {MarkupSelection "strong"}
.menubar.markup.menu add command \
	-label Italic \
	-command {MarkupSelection "em"}

#create a menu for inserting images
menubutton .menubar.insertImage \
	-text "Insert Image" \
	-underline 0 \
	-menu .menubar.insertImage.menu

menu .menubar.insertImage.menu

#item in the image menu
.menubar.insertImage.menu add command \
	-label "Find Image" \
	-command InsertImageFile

pack .menubar.file -side left
pack .menubar.markup -side left
pack .menubar.insertImage -side left
pack .menubar -side top -fill x

#start the focus in the editor 
focus .fr.ed

#a clean way of displaying error messages
proc ShowMessage {mess} {

	toplevel .messpop \
		-width 10c \
		-height 4c

	grab .messpop
	wm title .messpop "Warning"

	message .messpop.msg \
		-relief raised \
		-bd 2 \
		-text $mess

	button .messpop.okb \
		-text OK \
        -command {destroy .messpop ; 
				  return 0}

	pack .messpop.msg .messpop.okb -side top 
}

# place markup tags around the selection
proc MarkupSelection {markupTag} {
	set theSel [selection get STRING]
	set selLen [string length $theSel]

#if true, then the selection done right to left
if {[string equal \
	$theSel \
	[.fr.ed get insert "insert +$selLen chars"]]} {
	.fr.ed delete \
		insert "insert + $selLen chars"
	.fr.ed insert \
		insert "<$markupTag>$theSel</$markupTag>"
} else {
	.fr.ed delete \
		"insert -$selLen chars" insert
	.fr.ed insert \
		insert "<$markupTag>$theSel</$markupTag>"
}

}

#Write the blog entry to file 
#Then execute a script to post the entry
proc WriteToBlog {} {
	set err [catch {set f [open "newentry" w]} \
		errormessage]
	if {$err == 0} {
		puts $f [.fr.ed get 1.0 end]
		close $f
		#the shell script that updates the blog
		exec ./updateBlog.sh
	} else {
		set ok [ShowMessage "No filename given"]
		}
} 


proc InsertImageFile {} {
	set typelist {
   		{"All Files" {*}}
   		{"GIF Image" {".gif"}}
   		{"JPEG Image" {".jpg"}}
	}

	global env
	set fullName \
	[tk_getOpenFile -title "Find Image File" \
					-initialdir $env(HOME) \
			 		-filetypes $typelist]

#use the full filename for the tag in the editor
#abbreviate it once it's copied to the iDisk
.fr.ed insert \
	   insert \
"<img src='$fullName' width= height= />"
}

proc WriteToBlogQuit {} {
	WriteToBlog
	exit
}

In order to fire up the editor, type wish editor.tcl into your terminal window, while in the same directory as the file you just copied. Most of the front end should be fairly straightforward, based on our previous discussion of Tcl/Tk. We set up a frame, title it, and then add in a menubar. Once that's done we add in the actual menus themselves and define their actions. We also insert a text widget that allows us to enter our writing. That's all mechanical enough. The interesting parts of the editor involve what the menu choices actually accomplish.


Your nice-looking editor that was almost too easy to make.

Let's start with the markup menu. Following good software design principles, you and I have produced some procedures to accomplish functionality based upon varying parameters.

In the editor, procedure MarkupSelection handles marking up the selection based upon a parameter that indicates the content of the tag. There's a bit of a nuisance you have to work around when dealing with selection in Tcl/Tk. What you can find out easily is where the insertion cursor is located and the length of the selection. What you have to do some detective work to discover is whether the act of selecting the text was accomplished right to left or left to right. If selection was accomplished left to right, then we'd just delete the characters from the insertion cursor (at the right of the selection) back to the beginning of the selection. If it was accomplished right to left, then we'd delete characters from the insertion cursor (at the left end of the selection) to the end of the selection.

Fortunately, we can compare the selection itself to sequences of characters defined relatively to the insertion cursor to determine which way the selection occurred. (Say that three times as fast as you can.) Based on one of these conditions, the procedure just sends an insert and delete command to the editor along with a range of characters for its arguments.

Next, let's have a look at the image menu. To insert an image, a procedure executes that displays a dialog box to the user. The user navigates through their directory, finds the image to insert, and when the user clicks OK, the tag specifying the location of the image gets inserted.

The actual process of rendering the image is a job for the viewer of the blog's browser once the entry is posted to the web. We'll work through the process of copying the image file to the iDisk and changing the absolute path in the image tag to one relative to the iDisk's directory structure in the next article. For now, trust that we're doing the right thing here. The interesting part of the InsertImageFile procedure involves the special variable env. global is a special, top-level scope that is outside of any procedure.

In order to get the values of our environment variables, we can declare a special global variable env and use it to access any variable obtained by typing env in our terminal window. We'll use the $HOME environment variable to specify a suitable location for directory browsing. A final detail to notice is that the dialog box will return paths that contain space characters. For now, this is fine, but keep in mind that we'll need to account for it when we actually try to copy the file to the iDisk later.

Before closing today's work, let's examine the WriteToBlog procedure. You'll notice that there's a line that references a shell script that you haven't written yet. The script involves several exciting new tools and concepts, so we need to save that one for next time.

For now, take note that the script exists and will ensure the grunt work of updating the blog that takes place at the back end. We can still understand the rest of the procedure, however, without knowing the details of this script. The idea is that we take the information stored in the text widget and store it to a file entitled newentry. The updateBlog.sh script uses this file to do its work. There's also a bit of basic error-checking we do to make sure the file opens successfully. Notice that getting the contents of the text editor is as simple as using the get command as an argument to the text widget and specifying that we want all of the text.

For Next Time

Consider implementing a markup for inserting links into your blog entry and review procedures ShowMessage and WriteToBlogQuit. There are many options, but think about the pros and cons of your choices before making a design decision.

You might also look into XHTML's specification for aligning text. Using the existing editor's functionality and the XHTML reference at w3schools.com, you should have all of the technical prowess you need to accomplish this task.

You'll find that a little bit of knowledge goes a long way in an app like this one. If you're really ambitious, dig into the text widget's tagging capabilities and try to add basic syntax highlighting for the XHTML commands you've included in your editor. We can only do so much here, but given sufficient time and effort, you can create truly amazing applications with Tcl/Tk. The best way to learn is to practice!

In the next lesson, you'll learn how to write the scripts we need to make procedure WriteToBlog functional, how to copy the image files from our local disk to our iDisk, and how to wrap some of that into a bash script that allows a measure of configurability. Once that's done, your blog will be ready for the world. The question is whether the world will be ready for your blog.

Matthew Russell is a computer scientist from middle Tennessee; and serves Digital Reasoning Systems as the Director of Advanced Technology. Hacking and writing are two activities essential to his renaissance man regimen.


Return to MacDevCenter.com.