tl; dr
The default delegate for all element views is QStyledItemDelegate . Its paint() method calls drawControl() , defined in qcommonstyle.cpp , to draw each element. Therefore, check qcommonstyle.cpp for details on how each item is drawn.
Long term response
Those who prefer brevity should read above tl; dr and style documentation in item representations . If you're still stuck (and probably many Python users will), the rest of this answer should help.
I. The default delegate is QStyledItemDelegate
QStyledItemDelegate is the default delegate for items in views. This is clearly stated in the Qt Model / View Programming Overview :
Since Qt 4.4, the default delegate implementation is provided by QStyledItemDelegate, and this is used as the default delegate by Qt standard views.
docs for QStyledItemDelegate provide more details:
When displaying data from models in the representations of Qt elements, for example, QTableView, individual items are typed by a delegate. In addition, when an item is edited, it provides an editor widget that is placed on top of the item’s view during editing. QStyledItemDelegate is the default delegate for all representations of Qt elements and is installed on them when they are created.
In general, if you want to understand the basic mechanics of any of the element views (not just the tree view, but tables and lists too), check out QStyledItemDelegate .
The paint() method in qstyleditemdleegate.cpp is defined on line 419 of the doxygenated code base . Let's look at the last two lines:
QStyle *style = widget ? widget->style() : QApplication::style(); style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, widget);
Two things happen here. Firstly, the style is set - usually before QApplication.style() . Secondly, this style drawControl() method is called to draw an object. And so it is. This is literally the last line of QStyledItemDelegate.paint() !
Therefore, if you really want to understand how the delegate draws things by default, we really need to learn the style that does all the real work. This is what we will do in the rest of this document.
II. QStyle: what gives the delegate his own style?
When something is displayed using Qt, it is drawn according to some style that was selected using the system when you created the QApplication instance. From the docs for QStyle :
The QStyle class is an abstract base class that encapsulates the look and feel of a GUI. Qt contains a set of QStyle subclasses that emulate the styles of various platforms supported by Qt (QWindowsStyle, QMacStyle, QMotifStyle, etc.). By default, these styles are built into the QtGui library.
In Qt, you will find the source code for style N in src/gui/styles/N.cpp .
Each style contains the implementation of elementary operations used to draw everything in a graphical interface, from tree views to drop-down menus. Standard styles, such as QWindowsStyle , inherit most of their methods from QCommonStyle . Each particular style usually includes minor deviations from this common base. Consequently, a close study of qcommonstyle.cpp will reveal basic functionality that Qt developers find useful in drawing all parts of the GUI. Its value is difficult to overestimate.
In the future, we will consider the details related to drawing survey elements.
III. QStyle.drawControl (): doing endoscopy on a delegate
As mentioned above, an understanding of the basic mechanics of drawing a view requires examining the implementation of drawControl() in qcommonstyle.cpp , an implementation that starts on line 1197. Notice that when I refer to the line number without mentioning the file name, by convention I have in mind qcommonstyle.cpp in the doxigenic code base .
The documentation for QStyle.drawControl () is instructive:
QStyle.drawControl (element, option, artist)
Options:
Draws this element with the options provided by the artist, the options specified by the option .... The parameter parameter is a pointer to QStyleOption and contains all the information needed to draw the desired element.
The caller tells drawControl() what type of element he is trying to draw by passing him the QStyle.ControlElement flag. Controls are higher-level window components that display information to the user: things like check boxes, buttons, and menu items. All controls are listed here:
http://pyqt.sourceforge.net/Docs/PyQt4/qstyle.html#ControlElement-enum
Recall that the control sent when QStyledItemDelegate.paint() was CE_ItemViewItem was CE_ItemViewItem , which is just the element that will be displayed inside the element's view. Inside QCommonStyle.drawControl() the CE_ItemViewItem case starts at line 2153. Let me insert it.
a. subElementRect (): size matters
This is the key to the correct size and location of each element. This is the first thing drawControl() computes. To get this information, it calls subElementRect() (defined on line 2313 and first called on line 2158). For example, we have:
QRect textRect = subElementRect(SE_ItemViewItemText, vopt, widget);
The first argument is the QStyle.SubElement flag, in this case SE_ItemViewItemText . Sub-elements of style are components of controls. Each element in the view has three possible sub-elements: checkbox, icon, and text; obviously, the SE_ItemViewItemText subelement represents the text. All possible subelements are listed here:
http://pyqt.sourceforge.net/Docs/PyQt4/qstyle.html#SubElement-enum
The subElementRect() method contains all cases of enumerating subelements: our case SE_ItemViewItemText begins on line 3015.
Note that subElementRect() returns a QRect that defines a rectangle in the plane using integer precision and can be constructed with four integers (left, top, width, height). For example, r1 = QRect(100, 200, 11, 16) . This indicates for the sub-element its size, as well as the position x, y, where it will be painted in the viewport.
subElementRect() actually calls viewItemLayout() (defined on line 999) to do the real work, which is a two-step process. First, viewItemLayout() calculates the height and width of the viewItemSize() using viewItemSize() . Secondly, it calculates the position of x and y of the subitem. Consider each of these operations in turn.
1. viewItemLayout (): calculating the width and height of the subitems
Starting at line 1003, viewItemLayout() calls viewItemSize() (defined on line 838), which calculates the height and width required for the subitem.
Where viewItemSize() get default numbers for things like title bar height? This is the area of the pixel metric. A pixel metric is a style-dependent size represented by the value of one pixel. For example, Style.PM_IndicatorWidth returns the width of the flag indicator, and QStyle.PM_TitleBarHeight returns the height of the title bar for your application style. All QStyle.PixelMetric are listed QStyle.PixelMetric :
http://pyqt.sourceforge.net/Docs/PyQt4/qstyle.html#PixelMetric-enum
You can get the value of a given pixel metric using QStyle.pixelMetric () , which is used a lot in viewItemSize() . The first input pixelMetric() is one of the QStyle.PixelMetric in the listing. In qcommonstyle.cpp implementation of pixelMetric() starts at line 4367.
For example, viewItemSize() calculates the width and height of the checkbox (if necessary) using the following:
return QSize(proxyStyle->pixelMetric(QStyle::PM_IndicatorWidth, option, widget), proxyStyle->pixelMetric(QStyle::PM_IndicatorHeight, option, widget));
Note that pixelMetric() used not only in viewItemSize() , but everywhere. It is used to calculate the metric properties of many GUI elements, from window borders to icons, and is applied to all qcommonstyle.cpp . Basically, whenever you need to know how many pixels your style uses for a graphic element that does not change its size (for example, a check box), the style will call pixel measures.
2. viewItemLayout (): Rubik Cube subelements for getting x / y positions
The second part of viewItemLayout() devoted to organizing the layout of sub-elements whose width and height were calculated. That is, he needs to find his x and y positions to finish filling in the values in QRect , for example textRect . Subelements will be organized differently depending on the general view settings (for example, whether they are oriented from right or left to right). Therefore, viewItemLayout() calculates the final resting position of each subitem depending on such factors.
If you ever need a hint on how to override sizeHint() in a user deletion, subElementRect() can be a useful source of tips and tricks. In particular, viewItemSize() probably contains useful tidbits and corresponding pixel metrics, which you might want to request if you want the custom view to be close to the standard.
After calculating the QRect for the subtrees of the text, icon, and checkbox, drawControl() moves and finally starts drawing.
B. Background color: getting primitive
First, the background is filled for the element (line 2163):
drawPrimitive(PE_PanelItemViewItem, option, painter);
This is very similar to calling QStyle.drawControl() , but the first argument is not a control, but a primitive (PE). Just like drawControl() is a great stretch method that controls the drawing of all higher-level QStyle.drawPrimitive() , QStyle.drawPrimitive() draws most primitive lower-level graphic elements in the graphical interface (for example, a rectangular background in the element view). These lower-level units, primitive elements, are listed here:
http://pyqt.sourceforge.net/Docs/PyQt4/qstyle.html#PrimitiveElement-enum
The docs say: “A primitive element is a common GUI element, such as an indicator or a bevel button. For example, the primitive PE_PanelItemViewItem element represents“ [T] background for the element in the element view. ”
Each style must have an implementation of drawPrimitive() , and ours starts at line 140. Here you can learn in great detail how it performs primitive operations with paint. This is a useful source of tips on how to use the paint() command in practice in your user delegates.
The reimplementation of QStyle.drawPrimitive() for the case PE_PanelItemViewItem begins at line 773. First, the appropriate background color is selected depending on the state of the element. He does this by querying the QStyle.StateFlag element. option.state contains state flags that describe the state of the element at the time (is it allowed, selected, edited, etc.?). These states are not only used in the back, but you will probably have to use it when overriding QStyledItemDelegate.paint() in user delegates. You can find the QStyle.StateFlag here:
http://pyqt.sourceforge.net/Docs/PyQt4/qstyle.html#StateFlag-enum
After selecting the desired color, drawPrimitive() then uses QPainter.fillRect() to fill the corresponding area with this color (line 786):
p->fillRect(vopt->rect, vopt->backgroundBrush);
QPainter.fillRect() is a very useful method when implementing custom delegates for yourself.
After leaving the background, drawControl() then finish drawing the element, starting with the checkbox (line 2165), then the icon (line 2185), and finally the text (line 2194). We will not dwell on this in detail, but I will end by briefly discussing how he draws the text.
C. Text Drawing: Apostate Transition
First, the state of an element is used to indicate the color of the text. This uses only the discussed QStyle.StateFlags . Then drawControl() discards the responsibility of drawing text to the user- viewItemDrawText() method (defined on line 921):
viewItemDrawText(painter, vopt, textRect);
This method takes as parameters the artist, parameter, and rectangle of the text described above (Part A). Note that the parameter parameter is very important: this is the QStyleOption class, by which the content is passed inside the style (it includes the icon properties, checkstate and text).
After pulling the text from the option, it is included in the QtGui.QTextLine , which is added to QtGui.QTextLayout . The final deviation (i.e. with ellipses, depending on the word wrap options) is drawn by QPainter.drawText() (see Line 983), which is one of the primitive Qt drawing operations.
Honestly, a large amount of viewItemDrawText() spent on word wrapping. This is where we begin to go into some of the Qt whales that no Python user has ever intended to see, much less mess with. For example, it uses the QStackTextEngine class. I recommend Google's “qstacktextengine pyqt” to find out how rare this has been for Python users. If this interests you, have it!
IV. Summary
If you want to access the basic drawing mechanics for the default delegate, you will eventually learn the implementation of QStyle.drawControl() in qcommonstyle.cpp , a 6000-line file beast. This exercise can be very useful for figuring out the exact procedures used to calculate dimensions, and for drawing primitive graphic elements that contain elements. Sometimes, however, this beast can be completely frightening and useless, for example, when it comes to wrapping words. In these cases, you may just have to figure out a custom implementation of the desired functions for your delegate.
Finally, now that we have seen the idea of how everything works, we can better understand how useful the documentation for QStyle will be, in particular the Styles section in element views . There we find the following frank love nugget:
Painting objects in the eyes is done by the delegate. The default Qts delegate, QStyledItemDelegate , is also used to compute the bounding rectangles of elements (and their subelements) ... When QStyledItemDelegate draws its objects, draws CE_ItemViewItems ... When implementing the style to customize the drawing of elements, you need to check the implementation of QCommonStyle (and any other subclasses from which your style is inherited). This way you will know which and how other style elements are already colored, and you can then redefine the color of the elements, which must be done differently.
So, basically the answer to the original post: "What did they say."