March 21, 2003
JSR-666: Rich text identifiers

Further suggestion for JSR-666.

Previous JSR-666 recommendations:

JSR-666: Rich text identifiers

As is so often the case, Microsoft is leading the way here.

Remember back in the bad old days of DOS and Windows 3.x? 8.3 filenames? Yuck! With Win9x came long file names, and better still, embedded spaces.

Lets have this in Java. And why stop there? Let's go for full rich text! my button could be different from my button, and my button different again. (After all, mybutton and myButton are already different, so it's not so great a leap. my exception might be more serious than my exception.

I'm sure that there are some parsing issues to sort out, but they are (waves hand) pretty trivial, I'd imagine...

(P.S. Check out the URL...)

Posted to Java by Simon Brunning at 05:21 PM
Anyone remember Cough Candy Twists?

Fizzy Cola Bottles, Flying Saucers? Sherbet Lemons?

Check out The Old Sweet Shop, for all your online crap sweet needs.

Remember the way that sherbert lemons used to lacerate the inside of your mouth? Bliss.

Posted to Apropos of nothing by Simon Brunning at 05:03 PM
Driving win32 GUIs with Python, part 3

Some things you can do with a control once you have it.

See Driving win32 GUIs with Python, part 1 and Driving win32 GUIs with Python, part 2.

There are, of course, loads of things you can do with a control. Anything that you can do with a mouse or a keyboard can be automated. I'll just give a few simple examples, from which you should be able to extrapolate most things that you might need to do.

A great many of these actions are class specific - you can select one or many of a combo box's items, for example, but a button doesn't have items to select.

OK A nice simple one first. Let's click a button:

def click(hwnd):
win32gui.SendMessage(hwnd, win32con.WM_LBUTTONDOWN, 0, 0)
win32gui.SendMessage(hwnd, win32con.WM_LBUTTONUP, 0, 0)

We can use this function like so:

optDialog = findTopWindow(wantedText="Options")
def findAButtonCalledOK(hwnd, windowText, windowClass): # Define a function to find our button
return windowClass == "Button" and windowText == "OK"
okButton = findControl(optDialog, findAButtonCalledOK)
click(okButton)

You could do this more tersely with a lambda, by the way:

optDialog = findTopWindow(wantedText="Options")
okButton = findControl(optDialog, lambda hwnd, windowText, windowClass : windowClass == "Button" and windowText == "OK")
click(okButton)

I prefer the first form, but that's purely subjective.

And now, for my next trick, let's get the text from an Edit control. "But wait", you'll say, "can't you use the win32gui.GetWindowText() function"? No, actually, you can't. The thing is, this works for some classes of window - you can use win32gui.GetWindowText() to get the text of a button or a label, for example. But other classes don't have the kind of text that win32gui.GetWindowText() sets. An edit control is one of these - it has lines of text rather than just text. Here's a function which will get it for you:

def getEditText(hwnd):
result = []
bufferlength = struct.pack('i', 255)
linecount = win32gui.SendMessage(hwnd, win32con.EM_GETLINECOUNT, 0, 0)
for line in range(linecount):
linetext = bufferlength + "".ljust(253)
linelength = win32gui.SendMessage(hwnd, win32con.EM_GETLINE, line, linetext)
result.append(linetext[:linelength])
return result

The only complicated bit here is the struct stuff. When sending the win32con.EM_GETLINE, you need to pass a string, into which the line of text will be inserted. The first byte of this string must contain the total length of the string. struct to the rescue! It would be nice to wrap this up into a class, implementing a file-like interface, at some point. Or perhaps it should be a generator? Anyway, as it stands, you can use it like so:

genTop = findTopWindow(wantedText="Generating the Runtime")
def editFinder(hwnd, windowText, windowClass): return windowClass == "Edit"
genEdit = findControl(genTop, editFinder)
print getEditText(genEdit)

Now, combo-boxes. (These are the ones with a little down-arrow button to the right hand side, allowing you to select one (or perhaps more) from several options.) Here is the code to get a list of the values from a combo box:

def getComboboxItems(hwnd):
result = []
bufferlength = struct.pack('i', 255)
itemCount = win32gui.SendMessage(hwnd, win32con.CB_GETCOUNT, 0, 0)
for itemIndex in range(itemCount):
linetext = bufferlength + "".ljust(253)
linelength = win32gui.SendMessage(hwnd, win32con.CB_GETLBTEXT, itemIndex, linetext)
result.append(linetext[:linelength])
return result

Looks a bit like getEditText, doesn't it? I thought so - refactored version below:

def getMultipleWindowValues(hwnd, getCountMessage, getValueMessage):
result = []
bufferlength = struct.pack('i', 255)
count = win32gui.SendMessage(hwnd, getCountMessage, 0, 0)
for itemIndex in range(count):
value = bufferlength + "".ljust(253)
valueLength = win32gui.SendMessage(hwnd, getValueMessage, itemIndex, value)
result.append(value[:valueLength])
return result

def getComboboxItems(hwnd): return getMultipleWindowValues(hwnd, getCountMessage=win32con.CB_GETCOUNT, getValueMessage=win32con.CB_GETLBTEXT)
def getEditText(hwnd): return getMultipleWindowValues(hwnd, getCountMessage=win32con.EM_GETLINECOUNT, getValueMessage=win32con.EM_GETLINE)

Last thing today - selection a combo-box item.

def selectComboboxItem(hwnd, item):
win32gui.SendMessage(hwnd, win32con.CB_SETCURSEL, item, 0)
click(hwnd)
keystroke(hwnd, win32con.VK_RETURN)

def keystroke(hwnd, key):
win32gui.SendMessage(hwnd, win32con.WM_KEYDOWN, key, 0)
win32gui.SendMessage(hwnd, win32con.WM_KEYUP, key, 0)

I had hoped that the first of these messages would be enough. Unfortunately, it was not to be - while the selected item did change in the GUI, the application that I was automating didn't respond to the change without the click, and the drop-down list didn't disappear without the keystroke. If anyone can suggest a more elegant way of doing this, I'd be pleased to hear of it.

Here I put it all together

# Find the ACE window library selection combo
def findAceLibrarySelectionFunction(hwnd, windowText, windowClass): return windowClass == "ComboBox" and ("EVO1" in getComboboxItems(hwnd))
libCombo = findControl(findTopWindow(wantedText="ACE"), findAceLibrarySelectionFunction)

# Get a list of the combo items
items = getComboboxItems(libCombo)
print "Items: " + str(items)
import random

# Pick one at random, and select it
selectItemIndex = random.randrange(len(items))
print "Selecting: " + items[selectItemIndex]
selectComboboxItem(libCombo, selectItemIndex)

Well, that's just about it from me on this, really, though if anything else occurs to me, you'll be sure to know. ;-)

Update: See Driving win32 GUIs with Python, part 1, Driving win32 GUIs with Python, part 2, Driving win32 GUIs with Python, part 3 and Driving win32 GUIs with Python, part 4.

Posted to Python by Simon Brunning at 04:59 PM
Python: Multiple dispatch

Generalizing polymorphism with multimethods

Dive under the skin of OOP, see how it's done, and see how it can be done a little differently...

Via postneo.

Posted to Python by Simon Brunning at 12:49 PM
G.W. Bush's speech

Tonight, having grown tired of waiting for Jesus, Big Daddy and The Spook to get off their high horses, I have decided to act unilaterally to open the gates of Hell and bring about the apocalypse. I don't have to tell you how fucking "A" awesome this is. I say jump, and the Joint Chiefs of Staff cock and lock!

Hey, it's from the Whitehouse - it must be genuine!

It's well worth having a look round this site - it's hysterical. I particularly like Operation Infinite Purity: Winning the War on Masturbation, (a Democrat-created crisis), and Godly Tips on How to Punish and Beat Your Christian Child.

NB, I also like the fact that iSpell doesn't recognise 'Whitehouse', and suggested 'Whorehouse' as a correction.

Posted to Funny by Simon Brunning at 11:55 AM
No girls this weekend

Cath wants to keep them with her in Reading.

This is perfectly fair - after all, I get them most weekends. Cath needs some weekends to do stuff with them too. She has them during the week, of course, but during that time they are always rushing about, getting ready for school, or bed, or whatever. At the weekend, there is time to do stuff, and I'm lucky enough to get the lions share of that. Can't complain, can I?

But I still hate it. I never know what to do with myself at the weekend when I'm on my own.

I guess that I'll just have to get very drunk.

Posted to Apropos of nothing by Simon Brunning at 11:25 AM
The girls' boyfriends

I'm not allowed a girlfriend, but it seems that the girls are allowed boyfriends.

Freja (six) said that she did have a boyfriend, but that she "dumped him", (her exact words), because he kept "chasing" her. This doesn't refer to being too attentive, or making too many phone calls. No, he just chased her around the playground.

She says that she doesn't want a boyfriend any more - boys are "Yuck". That's my girl.

Ella (4 1/2) claims to have three boyfriends. It would be wrong of me to make any allusion to her mother at this point, so I won't.

Posted to Apropos of nothing by Simon Brunning at 09:18 AM