From d796c9dd933ab96ec83b9a634feedd5d32e1ba3f Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Tue, 8 Nov 2011 12:31:36 -0600 Subject: Test conversion to TQt3 from Qt3 8c6fc1f8e35fd264dd01c582ca5e7549b32ab731 --- doc/html/tutorial1-08.html | 297 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 297 insertions(+) create mode 100644 doc/html/tutorial1-08.html (limited to 'doc/html/tutorial1-08.html') diff --git a/doc/html/tutorial1-08.html b/doc/html/tutorial1-08.html new file mode 100644 index 000000000..afb3e3390 --- /dev/null +++ b/doc/html/tutorial1-08.html @@ -0,0 +1,297 @@ + + + + + +TQt Tutorial - Chapter 8: Preparing for Battle + + + + + + + +
+ +Home + | +All Classes + | +Main Classes + | +Annotated + | +Grouped Classes + | +Functions +

TQt Tutorial - Chapter 8: Preparing for Battle

+ + +

Screenshot of tutorial eight
+

In this example, we introduce the first custom widget that can paint +itself. We also add a useful keyboard interface (with two lines of +code). +

+

Line-by-line Walkthrough +

+

t8/lcdrange.h +

+

This file is very similar to the lcdrange.h in Chapter 7. We have added +one slot: setRange(). +

+ +

        void setRange( int minVal, int maxVal );
+
+

We now add the possibility of setting the range of the LCDRange. +Until now, it has been fixed at 0..99. +

t8/lcdrange.cpp +

+

+ +

