Changing the font in Enthought TraitsUI TextEditor - python

I would like to change the font in a TextEditor in TraitsUI view. How can I do this?
I read the (excellent) documentation, the API reference docs and asked Google for an answer, but could not find one.
Platform- and toolkit-independence is not a requirement for my application. I work on Windows and use the wx toolkit.

After digging into the source code and some experimenting, I came up with the following solution. To me, this seems to be too complicated (I have to subclass two classes!) to be the simplest or intended way to do this.
If there is a better solution, I would be glad to learn about it.
import wx
from traitsui.wx.text_editor import CustomEditor
from traitsui.editors.text_editor import ToolkitEditorFactory
class _MyTextEditor(CustomEditor):
def init(self, parent):
CustomEditor.init(self, parent)
font = wx.Font(10, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
self.control.SetFont(font)
class MyTextEditor(ToolkitEditorFactory):
klass = _MyTextEditor
def _get_custom_editor_class(self):
return _MyTextEditor
def _get_simple_editor_class(self):
return _MyTextEditor
if __name__ == "__main__":
from traitsui.api import View, Item
from traits.api import Str, HasTraits
class MyTestcase(HasTraits):
a_string = Str()
traits_view = View(Item('a_string', editor=MyTextEditor()))
w = MyTestcase()
w.configure_traits()

I think Traits uses Qt. So to change the font size, use the style_sheet argument. See example below
Item('a_string', style_sheet='*{font-size:24px}')
If you want to apply multiple font options, separate with a semicolon like this:
Item('a_string', style_sheet='*{font-size:24px; font-style:italic}')
For all of Qt stylesheet options that you can apply, look at
Qt Style Sheets Reference

Related

Maya Python: Button always at the center of the window

I'm starting experimenting with Maya python, and I'm trying to do some UI.
I came across to a really strange problem, I can't get a button to stay in the center of the windows.
I've tried different things but nothing seems to work, here is the code:
import maya.cmds as cmds
cmds.window( width=200 )
WS = mc.workspaceControl("dockName", retain = False, floating = True,mw=80)
submit_widget = cmds.rowLayout(numberOfColumns=1, p=WS)
cmds.button( label='Submit Job',width=130,align='center', p=submit_widget)
cmds.showWindow()
this is a simple version but still, I can't get it to work.
can someone help me?
I honestly don't know the answer as anytime I have to dig into Maya's native UI stuff it makes me question my own life.
So I know it's not exactly what you're asking for, but I'll opt with this: Use PySide instead. At first glance it might make you go "woah, that's way too hard", but it's also a million times better (and actually easier). It's much more powerful, flexible, has great documentation, and also used outside of Maya (so actually useful to learn). Maya's own interface uses the same framework, so you can even edit it with PySide once you're more comfortable with it.
Here's a bare-bones example to create a centered button in a window:
# Import PySide libraries.
from PySide2 import QtCore
from PySide2 import QtWidgets
class MyWindow(QtWidgets.QWidget): # Create a class for our window, which inherits from `QWidget`
def __init__(self, parent=None): # The class's constructor.
super(MyWindow, self).__init__(parent) # Initialize its `QWidget` constructor method.
self.my_button = QtWidgets.QPushButton("My button!") # Create a button!
self.my_layout = QtWidgets.QVBoxLayout() # Create a vertical layout!
self.my_layout.setAlignment(QtCore.Qt.AlignCenter) # Center the horizontal alignment.
self.my_layout.addWidget(self.my_button) # Add the button to the layout.
self.setLayout(self.my_layout) # Make the window use this layout.
self.resize(300, 300) # Resize the window so it's not tiny.
my_window_instance = MyWindow() # Create an instance of our window class.
my_window_instance.show() # Show it!
Not too bad, right?

I can't find classes/attribute on matplotlib documents

From the code below, all I want to know is what is the window used for?
plt.ion()
figManager = plt.get_current_fig_manager()
figManager.window.showMaximized()
I went to the matplotlib documentation, searched for get_current_fig_manager() and it retured FigureManagerBase. I then looked at FigureMangerBase, and there's no window attribute, methods, super class is object.
In case you are using the Qt5Agg backend and look at the repr of the figManager.window, it is a matplotlib.backends.backend_qt5.MainWindow object.
Digging into the MPL code, you can find it is just a wrapper object for the QtWidgets.QMainWindow object. Code found on github:
class MainWindow(QtWidgets.QMainWindow):
closing = QtCore.Signal()
def closeEvent(self, event):
self.closing.emit()
QtWidgets.QMainWindow.closeEvent(self, event)
It looks like it just gets tacked on as an undocumented attribute to the FigureManagerBase object as a way to reference the open Qt window. This allows the user to access the Qt windows when in interactive mode without having to import Qt.
Probably should be documented. You can always put in an issue.

How to create an interactive text menu in Python?

I'm not sure what to call it. I want to know how to make one of those menus where you use the arrow keys to highlight your options and press enter to accept it.
The questioner acknowledged being unsure how to clearly state what they're after (I know the feeling!) and it is a little while after the question was posted, but in light of their comment suggesting they were after text, I believe something like python-prompt-toolkit, which is used to provide text-based autocomplete in a number of Python projects, may offer a solution.
There is documentation here which has this example of using a WordCompleter:
from prompt_toolkit import prompt
from prompt_toolkit.completion import WordCompleter
html_completer = WordCompleter(['<html>', '<body>', '<head>', '<title>'])
text = prompt('Enter HTML: ', completer=html_completer)
print('You said: %s' % text)
That produces output like this:
The example above is still relatively like a ComboBox merely rendered in text, but there are ways to produce other styles of menu as shown in the gallery here.
If that isn't sufficient then another option is looking into something that wraps ncurses, like https://bitbucket.org/npcole/npyscreen or http://urwid.org/ .
The answer to your question including the examples you provided is curses. This package is very much dependent on the underlying operating system. So if platform independence is key then you will get issues. There is for example a Windows port UniCurses but your implementation has to handle this switch if necessary.
There are also tools built on top of curses. Four example Urwid.
I personally have some experience with curses and if you have Linux as the underlying system this can be fun if your requirements are robust and simple. Like your menu requirement. I have to say though that the learning curve is pretty steep.
Hope this helps. But given the broad question thus is the only level of detail to provide at this stage.
I think you mean Combobox.
Here is a short example based on this and PyQt:
from PyQt4 import QtGui, QtCore
import sys
class CheckableComboBox(QtGui.QComboBox):
def __init__(self):
super(CheckableComboBox, self).__init__()
self.view().pressed.connect(self.handleItemPressed)
self.setModel(QtGui.QStandardItemModel(self))
def handleItemPressed(self, index):
item = self.model().itemFromIndex(index)
if item.checkState() == QtCore.Qt.Checked:
item.setCheckState(QtCore.Qt.Unchecked)
else:
item.setCheckState(QtCore.Qt.Checked)
class Dialog_01(QtGui.QMainWindow):
def __init__(self):
super(QtGui.QMainWindow,self).__init__()
myQWidget = QtGui.QWidget()
myBoxLayout = QtGui.QVBoxLayout()
myQWidget.setLayout(myBoxLayout)
self.setCentralWidget(myQWidget)
self.toolbutton = QtGui.QToolButton(self)
self.toolbutton.setText('Select Categories ')
self.toolmenu = QtGui.QMenu(self)
for i in range(3):
action = self.toolmenu.addAction("Category " + str(i))
action.setCheckable(True)
self.toolbutton.setMenu(self.toolmenu)
self.toolbutton.setPopupMode(QtGui.QToolButton.InstantPopup)
myBoxLayout.addWidget(self.toolbutton)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
combo = Dialog_01()
combo.show()
combo.resize(480,320)
sys.exit(app.exec_())

Overriding/Reimplementing Slots in PySide

I have almost the exact same question as the one found here:
Override shouldInterruptJavaScript in QWebPage with PySide
In my case though I want to override the copy and paste slots on QLineEdit
import sys
from PySide import QtGui, QtCore
class myLineEdit(QtGui.QLineEdit):
# FIXME: This is not working, the slot is not overriden!
#QtCore.Slot()
def copy(self):
print 'overridden copy event'
App.clipboard().setText('customized text')
return False
#QtCore.Slot()
def paste(self):
print 'overridden paste event'
self.setText('customized text')
return False
if __name__ == "__main__":
App = QtGui.QApplication(sys.argv)
Widget = myLineEdit()
Widget.show()
cmenu = Widget.createStandardContextMenu()
sys.exit(App.exec_())
I'm using Python 2.7.3, with PySide 1.2.2
I don't know if these methods are even supposed to be override-able, but I can't find any documentation that says they shouldn't be.
I also found this page
http://qt-project.org/faq/answer/is_it_possible_to_reimplement_non-virtual_slots
The page explains how certain kinds of slots get pointers set to them by functions that get called when the object is initialized (or something along those lines, I'm not as familiar with the C++).
Following this logic I added the createStandardContextMenu() call above in the hopes that it would reinitialize the slots for at least the context menu, but no luck.
Am I doing something wrong? Or should I try filing a bug report?
You cannot override QLineEdit.copy or QLineEdit.paste in such a way that they will be called internally by Qt.
In general, you can only usefully override or reimplement Qt functions that are defined as being virtual. The Qt Docs will always specify whether this is the case, and for QLineEdit, there are no public slots that are defined in that way.
There is also no easy workaround. There are a lot of different ways in which copy and paste operations (or their equivalents) can be invoked, such as keyboard shortcuts, context menu, drag and drop, etc. It can be done: but it's a lot of work to get complete control over all these sorts of operations. So you need to think carefully about what you're trying to achieve before deciding how to proceed.

How to tweak my tooltips in wxpython?

I was trying to add a tooltip to show the full content of a truncated ObjectListView, until it turned out it had such a feature built-in:
I tried making my own tool tips using wx.TipWindow, wx.PopupWindow and SuperToolTip, but none of them looked as 'native' as this one.
While I'm aware of this wiki article that supposedly enables the tooltip for truncated wx.Listrctrls, I didn't really understand how to get it working. I also expect that it only works when something is truncated, whereas I'd like to be able to use it to display some more information.
I guess the SuperToolTip comes close, but when you remove the 'header' it leaves it with empty space at the top, rather than centering the text in the middle of the tooltip and making it fit.
I tried looking through the source code of ObjectListView, SuperToolTip and wxpython to try and find how tooltips are being created, but I can't really find the low level parts that make it happen.
So how can I tweak tooltips so they look more like native tooltips?
The code to generate my current popups was:
text = "I'm a popup"
class PopUp(wx.TipWindow):
def __init__(self, parent, text):
wx.TipWindow.__init__(self, parent, text)
class PopUp2(wx.PopupWindow):
def __init__(self, parent, text):
wx.PopupWindow.__init__(self, parent)
st = wx.StaticText(self, parent, text)
# Import `from agw import supertooltip as STT`
popup3 = STT.SuperToolTip(text)
I'm not sure if we have a way to create a native Win7 tooltip yet, as you've seen wx.TipWindow looks like the tooltips from older versions of Windows, so there are probably some newer APIs that we should be using instead. Please create a ticket at trac.wxwidgets.org to find out for sure or to request the change if it's not possible some other way that I'm not thinking of at the moment.
Even if you can't create and pop up a native tooltip from scratch, you can still assign the entire ListCtrl a tooltip when you create it, and then change the text to whatever you want based on the item under the mouse pointer. It doesn't position the tooltip neatly over the list item like ObjectListView does, but I think it still accomplishes what you're asking.
self.lc = wx.ListCtrl(self, style=wx.LC_REPORT)
# ...
self.lc.Bind(wx.EVT_MOTION, self.OnMouseMotion)
def OnMouseMotion(self, evt):
pos = self.lc.ScreenToClient(wx.GetMousePosition())
item_index, flag = self.lc.HitTest(pos)
tip = self.lc.GetToolTip()
if flag == wx.LIST_HITTEST_ONITEMLABEL:
tip.SetTip('Some information about ' + self.lc.GetItemText(item_index))
else:
tip.SetTip('')
evt.Skip()

Categories