Skip to content

Commit 3d5434d

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]>
1 parent ff06957 commit 3d5434d

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,57 +8,69 @@
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
__all__ = ["Chooser", "askcolor"]
2515

2616

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

3333
command = "tk_chooseColor"
3434

3535
def _fixoptions(self):
36+
"""Ensure initialcolor is a tk color string.
37+
38+
Convert initialcolor from a RGB triplet to a color string.
39+
"""
3640
try:
37-
# make sure initialcolor is a tk color string
3841
color = self.options["initialcolor"]
3942
if isinstance(color, tuple):
40-
# assume an RGB triplet
43+
# Assume an RGB triplet.
4144
self.options["initialcolor"] = "#%02x%02x%02x" % color
4245
except KeyError:
4346
pass
4447

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

51-
# to simplify application code, the color chooser returns
52-
# an RGB tuple together with the Tk color string
59+
# To simplify application code, the color chooser returns
60+
# an RGB tuple together with the Tk color string.
5361
r, g, b = widget.winfo_rgb(result)
54-
return (r/256, g/256, b/256), str(result)
62+
return (r//256, g//256, b//256), str(result)
5563

5664

5765
#
5866
# convenience stuff
5967

60-
def askcolor(color = None, **options):
61-
"Ask for a color"
68+
def askcolor(color=None, **options):
69+
"""Display dialog window for selection of a color.
70+
71+
Convenience wrapper for the Chooser class. Displays the color
72+
chooser dialog with color as the initial value.
73+
"""
6274

6375
if color:
6476
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
@@ -192,6 +192,26 @@ def test_clipboard_astral(self):
192192
with self.assertRaises(tkinter.TclError):
193193
root.clipboard_get()
194194

195+
def test_winfo_rgb(self):
196+
root = self.root
197+
rgb = root.winfo_rgb
198+
199+
# Color name.
200+
self.assertEqual(rgb('red'), (65535, 0, 0))
201+
self.assertEqual(rgb('dark slate blue'), (18504, 15677, 35723))
202+
# #RGB - extends each 4-bit hex value to be 16-bit.
203+
self.assertEqual(rgb('#F0F'), (0xFFFF, 0x0000, 0xFFFF))
204+
# #RRGGBB - extends each 8-bit hex value to be 16-bit.
205+
self.assertEqual(rgb('#4a3c8c'), (0x4a4a, 0x3c3c, 0x8c8c))
206+
# #RRRRGGGGBBBB
207+
self.assertEqual(rgb('#dede14143939'), (0xdede, 0x1414, 0x3939))
208+
# Invalid string.
209+
with self.assertRaises(tkinter.TclError):
210+
rgb('#123456789a')
211+
# RGB triplet is invalid input.
212+
with self.assertRaises(tkinter.TclError):
213+
rgb((111, 78, 55))
214+
195215
def test_event_repr_defaults(self):
196216
e = tkinter.Event()
197217
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)