Some main-window-style applications need to use more than one widget in their central area. Two common types of applications that need to do this are email clients and network news readers. There are three approaches we can take to handle this. One is to create a composite widget, that is, a widget that Compos is composed of other widgets (created and laid out like a dialog, but inheriting from QWidget instead of QDialog), and use this widget as the main window's central widget. Another approach is to have just one central widget and put the other widgets inside dock windows—we have already seen this in Chapter 6. The third approach is to use splitters, the topic of this section.

Figure 9.5 shows a mock-up of a news reader application, and Figure 9.6 illustrates the relationship between the form's splitters and widgets. Splitters are fully supported by Qt Designer, and are used in much the same way as vertical and horizontal box layouts: We select two or more widgets, and click Form^Lay Out Horizontally in Splitter or Form^Lay Out Vertically in Splitter.

In this section we will show how to create splitters in code, including how to save and restore their relative positions. We will begin by looking at the relevant parts of the News Reader mock-up's initializer.

class MainWindow(QMainWindow):

def_init_(self, parent=None):

super(MainWindow, self)._init_(parent)

self.groupsList = QListWidget() self.messagesList = QListWidget() self.messageView = QTextBrowser()

The initializer begins conventionally with the call to super(). The next three lines are slightly unusual, since although this is a main window, we have created three widgets instead of just one.

Figure 9.5 The News Reader application mock-up

self.messageSplitter = QSplitter(Qt.Vertical)



self.mainSplitter = QSplitter(Qt.Horizontal)




We now create two splitters. The first is the messageSplitter; this holds the message list and message view widgets vertically, one above the other. The second splitter, mainSplitter, splits horizontally, with the group list widget on its left and the message splitter on its right. Like box layouts, splitters can hold more than two widgets, in which case they place a splitter in between each pair of widgets. The main splitter holds one widget and the other splitter, which in turn holds the other two widgets. So the main splitter ultimately holds everything else, and since splitters are widgets (unlike box layouts, which are layouts), a splitter can be added as a main window's central widget, as we have done here.

Some users find splitters annoying because they can resize them only by using the mouse. We will minimize this annoyance by saving and restoring the user's splitter sizes. This is helpful since the user can simply set the sizes once, and from then on the sizes they set will be honored.

Figure 9.6 The News Reader's splitters and widgets

settings = QSettings()

size = settings.value("MainWindow/Size",

QVariant(QSize(600, 500))).toSize()


position = settings.value("MainWindow/Position",

self.move(position) self.restoreState(

settings.value("MainWindow/State").toByteArray()) self.messageSplitter.restoreState(

settings.value("MessageSplitter").toByteArrayO) self.mainSplitter.restoreState(


Saving the user's main window settings begins with some familiar code for restoring the window's size and position and the state of any toolbars and dock windows it may have. Splitters too have a state, and this is restored and saved in the same way as the main window's state.

def closeEvent(self, event): if self.okToContinue(): settings = QSettings()

settings.setValue("MainWindow/Size", QVariant(self.size())) settings.setValue("MainWindow/Position",

QVariant(self.pos())) settings.setValue("MainWindow/State",

QVariant(self.saveState())) settings.setValue("MessageSplitter",

QVariant(self.messageSplitter.saveStateO)) settings.setValue("MainSplitter",




In the main window's close event, again the code begins in a familiar way, only we now save the state of the splitters in addition to the main window's size, position, and state.

When the News Reader application is run for the very first time, by default the main splitter gives exactly half its width to the group list widget, and half to the message splitter. Similarly, the message splitter gives half its height to the message list widget and half to the message view widget. We want to change these proportions, making the group list narrower and the message viewer taller, and we can do so by applying stretch factors. For example:

self.mainSplitter,setStretchFactor(0, 1) self.mainSplitter.setStretchFactor(1, 3) self.messageSplitter,setStretchFactor(0, 1) self.messageSplitter.setStretchFactor(1, 2)

The first argument to setStretchFactor() is the 0-based index position of the widget (from left to right, or from top to bottom), and the second argument is the stretch factor to be applied. In this case, we have said that the zero-th widget (the group list widget) should have a stretch factor of 1 and the first widget (the message splitter) should have a stretch factor of 3, thus dividing the horizontal space in a proportion of 1:3. Similarly, for the message splitter we split the vertical space in a proportion of 1:2 in favor of the message view widget. Since we save and restore the splitters' sizes, the stretch factors have an effect only the first time the application is run.

Was this article helpful?

+2 0
Tube Traffic Ninja

Tube Traffic Ninja

Discover How You Can Quickly And Easily Dominate Google and YouTube... With Simple Cash Generating Videos. Did you know that YouTube is the second largest search website on the entire Internet? YouTube gets more daily searches than Bing and Yahoo. In fact, there is only one search engine that gets more action.

Get My Free Ebook

Post a comment