In this chapter we will explain how to create an application's main window and how to add actions (explained shortly), menus and toolbars. We will also demonstrate how some common actions, like cut and paste in a QTextEdit, can be performed automatically simply by making the appropriate signals to slots connections. We will build the richedit application to illustrate the necessary techniques.
We begin by creating a project file. Start Qt Designer or if it is already running close any existing project and files. Click File|New Project to invoke the Project Settings dialog. Enter a name for the project, e.g. richedit, and a name for the project file, e.g. richedit.pro. Click OK. If you're unfamiliar with Actions and Action Groups the sidebar provides the necessary introduction; otherwise skip ahead to the section called Designing the Main Window "Designing the Main Window".
We will use the main window wizard to build a main window. The wizard allows us to create actions and a menu bar and toolbar through which the user can invoke the actions. We will also create our own actions, menus and toolbar. We will add some widgets to the toolbar and add a main widget to the main window. Finally we will connect signals to slots to take advantage of Qt's default functionality and minimize our coding.
Click File|New to invoke the New Form dialog, click Mainwindow, then click OK. A new QMainWindow form will be created and the Mainwindow Wizard will pop up.
The Choose available menus and toolbars wizard page appears first. It presents three categories of default actions, File Actions, Edit Actions and Help Actions. For each category you can choose to have Qt Designer create menu items, toolbar buttons and signal/slots connections for the relevant actions. You can always add or delete actions, menu items, toolbar buttons and connections later.
We will accept the defaults for File Actions, i.e. have menu items, toolbar buttons and the relevant connections created. But for the Edit Actions we don't want any connections created since we'll be connecting the actions directly to the QTextEdit we'll create later, so uncheck the Edit Action's Create Slots and Connections checkbox. We won't have any Help Actions on the toolbar so uncheck the Help Action's Toolbar checkbox. Click Next to move on to the next wizard page.
The Setup Toolbar wizard page is used to populate a toolbar with actions from each of the default action categories. The Category combobox is used to select which set of actions you wish to work on. The Actions list box lists the actions available for the current category. The Toolbar listbox lists the toolbar buttons you want to create. The blue left and right arrow buttons are used to move actions into or out of the Toolbar list box. The blue up and down arrow buttons are used to move actions up and down within the Toolbar list box. Note that the '<Separator>' item in the Actions list box may be moved to the Toolbar list box as often as required and will cause a separator to appear in the finished toolbar.
Copy the New, Open and Save Actions to the Toolbar list box. Copy a <Separator> to the Toolbar list box. Change the Category to Edit and copy the Undo, Redo, Cut Copy and Paste actions to the Toolbar list box. Click Next and then click Finish.
If you preview the form (Ctrl+T) the File and Edit menus will be available and you'll be able to drag the toolbar either into an independent window of its own, or to dock it to the left, right, bottom or top of the window. The menus and toolbars are not functional yet but we will rectify this as we progress.
Our application requires more menu items and toolbar buttons than the the defaults we created with the main window wizard. But before we create the menu items and toolbar buttons we will create the actions that they'll invoke. The Action Editor appears automatically when you create a main window. You can also access it through the Window menu (click Window|Action Editor).
For the richedit application we need to create actions for indicating bold, italic and underlined font attributes, and to set text alignment.
Right click in the Action Editor where the actions are listed, then left click New Action. This will create a new action called 'Action' at the top of the list of actions. The Property Editor will change to show the default settings for the new action. We'll now go through all the properties we need to change.
Change the name of the action to 'boldAction'.
Since bold can only be on or off change the toggleAction property to True.
The iconSet property is used to set an icon which will appear to the left of the action's name in any menu you associate the action with. The iconSet is also used for the toolbar button if you associate the action with a toolbar. Click the ellipsis button (...) to invoke the Edit Pixmap Collection dialog. The pixmap we require is not in the default collection. Click the Add button and a file dialog will appear. The icons we require are in the Qt examples directory, qt/examples/textedit/. Navigate to the textedit directory and select the textbold.xpm file. Click the new textbold icon in the pixmap collection then click OK.
Change the text property to 'bold'. This automatically changes the menuText, toolTip and statusTip properties.
Change the menu text to '&Bold'. If we choose to associate this action with a menu item then this property is used; otherwise it is ignored.
Change the accel property to 'CTRL+B'. This will associate the Ctrl+B keyboard accelerator with this action.
We need to add two more actions, italic and underline. For each one right click the Action Editor and click New Action. Then repeat the steps listed above to change each action's properties:
For the italic action change its name to 'italicAction' and ensure its toggleAction property is True. The iconSet is in the textedit directory and is called textitalic.xpm; add its pixmap in the same way that we added the bold pixmap. (For example, click the ellipsis (...), click Add, navigate to the textedit directory and click the textitalic.xpm pixmap. Then click the textitalic pixmap in the pixmap collection and click OK). Change the action's text to 'italic', its menuText to '&Italic' and its accel to 'CTRL+I'.
For the underline action change its name to 'underlineAction' and set its toggleAction property to True. The iconSet is in the same directory and is called textunder.xpm; add it in the same way as the previous pixmaps. Change its text to 'underline', its menuText to '&Underline' and its accel to 'CTRL+U'.
It is perfectly possible to have bold, italic and underline all active at once. But for alignment, i.e. left align, right align and centered, it only makes sense for one of them to be active at any one time. Because we need the alignment actions to operate in sync with one another we must create an Action Group which will automatically manage the behaviour of the actions it contains in the way we require.
Right click the Action Editor then left click New Action Group. Change the action group's name in the Property Editor to 'alignActionGroup', and change its text to 'align'. The 'exclusive' property's default is True. This ensures that only one action within the action group can be 'on' at any one time which is the behaviour we require.
We create the actions within the action group in almost the same way as before. The only difference is that we must right click the alignActionGroup (rather than an Action) and then left click New Action to create a new action within the action group. We will create three new actions within the alignActionGroup:
Create a new action within the alignActionGroup action group. Change the name of this action to 'leftAlignAction' and ensure its toggleAction property is True. Use the iconSet in the textedit directory called textleft.xpm, adding the pixmap to the pixmap collection in the same way as we added the textbold pixmap earlier. Change its text to 'left', its menuText to '&Left' and its accel to 'CTRL+L'.
Create another new action within alignActionGroup. Change this action's name to 'rightAlignAction' and set its toggleAction property to True. Set its iconSet to textright.xpm using the pixmap collection as before. Change its text to 'right', its menuText to '&Right' and its accel to 'CTRL+R'.
Create a third action within alignActionGroup. Change its name to 'centerAlignAction' and make its toggleAction property True. Change its iconSet to textcenter.xpm. Change its text to 'center' and its menuText to '&Center'. We won't set an accelerator for this action.
We have some actions that we don't intend providing for this first release, for example, the editFindAction and the filePrintAction. Click editFindAction and then click the Delete Action toolbar button. Delete the filePrintAction in the same way. Action Groups (including any actions they contain) can also be deleted with the Delete Action toolbar button.
All the actions we require are now in place and we are ready to create a new toolbar and add some of our actions to it. Right click on the right hand side of the toolbar area, or on the form, then left click Add Toolbar. The new toolbar is empty and is visible only by its toolbar handle. (Toolbar handle's are usually represented as a gray area containing either two thick vertical lines or with many small pits).
We'll add the new actions we've just created. Drag the alignActionGroup, (not any action it contains), to the new toolbar and drop it on the toolbar handle to the right of the vertical lines. The three alignment actions will be added to the toolbar. The bold, italic and underline actions do not belong to an action group, and must be dragged to the toolbar individually. Drag the bold action to the toolbar: when the mouse is over the toolbar a thick red line will appear indicating the position at which the toolbar button will be inserted; drop the bold action on the toolbar. Drag the italic and underline actions to the toolbar and drop them next to the bold button. Separate the alignment toolbar buttons from the font related buttons by right clicking the centered toolbar button and clicking Insert Separator.
Toolbar buttons and separators (usually represented as indented vertical gray lines), can be dragged and dropped into new positions in the toolbar at any time. Separators can be inserted by right clicking a toolbar button and clicking Insert Separator. Toolbar buttons and separators can be deleted by right clicking them and clicking Delete Item. Toolbars can be deleted by right clicking their toolbar handle and clicking Delete Toolbar.
If you preview the application you'll find that both the original and new toolbar can be dragged to different docking points or dragged out of the application as independent tool windows.
We want our users to be able to choose the font and font size from the toolbar. To achieve this we'll create a font combobox and a font size spinbox and place them in the formatting toolbar we created in the previous section.
Click Qt Designer's ComboBox toolbar button and click the last (right-most) toolbar button in the application's new toolbar. Change the combobox's name to 'fontComboBox'. Click the SpinBox toolbar button and click the combobox we've just added to insert the spinbox next to it. Change the spinbox's minValue property to 6, its value property to 10 and its suffix to a space followed by 'pt'. Insert a separator to the left of the combobox.
Although you can put any widget into a toolbar we recommend that widgets which can be associated with an action should not be added to the toolbar directly. For these widgets, i.e. menu items, toolbar buttons and lists of items, you should create an action (drop down action for a list of items), associate the action with the widget, and add the action to the toolbar. Widgets that can sensibly be inserted directly into a toolbar are ComboBoxes, SpinBoxes and LineEdits.
We'll now add the actions we added to the new toolbar to a new menu and modify the existing menus slightly.
Right click our application's menu bar and click Add Menu Item. A new menu item called 'Menu' will appear. Right click this menu item and click Rename Item. Change its name to 'F&ormat'. Click the menu item and a gray bar will appear beneath it -- this is the empty menu. Drag the alignActionGroup to the Format menu item and drop the action group on the menu. (The menu's gray bar will appear and a thick red line will be drawn where the new menu items will appear -- drop when the red line is in the position you require.) Now if you click the Format menu item the three alignment actions will be displayed. Just like the toolbar we must add the bold, italic and underline actions individually. Drag the bold action to the Format menu and move the mouse so that the red line is positioned at the bottom of the menu, then drop the action. Repeat this process for the italic and underline actions.
We'll now deal with the separators in the menus. Firstly we'll add a separator in the Format menu and then we'll remove some redundant separators from the other menus. Click the Format menu and right click the bold item; click Insert Separator. Click the File menu and right click one of the separators above the Exit action; click Delete Item. Click the Edit menu, right click the separator at the very bottom of the menu and click Delete Item. Delete Item can be used to delete both separators and menu items.
Click the Format menu and drag it to the left of the Help menu, then drop the Format menu. (A thick red bar will appear to indicate the insertion postion.) Both menus and menu items may be dragged and dropped to different positions in the same way.
Preview the application and try clicking the alignment and font style toolbar buttons and menu items. Qt will automatically keep the state of the menu items and the toolbar buttons synchronized.
Our application is a rich text editor, but so far there has been nowhere for the user to edit text. We'll add a QTextEdit widget and use Qt's signals and slots mechanism to minimize the code we have to write to make it functional.
Click Qt Designer's Richtext Editor (Text Edit) toolbar button and click in the center of the form. Click the form, then click the Lay Out Horizontally toolbar button. We're now ready to make the connections we need; but first we will do some renaming to make things easier to understand. Click on the Text Edit widget and change its name property to 'textEdit'. Change the textFormat property to 'RichText'. Change the name of the form to 'EditorForm' and its caption to 'Rich Edit'.
The QTextEdit widget contains built-in functionality for cut and paste and various other editing functions. By connecting the appropriate signals to our textEdit we can take advantage of this functionality without the need to write any code.
Click the underlineAction in the Action Editor, then click the Connect button. The Edit Connections dialog will appear. Click the toggled() signal. Since we wish to connect this signal to the text edit widget drop down the Slots combobox and click textEdit. The text edit's slots that can respond to a toggled signal will appear in the right hand list box. Click the setUnderline() slot, then click OK.
Connect up the bold and italic actions in the same way. (For example, click the bold action and click Connect. Click the toggled() signal, change the Slots combobox item to textEdit and click the setBold() slot. Click OK.) If you preview the form you'll find that you can enter text and that choosing bold, italic or underline will work.
The cut, copy, paste, undo and redo actions are connected in the same way as the font attributes. For example, click the editPasteAction action and click Connect. Click the activated() signal, change the Slots combobox item to textEdit and click the paste() slot. Click OK to save the connection. Connect the cut, copy, undo and redo actions in the same way. (For example, click the editCopyAction action, click Connect, click the activated() signal, change the Slots combobox item to textEdit, click the copy() slot then click OK.) Then the cut, copy, paste, undo and redo actions will all work in preview mode.
We need to create a slot to receive signals from alignment actions and set the textEdit widget's alignment state accordingly. One approach would be to connect each individual alignment action to our slot, but because the align actions are in a group we will connect the alignActionGroup to our slot and determine which alignment the user chose from the QAction pointer that is passed.
Create a new slot with the signature changeAlignment(QAction *align). (Click Edit|Slots, click New Slot, enter the slot's signature and click OK.) Click alignActionGroup in the Action Editor, then click Connect. Connect the selected(QAction*) signal to our change alignment slot, then click OK.
We'll have to write the code to set the alignment ourselves; we'll cover this in the section called Aligning Text "Aligning Text".
We'll start by dealing with font size since it's easiest. Click the Connect Signals/Slots toolbar button then click the spinbox and drag to the text edit widget; release on the text edit. Click the valueChanged(int) signal and on the textEdit's setPointSize(int) slot. Click OK and font sizes are done. (Because font sizes are handled purely through built-in signals and slots they work in preview mode.)
Connect the fontComboBox's activated() signal to the textEdit's setFamily() slot. This connection will handle updating the textEdit's font family with the user's choice. We will have to populate the combobox with font names to choose from in code. (See the init() function in the section called Changing Fonts "Changing Fonts".) It's a good idea to connect the fontComboBox's activate() signal to the textEdit's setFocus() slot; this will ensure that after the user has changed font the focus will return to their text.
The richedit application is nearly complete. We will have to write code to handle text alignment, font and font size, and also file loading and saving. We will also write the code for application exit to deal correctly with any unsaved changes.