For a small chess program I created a small dictionary I use to convert an internal direction to an arrow glyph for display:
# large arrow glyphs (Unicode)
ARROWGLYPH = {
"n": "\u2B06", # straight up
"ne": "\u2B08", # up and right
"e": "\u2B95", # straight right
"se": "\u2B0A", # down and right
"s": "\u2B07", # straight down
"sw": "\u2B0B", # down and left
"w": "\u2B05", # straight left
"nw": "\u2B09", # up and left
"k1": "\u2B08", # up two, right one
"k2": "\u2B08", # up one, right two
"k3": "\u2B0A", # down one, right two
"k4": "\u2B0A", # down two, right one
"k5": "\u2B0B", # down two, left one
"k6": "\u2B0B", # down one, left two
"k7": "\u2B09", # up one, left two
"k8": "\u2B09", # up two, left one
"P2": "\u2B06", # up two
"p2": "\u2B07", # down two
"ck": "\u2B95", # right two
"cq": "\u2B05", # left two
}
When it comes time to display any of these, I change the text of a tkinter button to one of these Unicode characters. My problem is that these do not always display the way I expect them to. Specifically, the Unicode characters associated with “w”, “s” and “n” appear as narrow arrows within boxes, rather than as the wide arrows I want.
It seems that the Unicode values of “\u2b05”, “\u2b06” and “\u2b07” are emoji characters that can have variants. This could be what is happening, although my understanding is that a variant requires a following variant character (V15 or V16) to trigger the display of an alternate glyph. I can’t see anywhere in my code any attachment of a variant character to any arrow character. Nor does any examination of a value before or after attaching it to a button show anything other than the expected single Unicode character.
I do not believe that it would help to switch to narrow arrows altogether, as from what I can tell the three affected characters are also emoji.
Curiously to me, there does seem to be a way around this by altering the way I initialize the buttons. My goal is to create a button inside a label frame. There is only one button in each of 64 chessboard frames. My idea here is to dynamically alter the title of the frame to show information about the frame, such as its name and the number of black or white pieces attacking it. Details are probably not important, since all that seems to work just fine.
If I initialize each button’s text to a null string, the problem of differing arrow glyphs appears:
def makeSquare(parent, file, rank):
'''make one chessbaord square'''
# the name and color of this square
sqname = CM.fr2sq( file, rank )
sqcolor = CLR_LITESQ if (file%2 + rank%2)%2 else CLR_DARKSQ
# we'll make the containing frame with the label non-null
# - this will make the label as large as it will ever be
frame = tk.LabelFrame( parent,
bg=sqcolor,
text=sqname,
labelanchor=tk.N,
borderwidth=0,
font=(FNT_TEXT),
)
# this arrangement puts white at bottom of chessboard
frame.grid( column=file-1, row=8-rank )
# we need them later
frame.dfltcolor = sqcolor
frame.color = sqcolor
frame.name = sqname
# bind these events to this frame
frame.bind("<Enter>", lambda event: enterSquare(event.widget))
frame.bind("<Leave>", lambda event: leaveSquare(event.widget))
# a button inside each frame
button = tk.Button( frame,
text="" , # default text
anchor=tk.CENTER,
bg=sqcolor, # it'd be nice if we could make this transparent and just color frame background
font=( FNT_TEXT, ICO_POINTS ),
height=1, # this height and width makes frame look square-ish
width=4,
borderwidth=0, # hide borders between buttons
)
# put button in frame
button.grid(column=0, row=0, sticky="ew")
# bind this event
button.bind("<Button>", lambda event: hitSquare(event.widget))
return ( sqname, frame )
Apologies for the length, but I’m trying to illustrate just how minor a change solves the display of arrow characters with varying glyphs while also causing another curiousity:
directions = ["n", "ne", "e", "se", "s", "sw", "w", "nw", "k1", "k2", "k3", "k4", "k5", "k6", "k7", "k8", "P2", "p2", "ck", "cq"]
def makeSquare(parent, file, rank):
'''make one chessbaord square'''
# the name and color of this square
sqname = CM.fr2sq( file, rank )
sqcolor = CLR_LITESQ if (file%2 + rank%2)%2 else CLR_DARKSQ
# we'll make the containing frame with the label non-null
# - this will make the label as large as it will ever be
frame = tk.LabelFrame( parent,
bg=sqcolor,
text=sqname,
labelanchor=tk.N,
borderwidth=0,
font=(FNT_TEXT),
)
# this arrangement puts white at bottom of chessboard
frame.grid( column=file-1, row=8-rank )
# we need them later
frame.dfltcolor = sqcolor
frame.color = sqcolor
frame.name = sqname
# bind these events to this frame
frame.bind("<Enter>", lambda event: enterSquare(event.widget))
frame.bind("<Leave>", lambda event: leaveSquare(event.widget))
ndx = directions[ (file+rank) % len(directions) ]
textval = ARROWGLYPH[ ndx ]
# a button inside each frame
button = tk.Button( frame,
text=textval, # default text
anchor=tk.CENTER,
bg=sqcolor, # it'd be nice if we could make this transparent and just color frame background
font=( FNT_TEXT, ICO_POINTS ),
height=1, # this height and width makes frame look square-ish
width=4,
borderwidth=0, # hide borders between buttons
)
# put button in frame
button.grid(column=0, row=0, sticky="ew")
# bind this event
button.bind("<Button>", lambda event: hitSquare(event.widget))
# now blank the button's text
button.config( text="" )
return ( sqname, frame )
I first did this as a debug step, with the idea of starting out by displaying an arrow on each square. If the “wrong” arrows appeared for some directions, I imagined that would spark another idea of some kind. I was a bit surprised when the arrows looked just fine. Subsequent uses of them during later execution also looked fine. I saw no unexpected glyphs.
I don’t know (yet) how much of that is necessary, but somehow initializing each button with a Unicode arrow character prevents the emoji arrows from displaying incorrectly later. It may be that any non-null text at all would work, but I haven’t experimented that far yet.
There is still something curious going on. When doing this, the glyphs for the chess pieces themselves appear differently. The are still recognizably what they should be, but they are lighter. Their outlines are not as thick, and they are not quite so detailed. It’s as if they too are now showing a variant form - the chess piece glyphs are also in a Unicode variant block - even though I didn’t ask for one.
Is there an explanation somewhere of what’s going on with these Unicode characters? Am I misunderstanding something obvious? Doing something wrong?