tkFont.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. # Tkinter font wrapper
  2. #
  3. # written by Fredrik Lundh, February 1998
  4. #
  5. # FIXME: should add 'displayof' option where relevant (actual, families,
  6. # measure, and metrics)
  7. #
  8. __version__ = "0.9"
  9. import Tkinter
  10. # weight/slant
  11. NORMAL = "normal"
  12. ROMAN = "roman"
  13. BOLD = "bold"
  14. ITALIC = "italic"
  15. def nametofont(name):
  16. """Given the name of a tk named font, returns a Font representation.
  17. """
  18. return Font(name=name, exists=True)
  19. class Font:
  20. """Represents a named font.
  21. Constructor options are:
  22. font -- font specifier (name, system font, or (family, size, style)-tuple)
  23. name -- name to use for this font configuration (defaults to a unique name)
  24. exists -- does a named font by this name already exist?
  25. Creates a new named font if False, points to the existing font if True.
  26. Raises _Tkinter.TclError if the assertion is false.
  27. the following are ignored if font is specified:
  28. family -- font 'family', e.g. Courier, Times, Helvetica
  29. size -- font size in points
  30. weight -- font thickness: NORMAL, BOLD
  31. slant -- font slant: ROMAN, ITALIC
  32. underline -- font underlining: false (0), true (1)
  33. overstrike -- font strikeout: false (0), true (1)
  34. """
  35. def _set(self, kw):
  36. options = []
  37. for k, v in kw.items():
  38. options.append("-"+k)
  39. options.append(str(v))
  40. return tuple(options)
  41. def _get(self, args):
  42. options = []
  43. for k in args:
  44. options.append("-"+k)
  45. return tuple(options)
  46. def _mkdict(self, args):
  47. options = {}
  48. for i in range(0, len(args), 2):
  49. options[args[i][1:]] = args[i+1]
  50. return options
  51. def __init__(self, root=None, font=None, name=None, exists=False, **options):
  52. if not root:
  53. root = Tkinter._default_root
  54. tk = getattr(root, 'tk', root)
  55. if font:
  56. # get actual settings corresponding to the given font
  57. font = tk.splitlist(tk.call("font", "actual", font))
  58. else:
  59. font = self._set(options)
  60. if not name:
  61. name = "font" + str(id(self))
  62. self.name = name
  63. if exists:
  64. self.delete_font = False
  65. # confirm font exists
  66. if self.name not in tk.splitlist(tk.call("font", "names")):
  67. raise Tkinter._tkinter.TclError, "named font %s does not already exist" % (self.name,)
  68. # if font config info supplied, apply it
  69. if font:
  70. tk.call("font", "configure", self.name, *font)
  71. else:
  72. # create new font (raises TclError if the font exists)
  73. tk.call("font", "create", self.name, *font)
  74. self.delete_font = True
  75. self._tk = tk
  76. self._split = tk.splitlist
  77. self._call = tk.call
  78. def __str__(self):
  79. return self.name
  80. def __eq__(self, other):
  81. return isinstance(other, Font) and self.name == other.name
  82. def __getitem__(self, key):
  83. return self.cget(key)
  84. def __setitem__(self, key, value):
  85. self.configure(**{key: value})
  86. def __del__(self):
  87. try:
  88. if self.delete_font:
  89. self._call("font", "delete", self.name)
  90. except (KeyboardInterrupt, SystemExit):
  91. raise
  92. except Exception:
  93. pass
  94. def copy(self):
  95. "Return a distinct copy of the current font"
  96. return Font(self._tk, **self.actual())
  97. def actual(self, option=None):
  98. "Return actual font attributes"
  99. if option:
  100. return self._call("font", "actual", self.name, "-"+option)
  101. else:
  102. return self._mkdict(
  103. self._split(self._call("font", "actual", self.name))
  104. )
  105. def cget(self, option):
  106. "Get font attribute"
  107. return self._call("font", "config", self.name, "-"+option)
  108. def config(self, **options):
  109. "Modify font attributes"
  110. if options:
  111. self._call("font", "config", self.name,
  112. *self._set(options))
  113. else:
  114. return self._mkdict(
  115. self._split(self._call("font", "config", self.name))
  116. )
  117. configure = config
  118. def measure(self, text):
  119. "Return text width"
  120. return int(self._call("font", "measure", self.name, text))
  121. def metrics(self, *options):
  122. """Return font metrics.
  123. For best performance, create a dummy widget
  124. using this font before calling this method."""
  125. if options:
  126. return int(
  127. self._call("font", "metrics", self.name, self._get(options))
  128. )
  129. else:
  130. res = self._split(self._call("font", "metrics", self.name))
  131. options = {}
  132. for i in range(0, len(res), 2):
  133. options[res[i][1:]] = int(res[i+1])
  134. return options
  135. def families(root=None):
  136. "Get font families (as a tuple)"
  137. if not root:
  138. root = Tkinter._default_root
  139. return root.tk.splitlist(root.tk.call("font", "families"))
  140. def names(root=None):
  141. "Get names of defined fonts (as a tuple)"
  142. if not root:
  143. root = Tkinter._default_root
  144. return root.tk.splitlist(root.tk.call("font", "names"))
  145. # --------------------------------------------------------------------
  146. # test stuff
  147. if __name__ == "__main__":
  148. root = Tkinter.Tk()
  149. # create a font
  150. f = Font(family="times", size=30, weight=NORMAL)
  151. print f.actual()
  152. print f.actual("family")
  153. print f.actual("weight")
  154. print f.config()
  155. print f.cget("family")
  156. print f.cget("weight")
  157. print names()
  158. print f.measure("hello"), f.metrics("linespace")
  159. print f.metrics()
  160. f = Font(font=("Courier", 20, "bold"))
  161. print f.measure("hello"), f.metrics("linespace")
  162. w = Tkinter.Label(root, text="Hello, world", font=f)
  163. w.pack()
  164. w = Tkinter.Button(root, text="Quit!", command=root.destroy)
  165. w.pack()
  166. fb = Font(font=w["font"]).copy()
  167. fb.config(weight=BOLD)
  168. w.config(font=fb)
  169. Tkinter.mainloop()