There is a change to the constructor (we'll discuss that later). +

    void LCDRange::setRange( int minVal, int maxVal )
+    {
+        if ( minVal < 0 || maxVal > 99 || minVal > maxVal ) {
+          qWarning( "LCDRange::setRange(%d,%d)\n"
+                   "\tRange must be 0..99\n"
+                   "\tand minVal must not be greater than maxVal",
+                   minVal, maxVal );
+          return;
+        }
+        slider->setRange( minVal, maxVal );
+    }
+
+

SetRange() sets the range of the slider in the LCDRange. Because we +have set up the TQLCDNumber to always display two digits, we want to +limit the possible range of minVal and maxVal to 0..99 to avoid +overflow of the TQLCDNumber. (We could have allowed values down to -9 +but chose not to.) If the arguments are illegal, we use TQt's +qWarning() function to issue a warning to the user and return +immediately. qWarning() is a printf-like function that by default +sends its output to stderr. If you want, you can install your own handler +function using ::qInstallMsgHandler(). +

t8/cannon.h +

+

CannonField is a new custom widget that knows how to display itself. +

+ +

    class CannonField : public TQWidget
+    {
+        Q_OBJECT
+    public:
+        CannonField( TQWidget *parent=0, const char *name=0 );
+
+

CannonField inherits TQWidget, and we use the same idiom as for LCDRange. +

        int angle() const { return ang; }
+        TQSizePolicy sizePolicy() const;
+
+    public slots:
+        void setAngle( int degrees );
+
+    signals:
+        void angleChanged( int );
+
+

For the time being, CannonField only contains an angle value for which we +provide an interface using the same idiom as for value in LCDRange. +

    protected:
+        void paintEvent( TQPaintEvent * );
+
+

This is the second of the many event handlers in TQWidget that we +encounter. This virtual function is called by TQt whenever a widget needs +to update itself (i.e., paint the widget's surface). +

t8/cannon.cpp +

+

+ +

    CannonField::CannonField( TQWidget *parent, const char *name )
+            : TQWidget( parent, name )
+    {
+
+

Again, we use the same idiom as for LCDRange in the previous chapter. +

        ang = 45;
+        setPalette( TQPalette( TQColor( 250, 250, 200) ) );
+    }
+
+

The constructor initializes the angle value to 45 degrees and sets a +custom palette for this widget. +

This palette uses the indicated color as background and picks other +colors suitably. (For this widget only the background and text +colors will actually be used.) +

    void CannonField::setAngle( int degrees )
+    {
+        if ( degrees < 5 )
+            degrees = 5;
+        if ( degrees > 70 )
+            degrees = 70;
+        if ( ang == degrees )
+            return;
+        ang = degrees;
+        repaint();
+        emit angleChanged( ang );
+    }
+
+

This function sets the angle value. We have chosen a legal range of +5..70 and adjust the given number of degrees accordingly. We have +chosen not to issue a warning if the new angle is out of range. +

If the new angle equals the old one, we return immediately. It is +important to only emit the signal angleChanged() when the angle really has changed. +

Then we set the new angle value and repaint our widget. The TQWidget::repaint() function clears the widget (usually filling it with +its background color) and sends a paint event to the widget. This +results in a call to the paint event function of the widget. +

Finally, we emit the angleChanged() signal to tell the outside world +that the angle has changed. The emit keyword is unique to TQt and +not regular C++ syntax. In fact, it is a macro. +

    void CannonField::paintEvent( TQPaintEvent * )
+    {
+        TQString s = "Angle = " + TQString::number( ang );
+        TQPainter p( this );
+        p.drawText( 200, 200, s );
+    }
+
+

This is our first attempt to write a paint event handler. The event +argument contains a description of the paint event. TQPaintEvent +contains the region in the widget that must be updated. For the time +being, we will be lazy and just paint everything. +

Our code displays the angle value in the widget at a fixed position. +First we create a TQString with some text and the angle; then we create +a TQPainter operating on this widget and use it to paint the string. +We'll come back to TQPainter later; it can do a great many things. +

t8/main.cpp +

+

+ +

    #include "cannon.h"
+
+

We include our new class. +

    class MyWidget: public TQWidget
+    {
+    public:
+        MyWidget( TQWidget *parent=0, const char *name=0 );
+    };
+
+

This time we include a single LCDRange and a CannonField in our top-level +widget. +

        LCDRange *angle = new LCDRange( this, "angle" );
+
+

In the constructor, we create and set up our LCDRange. +

        angle->setRange( 5, 70 );
+
+

We set the LCDRange to accept ranges from 5 to 70 degrees. +

        CannonField *cannonField
+            = new CannonField( this, "cannonField" );
+
+

We create our CannonField. +

        connect( angle, SIGNAL(valueChanged(int)),
+                 cannonField, SLOT(setAngle(int)) );
+        connect( cannonField, SIGNAL(angleChanged(int)),
+                 angle, SLOT(setValue(int)) );
+
+

Here we connect the valueChanged() signal of the LCDRange to the +setAngle() slot of the CannonField. This will update CannonField's angle +value whenever the user operates the LCDRange. We also make the reverse +connection so that changing the angle in the CannonField will update the +LCDRange value. In our example we never change the angle of the +CannonField directly; but by doing the last connect() we ensure that no +future changes will disrupt the synchronization between those two values. +

This illustrates the power of component programming and proper +encapsulation. +

Notice how important it is to emit the angleChanged() signal only when +the angle actually changes. If both the LCDRange and the CannonField +had omitted this check, the program would have entered an infinite +loop upon the first change of one of the values. +

        TQGridLayout *grid = new TQGridLayout( this, 2, 2, 10 );
+        //2x2, 10 pixel border
+
+

So far we have used the no-assembly-retquired TQVBox and TQGrid widgets +for geometry management. Now, however, we want to have a little more +control over the layout, and we switch to the more powerful TQGridLayout +class. TQGridLayout isn't a widget; it is a different class that can +manage the children of any widget. +

As the comment indicates, we create a two-by-two array with ten pixel +borders. (The constructor for TQGridLayout can be a little cryptic, +so it's good to put in such comments.) +

        grid->addWidget( tquit, 0, 0 );
+
+

We add the Quit button in the top-left cell of the grid: 0, 0. +

        grid->addWidget( angle, 1, 0, TQt::AlignTop );
+
+

We put the angle LCDRange in the bottom-left cell, aligned to the top +of its cell. (This alignment is one of the things TQGridLayout allows +but TQGrid does not allow.) +

        grid->addWidget( cannonField, 1, 1 );
+
+

We put the CannonField object in the bottom-right cell. (The top- +right cell is empty.) +

        grid->setColStretch( 1, 10 );
+
+

We tell TQGridLayout that the right column (column 1) is stretchable. +Because the left column isn't (it has stretch factor 0, the default +value), TQGridLayout will try to let the left-hand widgets' sizes be +unchanged and will resize just the CannonField when the MyWidget is +resized. +

        angle->setValue( 60 );
+
+

We set an initial angle value. Note that this will trigger the +connection from LCDRange to CannonField. +

        angle->setFocus();
+
+

Our last action is to set angle to have keyboard focus so that +keyboard input will go to the LCDRange widget by default. +

LCDRange does not contain any keyPressEvent(), so that would seem not +to be terribly useful. However, its constructor just got a new line: +

+ +

        setFocusProxy( slider );
+
+

The LCDRange sets the slider to be its focus proxy. That means that +when someone (the program or the user) wants to give the LCDRange +keyboard focus, the slider should take care of it. TQSlider has a decent +keyboard interface, so with just one line of code we've given LCDRange +one. +

Behavior +

+

The keyboard now does something - the arrow keys, Home, End, PageUp +and PageDown all do something vaguely sensible. +

When the slider is operated, the CannonField displays the new angle +value. Upon resizing, CannonField is given as much space as possible. +

On Windows machines with an 8-bit display the new background color is +dithered to death. The next chapter works around this. +

(See Compiling for how to create a +makefile and build the application.) +

Exercises +

+

Try to resize the window. What happens if you make it really narrow +or really squat? +

If you remove the AlignTop, what happens to the LCDRange's position +and size? Why? +

If you give the left-hand column a non-zero stretch factor, what +happens when you resize the window? +

Leave out the setFocus() call. Which behavior do you prefer? +

Try to change "Quit" to "&Quit" in the TQButton::setText() call. How +does the button's look change? What happens if you press Alt+Q while +the program's running? (It is Meta+Q on a few keyboards.) +

Center the text in the CannonField. +

You're now ready for Chapter 9. +

[Previous tutorial] +[Next tutorial] +[Main tutorial page] +

+ +


+ +
Copyright © 2007 +TrolltechTrademarks +
TQt 3.3.8
+
+ -- cgit v1.2.3