Lab -- User Interface Elements

This lab will build off of what you did before. You will use the QT designer to layout and design a user interface. Since this involves, once again, using what is most likely a new tool for several of you, we will provide fairly detailed instructions.

Summary

For those of you who just want to know the bottom line, we'll give that first:

Designer

Your installation of QT should come with the QT designer. The executable is in the QT "bin" directory which is most likely part of your path. The Windows installation also gives you a shortcut in the start menu. When you first run the designer, you are offered a handful of templates to choose from. Use the Main Window option.
You'll then be presented with an empty "canvas" surrounded by several different dialogs. It's a bit cluttered. We recommend getting rid of the "Action Editor", "Signal/Slot Editor", and "Resource Editor". You don't really need them for this project. You definitely need the "Property Editor" and the "Object Inspector" might come in handy too. The menu bar in the application window has a "Tools" menu that lets you get them back if you close them.
Laying things out and configuring your interface is a little weird at first, but not too hard to learn. The application window has a big list of widgets to choose from. You drag these onto your canvas where you want them. You then organize them using the different layouts and give them a name and set other properties using the "Property Editor". Exceptions are the MenuBar and your GLWidget. We'll discuss those first.

MenuBar

The MenuBar is easy, but configuring it is a little bit broken in the designer (version 4.x is still a work in progress). You can still do everything you need to. At the top of your "canvas" you'll see a gray box that says, "Type Here". Click on it and type "&File" (the ampersand lets you access the menu item with the Alt+F combination). Once you have done that, you can click on the and add sub-menu items the same way. When you first create the item, its properties will appear in the "Property Editor" window. However, once you click on something else, clicking on the menu item does not show its properties any more. You can still edit the properties by selecting the item through the "Object Inspector". One reason to edit the menu-item properties is to set the object name. If you create an item named "E&xit", it will be name actionE_xit. That's annoying. Select it and remove the underscore from the objectName field or name it something else.

GLWidget

You'll quickly notice that there is no option for placing a GLWidget on the canvas, especially not your GLWidget. You can actually create a plug-in for the designer that will put your Custom Widget into the designer menu. For this lab, that's more trouble than it's worth. Instead, drag a Frame onto your canvas. Right click on it and select "Promote to Custom Widget". Fill out the appropriate values. Unfortunately, the QGLWidget does not inherit from QFrame. So you need to make sure the designer doesn't try to set any QFrame specific values. Specifically, if you look at the "Property Editor", you'll see that frameShape and frameShadow are both bolded. That means the value is not the default value. Select both and click the little red arrow on the side to make the value revert to default (NoFrame and Plain).

Other widgets

Drag and drop the necessary widgets onto your canvas. QLabels are nice for labeling your widgets.

Layouts

There are three kinds of layouts: Horizontal, Vertical, and Grid (there are also Splitters which are sort of like Layouts). The difference is obvious. You can either drag layouts onto the canvas and then drag other widgets into them, or you can select a number of widgets and then click the appropriate layout button. You need to have your widgets in layouts to make sure that the right things happen when you resize the window or other events happen. Use layouts liberally. Use spacers to keep your widgets from cramping together or spreading about too much. The provided example image is not, by any means, ideal, but it more or less gives a visual summary of what you need.
Create a new directory for this lab and save the .ui file to it.

Using your New Interface

Assuming you didn't rename the files from the example code we used in the last lab, copy main.cpp, glwidget.h, and glwidget.cpp over to your new directory. Now you need to create a class that will use the object layout you created with the designer. There are a few ways. You could learn a lot about it in the on-line documentation. Because it can be a hassle, however, here's code for the most common:

MainWindow.h file
#ifndef __MAINWINDOW_H
#define __MAINWINDOW_H

//This file will be generated automatically,
//assuming you didn't change the objectName of
//your main form in the designer.
#include "ui_MainWindow.h"  
class MainWindow : public QMainWindow
{
  Q_OBJECT
public:
  MainWindow(QWidget *parent = 0);
public:
  Ui::MainWindow ui;
};
#endif
MainWindow.cpp file
#include "MainWindow.h"

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
  ui.setupUi(this);
  //Connect the SIGNALS and SLOTS here
}
You'll have to change main.cpp to #include and instantiate your MainWindow class instead of Window. I think you can handle that. With these six files (3 .cpp, 2 .h, and a .ui in a pear tree) you should be able to get your code to compile:
qmake -project QT+=opengl -o myProject.pro
qmake myProject.pro
make

Event Handling

Generally, programs handle events with interupts which generate messages that are then processed by a message loop. QT does that too, but it is mostly abstracted away with SIGNALS and SLOTS. You should have already learned about that during the last lab while you were dutifully going through the tutorials. After the exectuing the ui.setupUi function, the ui member of your MainWindow class provides access to all the variables you created with the designer. For example, if you created a menu item and set its objectName to "actionExit" and wanted to make clicking on that menu item close the program, you would use:
connect( ui.actionExit,SIGNAL(triggered(bool)),this,SLOT(close()) );
You'll need to create slots and connect them to signals as appropriate to complete the requirements. Mouse-events are handled with a callback instead of a SLOT, but you should already have one functional from the sample code we used. You just need to tweak it so that when you click on the screen, you leave a marker behind. Tie the scroll bars to these markers so that you can move them around. Note that this is probably the hardest part of the lab. We used gluSphere to create markers, but you can use whatever you want. You'll have to use the perspective information and the scroll bars to decide where to draw the markers. Ask questions. Help each other.