Repository: psychopy/psychopy

Issue:
Feature request: ability to clear output window
IMHO, it would be nice if you could clear the messages from the output window. Sometimes a run-time error results in dozens of error messages displayed in the output window, but it's usually the first one or two that indicate where in your code the error originated. So on a first run, you can just scroll all the way to the start to find it. But on subsequent runs, you have to scroll back until you find where the trace starts. I usually end up exiting PsychoPy and starting it again (I know, I'm lazy), but if I could clear the output window before each subsequent run, I wouldn't have to do that. Maybe there's already some way to do this, but I couldn't find it.


Discussion:
Agreed. First up I guess the panel needs a button ("clear") and maybe ("copy")? @dvbridges might enjoy this one! After adding those buttons, the mechanics of actually clearing the buffer (or copying to clipboard) are pretty trivial.
Yes, would like to do this thanks 👍 
Thanks! I don't know if a copy button is really needed. A standard copy-and-paste works (at least in Windows). But I guess if there are dozens of messages, a button might be convenient.
Agree wholeheartedly with the need for this, but rather than cluttering the interface for a relatively rare operation, what about just adding an option from a contextual menu from right-clicking (i.e. along with the copy/paste options)? That would be the first place I'd think of looking, if there wasn't an obvious button.
Leaving as unassigned for now, in case someone else wants to join in. I have other priorities (e.g., timing tests) for the next week or so.
I just took a look at the context menu for the output tab. If you right-click on the tab, there already are options to "Select All", "Cut", "Copy", "Paste" and "Delete". but the "Cut" option is grayed-out, even if some text has been selected. The "Copy" function works, though.

Resolving patch:
diff --git a/psychopy/app/coder/coder.py b/psychopy/app/coder/coder.py
--- a/psychopy/app/coder/coder.py
+++ b/psychopy/app/coder/coder.py
@@ -1278,7 +1278,10 @@ def __init__(self, parent, ID, title, files=(), app=None):
             fontSize=self.prefs['outputFontSize'])
         self.outputWindow.write(_translate('Welcome to PsychoPy3!') + '\n')
         self.outputWindow.write("v%s\n" % self.app.version)
+        # Add context manager to output window
+        self.outputWindow.Bind(wx.EVT_CONTEXT_MENU, self.outputContextMenu)
         self.shelf.AddPage(self.outputWindow, _translate('Output'))
+
         if self.app._appLoaded:
             self.setOutputWindow()
 
@@ -1337,6 +1340,45 @@ def __init__(self, parent, ID, title, files=(), app=None):
         self.SendSizeEvent()
         self.app.trackFrame(self)
 
+    def outputContextMenu(self, event):
+        """Custom context menu for output window.
+
+        Provides menu items to clear all, select all and copy selected text."""
+        if not hasattr(self, "outputMenuID1"):
+            self.outputMenuID1 = wx.NewId()
+            self.outputMenuID2 = wx.NewId()
+            self.outputMenuID3 = wx.NewId()
+
+            self.Bind(wx.EVT_MENU, self.outputClear, id=self.outputMenuID1)
+            self.Bind(wx.EVT_MENU, self.outputSelectAll, id=self.outputMenuID2)
+            self.Bind(wx.EVT_MENU, self.outputCopy, id=self.outputMenuID3)
+
+        menu = wx.Menu()
+        itemClear = wx.MenuItem(menu, self.outputMenuID1, "Clear All")
+        itemSelect = wx.MenuItem(menu, self.outputMenuID2, "Select All")
+        itemCopy = wx.MenuItem(menu, self.outputMenuID3, "Copy")
+
+        menu.Append(itemClear)
+        menu.AppendSeparator()
+        menu.Append(itemSelect)
+        menu.Append(itemCopy)
+        # Popup the menu.  If an item is selected then its handler
+        # will be called before PopupMenu returns.
+        self.PopupMenu(menu)
+        menu.Destroy()
+
+    def outputClear(self, event):
+        """Clears the output window in Coder"""
+        self.outputWindow.Clear()
+
+    def outputSelectAll(self, event):
+        """Selects all text from the output window in Coder"""
+        self.outputWindow.SelectAll()
+
+    def outputCopy(self, event):
+        """Copies all text from the output window in Coder"""
+        self.outputWindow.Copy()
+
     def makeMenus(self):
         # ---Menus---#000000#FFFFFF-------------------------------------------
         menuBar = wx.MenuBar()


Test patch: