From 03da993aca8fd4959ce5b2d3ee0b14b4a273ad87 Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Fri, 16 Jul 2021 08:41:25 +0100 Subject: [PATCH] Deprecate `__init__` methods which create the widget (#993) * Deprecate auto-create for Wx ListBox widget. * Deprecate autocreate for the Wx ImageButton. * More work on Wx ImageButton * Lots of fixes for WxPython ProgressWidget: - proper calling of super() - make autocreation optional - populate traits correctly - invoke correctly from ProgressDialog - fix background color issue * Deprecate auto-create on __init__ for Wx Grid * Deprecate autocreate on __init__ for ImageWidget. * Deprecate auto-create in __init__ for Wx viewer widgets. * Deprecate auto-create in __init__ for Wx Tree Widget. --- pyface/ui/wx/grid/grid.py | 19 ++++++++++--- pyface/ui/wx/image_button.py | 37 +++++++++++++++++-------- pyface/ui/wx/image_widget.py | 23 ++++++++++++---- pyface/ui/wx/list_box.py | 42 +++++++++++++++-------------- pyface/ui/wx/progress_dialog.py | 40 ++++++++++++++++++++------- pyface/ui/wx/tree/tree.py | 36 +++++++++++++++---------- pyface/ui/wx/viewer/table_viewer.py | 26 +++++++++++++----- pyface/ui/wx/viewer/tree_viewer.py | 28 ++++++++++++++----- 8 files changed, 175 insertions(+), 76 deletions(-) diff --git a/pyface/ui/wx/grid/grid.py b/pyface/ui/wx/grid/grid.py index e4332d393..5095eca80 100644 --- a/pyface/ui/wx/grid/grid.py +++ b/pyface/ui/wx/grid/grid.py @@ -10,8 +10,9 @@ """ A grid control with a model/ui architecture. """ - import sys +import warnings + import wx import wx.lib.gridmovers as grid_movers from os.path import abspath, exists @@ -165,15 +166,26 @@ def __init__(self, parent, **traits): 'parent' is the toolkit-specific control that is the grid's parent. """ + create = traits.pop('create', True) # Base class constructors. - super().__init__(**traits) + super().__init__(parent=parent, **traits) + if create: + self.create() + warnings.warn( + "automatic widget creation is deprecated and will be removed " + "in a future Pyface version, use create=False and explicitly " + "call create() for future behaviour", + PendingDeprecationWarning, + ) + + def _create_control(self, parent): # Flag set when columns are resizing: self._user_col_size = False # Create the toolkit-specific control. - self.control = self._grid = grid = wxGrid(parent, -1) + self._grid = grid = wxGrid(parent, -1) grid.grid = self self._moveTo = None @@ -328,6 +340,7 @@ def __init__(self, parent, **traits): self._edit = False grid.Bind(wx.EVT_IDLE, self._on_idle) + return grid def dispose(self): # Remove all wx handlers: diff --git a/pyface/ui/wx/image_button.py b/pyface/ui/wx/image_button.py index 4bb549008..6f90c0b70 100644 --- a/pyface/ui/wx/image_button.py +++ b/pyface/ui/wx/image_button.py @@ -14,11 +14,12 @@ toolbar button. """ - +import warnings import wx + from numpy import array, frombuffer, reshape, ravel, dtype -from traits.api import Bool, Str, Range, Enum, Instance, Event +from traits.api import Any, Bool, Str, Range, Enum, Instance, Event from pyface.ui_traits import Orientation from .widget import Widget @@ -78,6 +79,8 @@ class ImageButton(Widget): # Fired when a 'button' or 'toolbar' style control is clicked: clicked = Event() + _image = Any() + # --------------------------------------------------------------------------- # Initializes the object: # --------------------------------------------------------------------------- @@ -85,22 +88,34 @@ class ImageButton(Widget): def __init__(self, parent, **traits): """ Creates a new image control. """ - self._image = None + create = traits.pop("create", True) - super().__init__(**traits) + super().__init__(parent=parent, **traits) + if create: + self.create() + warnings.warn( + "automatic widget creation is deprecated and will be removed " + "in a future Pyface version, use create=False and explicitly " + "call create() for future behaviour", + PendingDeprecationWarning, + ) + + def _create_control(self, parent): self._recalc_size() - self.control = wx.Window(parent, -1, size=wx.Size(self._dx, self._dy)) - self.control._owner = self + control = wx.Window(parent, -1, size=wx.Size(self._dx, self._dy)) + control._owner = self self._mouse_over = self._button_down = False # Set up mouse event handlers: - self.control.Bind(wx.EVT_ENTER_WINDOW, self._on_enter_window) - self.control.Bind(wx.EVT_LEAVE_WINDOW, self._on_leave_window) - self.control.Bind(wx.EVT_LEFT_DOWN, self._on_left_down) - self.control.Bind(wx.EVT_LEFT_UP, self._on_left_up) - self.control.Bind(wx.EVT_PAINT, self._on_paint) + control.Bind(wx.EVT_ENTER_WINDOW, self._on_enter_window) + control.Bind(wx.EVT_LEAVE_WINDOW, self._on_leave_window) + control.Bind(wx.EVT_LEFT_DOWN, self._on_left_down) + control.Bind(wx.EVT_LEFT_UP, self._on_left_up) + control.Bind(wx.EVT_PAINT, self._on_paint) + + return control def _recalc_size(self): # Calculate the size of the button: diff --git a/pyface/ui/wx/image_widget.py b/pyface/ui/wx/image_widget.py index 059a9ab4e..e8ecf91c1 100644 --- a/pyface/ui/wx/image_widget.py +++ b/pyface/ui/wx/image_widget.py @@ -10,13 +10,12 @@ """ A clickable/draggable widget containing an image. """ +import warnings import wx - from traits.api import Any, Bool, Event - from .widget import Widget @@ -64,10 +63,24 @@ class ImageWidget(Widget): def __init__(self, parent, **traits): """ Creates a new widget. """ - # Base class constructors. - super().__init__(**traits) + create = traits.pop('create', True) + + # Base-class constructors. + super().__init__(parent=parent, **traits) + + # Create the widget! + if create: + self.create() + warnings.warn( + "automatic widget creation is deprecated and will be removed " + "in a future Pyface version, use create=False and explicitly " + "call create() for future behaviour", + PendingDeprecationWarning, + ) + + def _create_control(self, parent): # Add some padding around the image. size = (self.bitmap.GetWidth() + 10, self.bitmap.GetHeight() + 10) @@ -96,7 +109,7 @@ def __init__(self, parent, **traits): wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DHIGHLIGHT), 1, wx.SOLID ) - return + return self.control # ------------------------------------------------------------------------ # Private interface. diff --git a/pyface/ui/wx/list_box.py b/pyface/ui/wx/list_box.py index 31008d21a..61080032d 100644 --- a/pyface/ui/wx/list_box.py +++ b/pyface/ui/wx/list_box.py @@ -9,13 +9,12 @@ # Thanks for using Enthought open source! """ A simple list box widget with a model-view architecture. """ +import warnings import wx - from traits.api import Event, Instance, Int - from pyface.list_box_model import ListBoxModel from .widget import Widget @@ -37,14 +36,28 @@ class ListBox(Widget): # Default style. STYLE = wx.LB_SINGLE | wx.LB_HSCROLL | wx.LB_NEEDED_SB - def __init__(self, parent, **traits): + def __init__(self, parent=None, **traits): """ Creates a new list box. """ + create = traits.pop('create', True) + # Base-class constructors. - super().__init__(**traits) + super().__init__(parent=parent, **traits) # Create the widget! - self._create_control(parent) + if create: + self.create() + warnings.warn( + "automatic widget creation is deprecated and will be removed " + "in a future Pyface version, use create=False and explicitly " + "call create() for future behaviour", + PendingDeprecationWarning, + ) + + def _create(self): + super()._create() + + self._populate() # Listen for changes to the model. self.model.observe(self._on_model_changed, "list_changed") @@ -54,7 +67,6 @@ def dispose(self): self._on_model_changed, "list_changed", remove=True ) self.model.dispose() - return # ------------------------------------------------------------------------ # 'ListBox' interface. @@ -69,8 +81,6 @@ def refresh(self): # Populate the list. self._populate() - return - # ------------------------------------------------------------------------ # wx event handlers. # ------------------------------------------------------------------------ @@ -91,8 +101,6 @@ def _on_item_activated(self, event): # Trait event notification. self.item_activated = index - return - # ------------------------------------------------------------------------ # Trait handlers. # ------------------------------------------------------------------------ @@ -105,8 +113,6 @@ def _selection_changed(self, index): if index != -1: self.control.SetSelection(index) - return - # Dynamic -------------------------------------------------------------# def _on_model_changed(self, event): @@ -115,8 +121,6 @@ def _on_model_changed(self, event): # For now we just clear out the entire list. self.refresh() - return - # ------------------------------------------------------------------------ # Private interface. # ------------------------------------------------------------------------ @@ -124,20 +128,20 @@ def _on_model_changed(self, event): def _create_control(self, parent): """ Creates the widget. """ - self.control = wx.ListBox(parent, -1, style=self.STYLE) + control = wx.ListBox(parent, -1, style=self.STYLE) # Wire it up! - self.control.Bind( + control.Bind( wx.EVT_LISTBOX, self._on_item_selected, id=self.control.GetId() ) - self.control.Bind( + control.Bind( wx.EVT_LISTBOX_DCLICK, self._on_item_activated, id=self.control.GetId(), ) # Populate the list. - self._populate() + return control def _populate(self): """ Populates the list box. """ @@ -145,5 +149,3 @@ def _populate(self): for index in range(self.model.get_item_count()): label, item = self.model.get_item_at(index) self.control.Append(label, item) - - return diff --git a/pyface/ui/wx/progress_dialog.py b/pyface/ui/wx/progress_dialog.py index 874eac27c..2800e2d06 100644 --- a/pyface/ui/wx/progress_dialog.py +++ b/pyface/ui/wx/progress_dialog.py @@ -12,14 +12,15 @@ """ A simple progress bar intended to run in the UI thread """ +import warnings + import wx import time - -from traits.api import Bool, Enum, Instance, Int, Property, Str - +from traits.api import Bool, Instance, Int, Property, Str from pyface.i_progress_dialog import MProgressDialog +from pyface.ui_traits import Orientation from .widget import Widget from .window import Window @@ -34,7 +35,7 @@ class ProgressBar(Widget): control = Instance(wx.Gauge) #: The orientation of the progress bar. - direction = Enum("horizontal", "horizontal", "vertical") + direction = Orientation("horizontal") #: The maximum value for the progress bar. _max = Int() @@ -46,20 +47,39 @@ def __init__( maximum=100, direction="horizontal", size=(200, -1), + **traits, ): """ Constructs a progress bar which can be put into a panel, or optionaly, its own window """ - self._max = maximum - self.parent = parent + create = traits.pop("create", True) + + # XXX minimum is ignored - it either should be deprecated or supported + super().__init__( + parent=parent, + _max=maximum, + direction=direction, + size=size, + **traits, + ) + if create: + self.create() + warnings.warn( + "automatic widget creation is deprecated and will be removed " + "in a future Pyface version, use create=False and explicitly " + "call create() for future behaviour", + PendingDeprecationWarning, + ) + + def _create_control(self, parent): style = wx.GA_HORIZONTAL - if direction == "vertical": + if self.direction == "vertical": style = wx.GA_VERTICAL - self.control = wx.Gauge(parent, -1, maximum, style=style, size=size) + return wx.Gauge(parent, -1, self._max, style=style, size=self.size) def update(self, value): """ Update the progress bar to the desired value. """ @@ -306,7 +326,8 @@ def _create_label(self, dialog, parent_sizer, text): return label def _create_gauge(self, dialog, parent_sizer): - self.progress_bar = ProgressBar(dialog, self.min, self.max) + self.progress_bar = ProgressBar(dialog, self.min, self.max, create=False) + self.progress_bar.create() parent_sizer.Add( self.progress_bar.control, 0, wx.CENTER | wx.ALL, self.margin ) @@ -388,7 +409,6 @@ def _create_control(self, parent): sizer = wx.BoxSizer(wx.VERTICAL) dialog.SetSizer(sizer) dialog.SetAutoLayout(True) - dialog.SetBackgroundColour(wx.NullColour) self.dialog_size = wx.Size() diff --git a/pyface/ui/wx/tree/tree.py b/pyface/ui/wx/tree/tree.py index 7bd99b502..bbd48c981 100644 --- a/pyface/ui/wx/tree/tree.py +++ b/pyface/ui/wx/tree/tree.py @@ -13,21 +13,14 @@ import logging import os - +import warnings import wx from traits.api import ( - Any, - Bool, - Callable, - Enum, - Event, - Instance, - List, - Property, - Str, + Any, Bool, Callable, Enum, Event, Instance, Int, List, Property, Str, + Tuple, ) @@ -163,6 +156,9 @@ class Tree(Widget): # Flag for allowing selection events to be ignored _ignore_selection_events = Bool(False) + # The size of the icons in the tree. + _image_size = Tuple(Int, Int) + # ------------------------------------------------------------------------ # 'object' interface. # ------------------------------------------------------------------------ @@ -176,10 +172,21 @@ def __init__(self, parent, image_size=(16, 16), **traits): specifies the size of the images (if required) displayed in the tree. """ + create = traits.pop('create', True) # Base class constructors. - super().__init__(**traits) - + super().__init__(parent=parent, _image_size=image_size, **traits) + + if create: + self.create() + warnings.warn( + "automatic widget creation is deprecated and will be removed " + "in a future Pyface version, use create=False and explicitly " + "call create() for future behaviour", + PendingDeprecationWarning, + ) + + def _create_control(self, parent): # Create the toolkit-specific control. self.control = tree = _Tree( self, parent, wxid=wx.ID_ANY, style=self._get_style() @@ -211,11 +218,11 @@ def __init__(self, parent, image_size=(16, 16), **traits): tree.Bind(wx.EVT_TREE_DELETE_ITEM, self._on_tree_delete_item) # Enable the tree as a drag and drop target. - self.control.SetDropTarget(PythonDropTarget(self)) + tree.SetDropTarget(PythonDropTarget(self)) # The image list is a wxPython-ism that caches all images used in the # control. - self._image_list = ImageList(image_size[0], image_size[1]) + self._image_list = ImageList(*self._image_size) if self.show_images: tree.AssignImageList(self._image_list) @@ -228,6 +235,7 @@ def __init__(self, parent, image_size=(16, 16), **traits): # Listen for changes to the model. self._add_model_listeners(self.model) + return tree # ------------------------------------------------------------------------ # 'Tree' interface. diff --git a/pyface/ui/wx/viewer/table_viewer.py b/pyface/ui/wx/viewer/table_viewer.py index c52475b9e..d344c33c1 100644 --- a/pyface/ui/wx/viewer/table_viewer.py +++ b/pyface/ui/wx/viewer/table_viewer.py @@ -10,11 +10,11 @@ """ A viewer for tabular data. """ +import warnings import wx -from traits.api import Color, Event, Instance - +from traits.api import Color, Event, Instance, Int, Tuple from pyface.ui.wx.image_list import ImageList from pyface.viewer.content_viewer import ContentViewer @@ -53,6 +53,9 @@ class TableViewer(ContentViewer): # A drag operation was started on a node. row_begin_drag = Event() + # The size of the icons in the table. + _image_size = Tuple(Int, Int) + def __init__(self, parent, image_size=(16, 16), **traits): """ Creates a new table viewer. @@ -62,12 +65,23 @@ def __init__(self, parent, image_size=(16, 16), **traits): specifies the size of the images (if any) displayed in the table. """ + create = traits.pop('create', True) - # Base-class constructor. - super().__init__(**traits) + # Base class constructors. + super().__init__(parent=parent, _image_size=image_size, **traits) + if create: + self.create() + warnings.warn( + "automatic widget creation is deprecated and will be removed " + "in a future Pyface version, use create=False and explicitly " + "call create() for future behaviour", + PendingDeprecationWarning, + ) + + def _create_control(self, parent): # Create the toolkit-specific control. - self.control = table = _Table(parent, image_size, self) + self.control = table = _Table(parent, self._image_size, self) # Table events. table.Bind(wx.EVT_LIST_ITEM_SELECTED, self._on_item_selected) @@ -93,7 +107,7 @@ def __init__(self, parent, image_size=(16, 16), **traits): # don't want to react if the input is set in the constructor. self.observe(self._on_input_changed, "input") - return + return table # ------------------------------------------------------------------------ # 'TableViewer' interface. diff --git a/pyface/ui/wx/viewer/tree_viewer.py b/pyface/ui/wx/viewer/tree_viewer.py index 3a302c896..e6104eb47 100644 --- a/pyface/ui/wx/viewer/tree_viewer.py +++ b/pyface/ui/wx/viewer/tree_viewer.py @@ -10,12 +10,11 @@ """ A viewer based on a tree control. """ +import warnings import wx - -from traits.api import Bool, Enum, Event, Instance, List - +from traits.api import Bool, Enum, Event, Instance, Int, List, Tuple from pyface.ui.wx.image_list import ImageList from pyface.viewer.content_viewer import ContentViewer @@ -74,6 +73,9 @@ class TreeViewer(ContentViewer): # A key was pressed while the tree is in focus. key_pressed = Event() + # The size of the icons in the tree. + _image_size = Tuple(Int, Int) + # ------------------------------------------------------------------------ # 'object' interface. # ------------------------------------------------------------------------ @@ -87,9 +89,21 @@ def __init__(self, parent, image_size=(16, 16), **traits): specifies the size of the label images (if any) displayed in the tree. """ + create = traits.pop('create', True) - # Base class constructor. - super().__init__(**traits) + # Base class constructors. + super().__init__(parent=parent, _image_size=image_size, **traits) + + if create: + self.create() + warnings.warn( + "automatic widget creation is deprecated and will be removed " + "in a future Pyface version, use create=False and explicitly " + "call create() for future behaviour", + PendingDeprecationWarning, + ) + + def _create_control(self, parent): # Create the toolkit-specific control. self.control = tree = wx.TreeCtrl(parent, -1, style=self._get_style()) @@ -110,7 +124,7 @@ def __init__(self, parent, image_size=(16, 16), **traits): # The image list is a wxPython-ism that caches all images used in the # control. - self._image_list = ImageList(image_size[0], image_size[1]) + self._image_list = ImageList(*self._image_size) if self.show_images: tree.AssignImageList(self._image_list) @@ -121,7 +135,7 @@ def __init__(self, parent, image_size=(16, 16), **traits): if self.input is not None: self._add_element(None, self.input) - return + return tree # ------------------------------------------------------------------------ # 'TreeViewer' interface.