Skip to content

Commit 96bcf6f

Browse files
[3.9] bpo-33289: Return RGB triplet of ints instead of floats from tkinter.colorchooser (GH-6578). (GH-24318)
(cherry picked from commit 6713e86) Co-authored-by: Cheryl Sabella <[email protected]> (cherry picked from commit 3d5434d) Co-authored-by: Serhiy Storchaka <[email protected]>
1 parent 63ebba0 commit 96bcf6f

File tree

5 files changed

+102
-26
lines changed

5 files changed

+102
-26
lines changed

Lib/tkinter/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,8 +1160,7 @@ def winfo_reqwidth(self):
11601160
self.tk.call('winfo', 'reqwidth', self._w))
11611161

11621162
def winfo_rgb(self, color):
1163-
"""Return tuple of decimal values for red, green, blue for
1164-
COLOR in this widget."""
1163+
"""Return a tuple of integer RGB values in range(65536) for color in this widget."""
11651164
return self._getints(
11661165
self.tk.call('winfo', 'rgb', self._w, color))
11671166

Lib/tkinter/colorchooser.py

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,55 +8,67 @@
88
# fixed initialcolor handling in August 1998
99
#
1010

11-
#
12-
# options (all have default values):
13-
#
14-
# - initialcolor: color to mark as selected when dialog is displayed
15-
# (given as an RGB triplet or a Tk color string)
16-
#
17-
# - parent: which window to place the dialog on top of
18-
#
19-
# - title: dialog title
20-
#
2111

2212
from tkinter.commondialog import Dialog
2313

2414

25-
#
26-
# color chooser class
27-
2815
class Chooser(Dialog):
29-
"Ask for a color"
16+
"""Create a dialog for the tk_chooseColor command.
17+
18+
Args:
19+
master: The master widget for this dialog. If not provided,
20+
defaults to options['parent'] (if defined).
21+
options: Dictionary of options for the tk_chooseColor call.
22+
initialcolor: Specifies the selected color when the
23+
dialog is first displayed. This can be a tk color
24+
string or a 3-tuple of ints in the range (0, 255)
25+
for an RGB triplet.
26+
parent: The parent window of the color dialog. The
27+
color dialog is displayed on top of this.
28+
title: A string for the title of the dialog box.
29+
"""
3030

3131
command = "tk_chooseColor"
3232

3333
def _fixoptions(self):
34+
"""Ensure initialcolor is a tk color string.
35+
36+
Convert initialcolor from a RGB triplet to a color string.
37+
"""
3438
try:
35-
# make sure initialcolor is a tk color string
3639
color = self.options["initialcolor"]
3740
if isinstance(color, tuple):
38-
# assume an RGB triplet
41+
# Assume an RGB triplet.
3942
self.options["initialcolor"] = "#%02x%02x%02x" % color
4043
except KeyError:
4144
pass
4245

4346
def _fixresult(self, widget, result):
44-
# result can be somethings: an empty tuple, an empty string or
45-
# a Tcl_Obj, so this somewhat weird check handles that
47+
"""Adjust result returned from call to tk_chooseColor.
48+
49+
Return both an RGB tuple of ints in the range (0, 255) and the
50+
tk color string in the form #rrggbb.
51+
"""
52+
# Result can be many things: an empty tuple, an empty string, or
53+
# a _tkinter.Tcl_Obj, so this somewhat weird check handles that.
4654
if not result or not str(result):
47-
return None, None # canceled
55+
return None, None # canceled
4856

49-
# to simplify application code, the color chooser returns
50-
# an RGB tuple together with the Tk color string
57+
# To simplify application code, the color chooser returns
58+
# an RGB tuple together with the Tk color string.
5159
r, g, b = widget.winfo_rgb(result)
52-
return (r/256, g/256, b/256), str(result)
60+
return (r//256, g//256, b//256), str(result)
5361

5462

5563
#
5664
# convenience stuff
5765

58-
def askcolor(color = None, **options):
59-
"Ask for a color"
66+
def askcolor(color=None, **options):
67+
"""Display dialog window for selection of a color.
68+
69+
Convenience wrapper for the Chooser class. Displays the color
70+
chooser dialog with color as the initial value.
71+
"""
6072

6173
if color:
6274
options = options.copy()
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import unittest
2+
import tkinter
3+
from test.support import requires, run_unittest, swap_attr
4+
from tkinter.test.support import AbstractTkTest
5+
from tkinter import colorchooser
6+
7+
requires('gui')
8+
9+
10+
class ChooserTest(AbstractTkTest, unittest.TestCase):
11+
12+
@classmethod
13+
def setUpClass(cls):
14+
AbstractTkTest.setUpClass.__func__(cls)
15+
cls.cc = colorchooser.Chooser(initialcolor='dark blue slate')
16+
17+
def test_fixoptions(self):
18+
cc = self.cc
19+
cc._fixoptions()
20+
self.assertEqual(cc.options['initialcolor'], 'dark blue slate')
21+
22+
cc.options['initialcolor'] = '#D2D269691E1E'
23+
cc._fixoptions()
24+
self.assertEqual(cc.options['initialcolor'], '#D2D269691E1E')
25+
26+
cc.options['initialcolor'] = (210, 105, 30)
27+
cc._fixoptions()
28+
self.assertEqual(cc.options['initialcolor'], '#d2691e')
29+
30+
def test_fixresult(self):
31+
cc = self.cc
32+
self.assertEqual(cc._fixresult(self.root, ()), (None, None))
33+
self.assertEqual(cc._fixresult(self.root, ''), (None, None))
34+
self.assertEqual(cc._fixresult(self.root, 'chocolate'),
35+
((210, 105, 30), 'chocolate'))
36+
self.assertEqual(cc._fixresult(self.root, '#4a3c8c'),
37+
((74, 60, 140), '#4a3c8c'))
38+
39+
40+
tests_gui = (ChooserTest,)
41+
42+
if __name__ == "__main__":
43+
run_unittest(*tests_gui)

Lib/tkinter/test/test_tkinter/test_misc.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,26 @@ def test_clipboard_astral(self):
178178
with self.assertRaises(tkinter.TclError):
179179
root.clipboard_get()
180180

181+
def test_winfo_rgb(self):
182+
root = self.root
183+
rgb = root.winfo_rgb
184+
185+
# Color name.
186+
self.assertEqual(rgb('red'), (65535, 0, 0))
187+
self.assertEqual(rgb('dark slate blue'), (18504, 15677, 35723))
188+
# #RGB - extends each 4-bit hex value to be 16-bit.
189+
self.assertEqual(rgb('#F0F'), (0xFFFF, 0x0000, 0xFFFF))
190+
# #RRGGBB - extends each 8-bit hex value to be 16-bit.
191+
self.assertEqual(rgb('#4a3c8c'), (0x4a4a, 0x3c3c, 0x8c8c))
192+
# #RRRRGGGGBBBB
193+
self.assertEqual(rgb('#dede14143939'), (0xdede, 0x1414, 0x3939))
194+
# Invalid string.
195+
with self.assertRaises(tkinter.TclError):
196+
rgb('#123456789a')
197+
# RGB triplet is invalid input.
198+
with self.assertRaises(tkinter.TclError):
199+
rgb((111, 78, 55))
200+
181201
def test_event_repr_defaults(self):
182202
e = tkinter.Event()
183203
e.serial = 12345
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Correct call to :mod:`tkinter.colorchooser` to return RGB triplet of ints
2+
instead of floats. Patch by Cheryl Sabella.

0 commit comments

Comments
 (0)