diff --git a/pyface/tests/test_application_window.py b/pyface/tests/test_application_window.py index fea8d4199..ab5c4fe6d 100644 --- a/pyface/tests/test_application_window.py +++ b/pyface/tests/test_application_window.py @@ -225,6 +225,31 @@ def test_statusbar_changed(self): with self.event_loop(): self.window.close() + def test_statusbar_timed_changed(self): + from time import sleep + + # test that status bar gets changed as expected + self.window.status_bar_manager = StatusBarManager( + message="hello world" + ) + with self.event_loop(): + self.window._create() + with self.event_loop(): + self.window.show(True) + with self.event_loop(): + duration = 0.3 + status_bar = self.window.status_bar_manager + status_bar.message_duration_sec = duration + status_bar.messages = ["goodbye world"] + self.assertEqual(status_bar.message, "goodbye world") + sleep(duration) + self.gui.process_events() + self.assertEqual(status_bar.message, "") + with self.event_loop(): + self.window.show(False) + with self.event_loop(): + self.window.close() + def test_icon(self): # test that status bar gets created as expected self.window.icon = ImageResource("core") diff --git a/pyface/ui/qt4/action/status_bar_manager.py b/pyface/ui/qt4/action/status_bar_manager.py index ffc7c4762..69c2d5089 100644 --- a/pyface/ui/qt4/action/status_bar_manager.py +++ b/pyface/ui/qt4/action/status_bar_manager.py @@ -17,7 +17,9 @@ from pyface.qt import QtGui -from traits.api import Any, Bool, HasTraits, List, Property, Str +from traits.api import Any, Bool, Float, HasTraits, Instance, List, Property, \ + Str +from pyface.timer.api import Timer class StatusBarManager(HasTraits): @@ -38,6 +40,11 @@ class StatusBarManager(HasTraits): # Whether the status bar is visible. visible = Bool(True) + # Number of seconds to display new messages for [default: indefinitely] + message_duration_sec = Float + + _timer = Instance(Timer) + # ------------------------------------------------------------------------ # 'StatusBarManager' interface. # ------------------------------------------------------------------------ @@ -49,17 +56,17 @@ def create_status_bar(self, parent): self.status_bar = QtGui.QStatusBar(parent) self.status_bar.setSizeGripEnabled(self.size_grip) self.status_bar.setVisible(self.visible) - - if len(self.messages) > 1: - self._show_messages() - else: - self.status_bar.showMessage(self.message) + self._show_messages() return self.status_bar def destroy_status_bar(self): """ Destroys the status bar. """ if self.status_bar is not None: + if self._timer is not None: + self._timer.Stop() + self._timer = None + self.status_bar.deleteLater() self.status_bar = None @@ -68,7 +75,6 @@ def destroy_status_bar(self): # ------------------------------------------------------------------------ def _get_message(self): - if len(self.messages) > 0: message = self.messages[0] else: @@ -120,10 +126,25 @@ def _visible_changed(self): # ------------------------------------------------------------------------ def _show_messages(self): - """ Display the list of messages. """ + """ Display the list of messages. + + Note: not using the msecs argument of the `status_bar.showNessage` + method to keep this class' message trait in sync with the Qt widget. + """ + def timed_action(): + self.messages = [] + self._timer.Stop() + self._timer = None + + if self.status_bar is None: + return # FIXME v3: At the moment we just string them together but we may # decide to put all but the first message into separate widgets. We # probably also need to extend the API to allow a "message" to be a # widget - depends on what wx is capable of. self.status_bar.showMessage(" ".join(self.messages)) + + # Schedule removing the message if needed: + if self.message_duration_sec > 0 and self._timer is None: + self._timer = Timer(self.message_duration_sec * 1000, timed_action) diff --git a/pyface/ui/wx/action/status_bar_manager.py b/pyface/ui/wx/action/status_bar_manager.py index b5dee2deb..15478b920 100644 --- a/pyface/ui/wx/action/status_bar_manager.py +++ b/pyface/ui/wx/action/status_bar_manager.py @@ -16,7 +16,9 @@ import wx -from traits.api import Any, HasTraits, List, Property, Str +from traits.api import Any, Float, HasTraits, Instance, List, on_trait_change,\ + Property, Str +from pyface.timer.api import Timer class StatusBarManager(HasTraits): @@ -31,22 +33,24 @@ class StatusBarManager(HasTraits): # The toolkit-specific control that represents the status bar. status_bar = Any() + # Number of seconds to display new messages for [default: indefinitely] + message_duration_sec = Float + + _timer = Instance(Timer) + # ------------------------------------------------------------------------ # 'StatusBarManager' interface. # ------------------------------------------------------------------------ def create_status_bar(self, parent): """ Creates a status bar. """ - if self.status_bar is None: self.status_bar = wx.StatusBar(parent) self.status_bar._pyface_control = self if len(self.messages) > 1: self.status_bar.SetFieldsCount(len(self.messages)) - for i in range(len(self.messages)): - self.status_bar.SetStatusText(self.messages[i], i) - else: - self.status_bar.SetStatusText(self.message) + + self.messages_changed() return self.status_bar @@ -54,6 +58,10 @@ def remove_status_bar(self, parent): """ Removes a status bar. """ if self.status_bar is not None: + if self._timer is not None: + self._timer.Stop() + self._timer = None + self.status_bar.Destroy() self.status_bar._pyface_control = None self.status_bar = None @@ -92,18 +100,21 @@ def _set_message(self, value): # Trait event handlers. # ------------------------------------------------------------------------ - def _messages_changed(self): + @on_trait_change("messages[]", post_init=True) + def messages_changed(self): """ Sets the text displayed on the status bar. """ - if self.status_bar is not None: - for i in range(len(self.messages)): - self.status_bar.SetStatusText(self.messages[i], i) + def timed_action(): + self.messages = [] + self._timer.Stop() + self._timer = None - def _messages_items_changed(self): - """ Sets the text displayed on the status bar. """ + if self.status_bar is None: + return - if self.status_bar is not None: - for i in range(len(self.messages)): - self.status_bar.SetStatusText(self.messages[i], i) + for i in range(len(self.messages)): + self.status_bar.SetStatusText(self.messages[i], i) - return + # Schedule removing the message if needed: + if self.message_duration_sec > 0 and self._timer is None: + self._timer = Timer(self.message_duration_sec * 1000, timed_action)