bpo-30781: IDLE - Use ttk Notebook in ConfigDialog (#2938)

The notebook looks a bit better.  It will work better with separate page classes. Traversal of widgets by Tab works better.  Switching tabs with keys becomes possible.  The font sample box works better at large font sizes.

One of the two simulated click tests no longer works.  This will be investigated while fixing a bug with the widget itself.
This commit is contained in:
Terry Jan Reedy 2017-07-29 00:49:39 -04:00 committed by GitHub
parent 5d0f30aae5
commit b331f80b47
3 changed files with 43 additions and 35 deletions

View File

@ -15,7 +15,7 @@ from tkinter import (Toplevel, Frame, LabelFrame, Listbox, Label, Button,
TOP, BOTTOM, RIGHT, LEFT, SOLID, GROOVE, NORMAL, DISABLED,
NONE, BOTH, X, Y, W, E, EW, NS, NSEW, NW,
HORIZONTAL, VERTICAL, ANCHOR, ACTIVE, END)
from tkinter.ttk import Scrollbar
from tkinter.ttk import Notebook, Scrollbar
import tkinter.colorchooser as tkColorChooser
import tkinter.font as tkFont
import tkinter.messagebox as tkMessageBox
@ -101,15 +101,19 @@ class ConfigDialog(Toplevel):
load_configs: Load pages except for extensions.
activate_config_changes: Tell editors to reload.
"""
self.tab_pages = TabbedPageSet(self,
page_names=['Fonts/Tabs', 'Highlighting', 'Keys', 'General',
'Extensions'])
self.tab_pages.pack(side=TOP, expand=TRUE, fill=BOTH)
self.create_page_font_tab()
self.create_page_highlight()
self.create_page_keys()
self.create_page_general()
self.create_page_extensions()
self.note = note = Notebook(self, width=450, height=450)
fontpage = self.create_page_font_tab()
highpage = self.create_page_highlight()
keyspage = self.create_page_keys()
genpage = self.create_page_general()
extpage = self.create_page_extensions()
note.add(fontpage, text='Fonts/Tabs')
note.add(highpage, text='Highlights')
note.add(keyspage, text=' Keys ')
note.add(genpage, text=' General ')
note.add(extpage, text='Extensions')
note.enable_traversal()
note.pack(side=TOP, expand=TRUE, fill=BOTH)
self.create_action_buttons().pack(side=BOTTOM)
def load_configs(self):
@ -270,7 +274,7 @@ class ConfigDialog(Toplevel):
# Create widgets:
# body and body section frames.
frame = self.tab_pages.pages['Fonts/Tabs'].frame
frame = Frame(self.note)
frame_font = LabelFrame(
frame, borderwidth=2, relief=GROOVE, text=' Base Editor Font ')
frame_indent = LabelFrame(
@ -281,7 +285,7 @@ class ConfigDialog(Toplevel):
font_name_title = Label(
frame_font_name, justify=LEFT, text='Font Face :')
self.fontlist = Listbox(frame_font_name, height=5,
takefocus=FALSE, exportselection=FALSE)
takefocus=True, exportselection=FALSE)
self.fontlist.bind('<ButtonRelease-1>', self.on_fontlist_select)
self.fontlist.bind('<KeyRelease-Up>', self.on_fontlist_select)
self.fontlist.bind('<KeyRelease-Down>', self.on_fontlist_select)
@ -297,7 +301,7 @@ class ConfigDialog(Toplevel):
temp_font = tkFont.Font(parent, ('courier', 10, 'normal'))
self.font_sample = Label(
frame_font_sample, justify=LEFT, font=temp_font,
text='AaBbCcDdEe\nFfGgHhIiJjK\n1234567890\n#:+=(){}[]')
text='AaBbCcDdEe\nFfGgHhIiJj\n1234567890\n#:+=(){}[]')
# frame_indent.
indent_title = Label(
frame_indent, justify=LEFT,
@ -493,10 +497,9 @@ class ConfigDialog(Toplevel):
self.highlight_target = tracers.add(
StringVar(parent), self.var_changed_highlight_target)
##widget creation
#body frame
frame = self.tab_pages.pages['Highlighting'].frame
#body section frames
# Widget creation:
# body frame and section frames
frame = Frame(self.note)
frame_custom = LabelFrame(frame, borderwidth=2, relief=GROOVE,
text=' Custom Highlighting ')
frame_theme = LabelFrame(frame, borderwidth=2, relief=GROOVE,
@ -504,12 +507,12 @@ class ConfigDialog(Toplevel):
#frame_custom
self.highlight_sample=Text(
frame_custom, relief=SOLID, borderwidth=1,
font=('courier', 12, ''), cursor='hand2', width=21, height=11,
font=('courier', 12, ''), cursor='hand2', width=21, height=13,
takefocus=FALSE, highlightthickness=0, wrap=NONE)
text=self.highlight_sample
text.bind('<Double-Button-1>', lambda e: 'break')
text.bind('<B1-Motion>', lambda e: 'break')
text_and_tags=(
text_and_tags=(('\n', 'normal'),
('#you can click here', 'comment'), ('\n', 'normal'),
('#to choose items', 'comment'), ('\n', 'normal'),
('def', 'keyword'), (' ', 'normal'),
@ -525,7 +528,7 @@ class ConfigDialog(Toplevel):
('cursor |', 'cursor'), ('\n ', 'normal'),
('shell', 'console'), (' ', 'normal'),
('stdout', 'stdout'), (' ', 'normal'),
('stderr', 'stderr'), ('\n', 'normal'))
('stderr', 'stderr'), ('\n\n', 'normal'))
for texttag in text_and_tags:
text.insert(END, texttag[0], texttag[1])
for element in self.theme_elements:
@ -1039,10 +1042,9 @@ class ConfigDialog(Toplevel):
self.keybinding = tracers.add(
StringVar(parent), self.var_changed_keybinding)
##widget creation
#body frame
frame = self.tab_pages.pages['Keys'].frame
#body section frames
# Widget creation:
# body and section frames.
frame = Frame(self.note)
frame_custom = LabelFrame(
frame, borderwidth=2, relief=GROOVE,
text=' Custom Key Bindings ')
@ -1449,9 +1451,8 @@ class ConfigDialog(Toplevel):
StringVar(parent), ('main', 'EditorWindow', 'height'))
# Create widgets:
# body.
frame = self.tab_pages.pages['General'].frame
# body section frames.
# body and section frames.
frame = Frame(self.note)
frame_run = LabelFrame(frame, borderwidth=2, relief=GROOVE,
text=' Startup Preferences ')
frame_save = LabelFrame(frame, borderwidth=2, relief=GROOVE,
@ -1488,7 +1489,7 @@ class ConfigDialog(Toplevel):
frame_helplist = Frame(frame_help)
frame_helplist_buttons = Frame(frame_helplist)
self.helplist = Listbox(
frame_helplist, height=5, takefocus=FALSE,
frame_helplist, height=5, takefocus=True,
exportselection=FALSE)
scroll_helplist = Scrollbar(frame_helplist)
scroll_helplist['command'] = self.helplist.yview
@ -1669,7 +1670,7 @@ class ConfigDialog(Toplevel):
save_all_changed_extensions: Call extension page Save().
"""
parent = self.parent
frame = self.tab_pages.pages['Extensions'].frame
frame = Frame(self.note)
self.ext_defaultCfg = idleConf.defaultCfg['extensions']
self.ext_userCfg = idleConf.userCfg['extensions']
self.is_int = self.register(is_int)
@ -1704,6 +1705,8 @@ class ConfigDialog(Toplevel):
self.extension_list.selection_set(0)
self.extension_selected(None)
return frame
def load_extensions(self):
"Fill self.extensions with data from the default and user configs."
self.extensions = {}

View File

@ -296,20 +296,24 @@ class GeneralTest(unittest.TestCase):
d.set = d.set_add_delete_state
d.upc = d.update_help_changes
helplist = d.helplist
helplist.insert(0, 'source')
helplist.activate(0)
dex = 'end'
helplist.insert(dex, 'source')
helplist.activate(dex)
helplist.focus_force()
helplist.see(0)
helplist.see(dex)
helplist.update()
x, y, dx, dy = helplist.bbox(0)
x, y, dx, dy = helplist.bbox(dex)
x += dx // 2
y += dy // 2
d.set.called = d.upc.called = 0
helplist.event_generate('<Enter>', x=0, y=0)
helplist.event_generate('<Motion>', x=x, y=y)
helplist.event_generate('<Button-1>', x=x, y=y)
helplist.event_generate('<ButtonRelease-1>', x=x, y=y)
self.assertEqual(helplist.get('anchor'), 'source')
self.assertTrue(d.set.called)
# The following fail after the switch to
# self.assertEqual(helplist.get('anchor'), 'source')
# self.assertTrue(d.set.called)
self.assertFalse(d.upc.called)
def test_set_add_delete_state(self):

View File

@ -0,0 +1 @@
IDLE - Use ttk Notebook in ConfigDialog