12

I am having troubles to display the icon of a QAction selected from the current icon theme. I made the ui with Qt designer and exported it with pyuic4 sample.ui > sample.py. After setting the icon from the theme with self.actionSample.setIcon(QtGui.QIcon.fromTheme(_fromUtf8("document-open"))), I get the following source code :

from PyQt4 import QtCore, QtGui
import sys

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    _fromUtf8 = lambda s: s

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(800, 600)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtGui.QStatusBar(MainWindow)
        self.statusbar.setObjectName(_fromUtf8("statusbar"))
        MainWindow.setStatusBar(self.statusbar)
        self.toolBar = QtGui.QToolBar(MainWindow)
        self.toolBar.setObjectName(_fromUtf8("toolBar"))
        MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar)
        self.actionSample = QtGui.QAction(MainWindow)
        self.actionSample.setObjectName(_fromUtf8("actionSample"))
        self.actionSample.setIcon(QtGui.QIcon.fromTheme(_fromUtf8("document-open")))
        self.toolBar.addAction(self.actionSample)

        QtCore.QMetaObject.connectSlotsByName(MainWindow)

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    window = QtGui.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(window)
    window.show()
    app.exec_()

When I execute it, the toolbar does not display the icon 'document-open'. Is it a bug or am I doing something wrong ?

Thanks

ekhumoro
  • 115,249
  • 20
  • 229
  • 336
Hypergraphe
  • 153
  • 1
  • 1
  • 6
  • 1
    What plaform are you on, and what version of Qt are you using? Also, did you set the icon in Designer, or add it yourself manually? – ekhumoro Oct 09 '12 at 21:12
  • @ekhumoro I am running : Gnu/Linux 3.2.0-2-686 - Debian Testing / Python 2.7.3rc2 / python-qt4 4.9.3-4 / I set up the icon manually after generating the `.py` file. But when I generate it with qt-designer it is the same. – Hypergraphe Oct 09 '12 at 21:55
  • The New Action dialog in the Action Editor should show the icon next to the "Icon theme" property if it's available. – ekhumoro Oct 09 '12 at 23:19
  • When I open the Action Editor, I have "document-open" written in the "Icon Theme" text edit. But I don't see any icon. – Hypergraphe Oct 10 '12 at 11:05

2 Answers2

15

The icon lookup process used by QIcon.fromTheme is somewhat complex.

Icon themes are only directly supported on the X11 platform for the GNOME and KDE desktop environments. For other platforms/desktops, it will be necessary to either install a theme along with the application, or tweak the user's environment in various ways.

To find the current system theme for GNOME, Qt will query gconf (if the gtk style is available), and otherwise default to the "gnome" theme. For KDE, Qt will examine the kdeglobals settings file(s), and otherwise default to "oxygen" (or "crystalsvg" for earlier versions of KDE). In addition, the "hicolor" theme can always be used as a fallback.

Once the system theme name has been determined, Qt will look for the directory containing the icons in various pre-determined places, which again depend on both the platform and desktop being used. On X11, this includes $HOME/.icons and $XDG_DATA_DIRS/icons. The only location common to all platforms/desktops is the resource path :/icons.

Icon theme directories must include an index.theme file, which (amongst other things) specifies the subdirectories that can contain icons. Only icon files with a png or svg extension are used.

The QIcon class has some static methods which will show exactly where Qt is looking for themed icons:

>>> from PyQt4 import QtGui
>>> app = QtGui.QApplication([])
>>> for path in QtGui.QIcon.themeSearchPaths():
...     print "%s/%s" % (path, QtGui.QIcon.themeName())
... 
/home/ekhumoro/.icons/hicolor
/usr/local/share/icons/hicolor
/usr/share/icons/hicolor
:/icons/hicolor

If the "document-open" icon isn't being displayed, Qt is either looking in the "wrong" place, or the icon is missing altogether.

UPDATE:

As I said above: by default, Qt only supports GNOME and KDE on the X11 platform. It doesn't know anything about FluxBox WM, and so cannot detect the current icon theme. This means it will fall back to using a minimal "hicolor" theme, which may not have all the required icons.

One way to solve this issue, is to create a "hicolor" symlink that points to the theme you want to use. Ideally, this should go in the location that is first in Qt's list of search paths:

$ ln -s icon/theme/directory $HOME/.icons/hicolor

UPDATE 2:

Qt5 still only supports kde and gnome by default, but the Qt Platform Abstraction layer at least makes it possible to create custom theme plugins (LXQT is one desktop environment that takes advantage of this). There are also several more DE's that are now treated as gtk/gnome: X-CINNAMON, UNITY, MATE, XFCE and LXDE.

ekhumoro
  • 115,249
  • 20
  • 229
  • 336
  • 1
    I am running FluxBox WM. When I execute the fragment of code above, I get : `/home/ben/.icons/hicolor /usr/local/share/icons/hicolor /usr/share/icons/hicolor :/icons/hicolor` Icons are located in `/usr/share/icons/hicolor` along with the index.theme so it should work right ? – Hypergraphe Oct 11 '12 at 10:22
  • 1
    Ok, I changed the theme with the `setThemeName` static method to one in my `.icons` and it worked well. Any Idea why PyQt does not look into the other search paths ? – Hypergraphe Oct 11 '12 at 10:31
1

Provided that self points to something QWidget-like you can use this ugly hack:

openIcon = self.style().standardIcon(QStyle.StandardPixmap.SP_FileDialogStart)
openAction(openIcon, 'Open', self)

Or, you can also access .style() on a QApplication instance, i.e. icon = app.style().standardIcon(...).

ccpizza
  • 28,968
  • 18
  • 162
  • 169