Extension Dialogs

There is another approach that we can take for complex dialogs: extension dialogs. These are typically used for cases where the dialog has "simple" and "advanced" options. Initially the dialog is shown with the simple options, but a toggle button is provided to show or hide the advanced options.

The extension dialog shown in Figure 9.3 shows the extra checkboxes when the More toggle button is depressed. Any QPushButton can be made into a toggle button by calling setCheckable(True) on it, or by setting its "checkable" property to True in Qt Designer.

Pyqt Noframe
Figure 9.3 An extension dialog

To make the extension dialog work we have used two "tricks". The first trick is to put all the advanced options' widgets inside a QFrame. This means that we need to hide and show only the frame, since PyQt will automatically hide and show all the widgets inside the frame to reflect the frame's state of visibility. If we don't want the user to see the frame's outline when it is visible, we can simply set its "frameShape" property to QFrame.NoFrame.

The second trick is to make the dialog a fixed size. This will ensure that the dialog shrinks as small as possible (while keeping its margins), and takes account of the dialog's visible contents. The effect of this is to make the dialog short when the advanced options are hidden, and tall enough to show the advanced options when they are visible. We must also hide the frame when the dialog is created. Here is the code for the dialog's initializer (from chap09/findandreplacedlg.py):

class FindAndReplaceDlg(QDialog, ui_findandreplacedlg.Ui_FindAndReplaceDlg):

def_init_(self, parent=None):

super(FindAndReplaceDlg, self).__init__(parent)

self.setupUi(self)

self.moreFrame.hide()

self.layout().setSizeConstraint(QLayout.SetFixedSize)

But how do we relate the More button to the shown/hidden state of the frame? Simply by connecting the moreButton's toggled(bool) signal to the moreFrame's setVisible(bool) slot. Note that if this connection is made in Qt Designer, we must check the Configure Connection dialog's "Show all signals and slots" checkbox; otherwise, the setVisible() slot will not appear.

For this section's final example, we will again look at how to achieve the layout in code. Unlike the previous two layouts which showed the use of new widgets (QTabWidget and QStackedWidget), this dialog's layout uses only widgets we have seen before—but does so in new ways. The following extracts are from the Find-

AndReplaceDlg class's initializer in chap09/findandreplacedlg.pyw. (The Qt Designer version is in the files findandreplacedlg.ui and findandreplacedlg.py.)

We will only show the creation of the form's widgets that are specifically relevant to extension dialogs. The form's layout is shown in Figure 9.4.

moreFrame = QFrame()

moreFrame.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken)

We create a frame in which we will put the extra checkboxes. If we didn't do the setFrameStyle() call, the frame would have no outline.

line.setFrameStyle(QFrame.VLine|QFrame.Sunken)

The line that we "draw" to visually separate the dialog's main widgets on the left from the buttons on the right is also a frame. Horizontal lines can be created by using a frame style of QFrame.HLine.

moreButton = QPushButton("&More") moreButton.setCheckable(True)

The More button is different from other buttons in one respect: It is checkable. This means that it acts like a toggle button, staying down when clicked the first time, then coming up when clicked the next time, and so on.

Figure 9.4 The Find and Replace dialog's layout

The labels and line edits are laid out in a grid; we will not show the code since we have seen this kind of layout many times before.

frameLayout = QVBoxLayout()

frameLayout.addWidget(self.backwardsCheckBox)

frameLayout.addWidget(self.regexCheckBox)

frameLayout.addWidget(self.ignoreNotesCheckBox)

moreFrame.setLayout(frameLayout)

We want the extra checkboxes to be laid out inside the more frame. To do this we create a layout, in this case a vertical box layout, and add the checkboxes to it. Then we set the layout on the frame. In previous examples, we have added layouts to layouts to achieve nesting, but here we nest by adding a layout to a frame. So in addition to being able to nest layouts inside one another, we can also nest frames and group boxes inside layouts, which gives us a great deal of flexibility.

leftLayout = QVBoxLayout()

leftLayout.addLayout(gridLayout)

leftLayout.addWidget(self.caseCheckBox)

leftLayout.addWidget(self.wholeCheckBox)

leftLayout.addWidget(moreFrame)

The left layout is a vertical box layout to which we add the grid layout (with the labels and line edits), the case sensitivity and whole words checkboxes, and then the more frame (that contains the extra checkboxes in a vertical box layout).

buttonLayout = QVBoxLayout()

buttonLayout.addWidget(self.findButton)

buttonLayout.addWidget(self.replaceButton)

buttonLayout.addWidget(closeButton)

buttonLayout.addWidget(moreButton)

buttonLayout.addStretch()

The button layout is very similar to ones we have seen before, only this time it is using a vertical box layout rather than a horizontal box layout.

mainLayout = QHBoxLayout()

mainLayout.addLayout(leftLayout)

mainLayout.addWidget(line)

mainLayout.addLayout(buttonLayout)

self.setLayout(mainLayout)

The dialog's main layout is a horizontal box layout, with the left layout on the left, then the dividing line, and then the button layout. The line will grow and shrink vertically according to whether the more frame is visible (and therefore whether the dialog is tall or short).

moreFrame.hide()

mainLayout.setSizeConstraint(QLayout.SetFixedSize)

We initially hide the more frame (and therefore the widgets it contains), and we use the set fixed size trick to ensure that the dialog resizes itself according to whether the more frame is visible.

self.connect(moreButton, SIGNAL("toggled(bool)"), moreFrame, SLOT("setVisible(bool)"))

The last thing we must do is connect the More button's toggled() signal to the more frame's setVisible() slot. When the frame is hidden (or shown), it will in turn hide (or show) all the widgets laid out inside it, because when show() or hide() is called on a widget, PyQt automatically propagates these calls to all the widget's children.

We have noted that there are two versions of each dialog shown in this section. One version is written entirely in code, for example, paymentdlg.pyw—and the other version has a Qt Designer user interface, with code in a module file—for example, paymentdlg.ui and paymentdlg.py. By comparing the "all in code" (.pyw) versions with the Qt Designer and module versions (.py), we can see clearly how much code writing we can avoid by using Qt Designer. An additional benefit of using Qt Designer, especially for complex widgets, is that it makes changing the design much easier than is the case when we do things manually.

ite widgets

Was this article helpful?

0 0
Tube Jacker

Tube Jacker

Download Tube Jacker And Discover Everything You Need To Know About Jacking Unlimited Traffic From The Video Giant. The drop dead easy way to create winning video campaigns that will FLOOD your website with unstoppable FREE traffic, all on complete and total autopilot. How to exploit a sneaky method of boosting exposure and getting your videos to the top of Google within 72 hours, guaranteed.

Get My Free Ebook


Post a comment