W tym przykładzie rozszerzymy klasę LCDRange tak aby zawierała etykietę. Dodamy też coś do czego można strzelić.
class QLabel;Nazwiemy zadeklarowanąQLabel ponieważ chcemy użyć wskaźnika do niej w definicji klasy.
class LCDRange : public QVBox { Q_OBJECT public: LCDRange( QWidget *parent=0, const char *name=0 ); LCDRange( const char *s, QWidget *parent=0, const char *name=0 );Dodaliśmy nowy konstruktor, który ustawia tekst w połączeniem z nazwą rodzica.
const char *text() const;Ta funckja zwraca tekst etykiety.
void setText( const char * );Ten slot jest tekstem etykiety.
private: void init();Ponieważ mamy teraz dwa konstruktory, wybraliśmy właną inicjalizację w prywatnej funkcjiinit().
QLabel *label;Mamy też nową prywatną zmienną; QLabel. QLabel jest jednym ze standardowych widgetów Qti może pokazywac tekst lub pixmapę bez lub z ramką.
#include <qlabel.h>Tutaj zawarliśmy definicję klasy QLabel.
LCDRange::LCDRange( QWidget *parent, const char *name ) : QVBox( parent, name ) { init(); }Ten konstruktor wywołuje funkcję init(), która zawiera własny kod inicjalizacyjny.
LCDRange::LCDRange( const char *s, QWidget *parent, const char *name ) : QVBox( parent, name ) { init(); setText( s ); }Konstruktor najpierw wywołuje init(), potem ustawia etykietę tekstową.
void LCDRange::init() { QLCDNumber *lcd = new QLCDNumber( 2, this, "lcd" ); slider = new QSlider( Horizontal, this, "slider" ); slider->setRange( 0, 99 ); slider->setValue( 0 ); label = new QLabel( " ", this, "label" ); label->setAlignment( AlignCenter ); connect( slider, SIGNAL(valueChanged(int)), lcd, SLOT(display(int)) ); connect( slider, SIGNAL(valueChanged(int)), SIGNAL(valueChanged(int)) ); setFocusProxy( slider ); }Ustawienie lcd i slider jest takie samo jak w poprzednim rozdzialer. Następnie tworzymy QLabel i mówimy jej by ustawiła swoją zawartość w centrum. Komenda connect() została także wzięta z poprzedniego rozdziału.
const char *LCDRange::text() const { return label->text(); }Ta funkcja zwraca tekst etykiety.
void LCDRange::setText( const char *s ) { label->setText( s ); }Ta funkcja ustawia tekst etykiety.
void newTarget();Ten slot tworzy cel w nowej pozycji.
signals: void hit(); void missed();Sygnał hit() emitowany jest w przypadku trafienia celu przez pocisk. Sygnał missed() emitowany jest gdy pocisk przemieści się dolną prawą za granicę widgetu.
void paintTarget( QPainter * );Ta prywatna funkcja rysuje cel.
QRect targetRect() const;Ta prywatna funkcja zwraca prostokąt wokół celu.
QPoint target;Ta prywatna zmienna zawiera centralny punkt celu.
#include <qdatetime.h>Zawieramy definicję klas QDate, QTime i QDateTime.
#include <stdlib.h>Zawieramy bibliotekę stdlib ponieważ potrzebujemy funkcji rand().
newTarget();Ta nowa linia została dodana do konstruktora. Ma za zadanie stworzyć "przypadkową" pozycję dla celu. Faktycznie jednak funkcja newTarget() narysuje tylko cel. Ponieważ jesteśmy w konstruktorze to widget CannonField jest niewidzialny. Qt gwarantuje, ze nic nie ulegnie zepsuciu gdy wywołamy repaint() na ukrytym widgecie.
void CannonField::newTarget() { static bool first_time = TRUE; if ( first_time ) { first_time = FALSE; QTime midnight( 0, 0, 0 ); srand( midnight.secsTo(QTime::currentTime()) ); } QRegion r( targetRect() ); target = QPoint( 200 + rand() % 190, 10 + rand() % 255 ); repaint( r.unite( targetRect() ) ); }Ta prywatna funkcja tworzy centralny punkt celu na "przypadkowej" pozycji.
Używamy funkcji rand() aby otrzymać przypadkowe liczby rzeczywiste. Jednak funkcja rand() zwykle daje te same wartości gdy na nowo uruchomisz program. Aby uniknąć tego musimy ustawić ziarno przypadkowości za każdym razem gdy wywołujemy tą funkcję, pseudo-rozwiązaniem bedzie liczna milisekund jakie upłynęły od północy.
Najpierw tworzymy statyczną wartość boolowską. Statyczna zmienna jak ta gwarantuje utrzymanie swojej wartości pomiedzy odwołaniami do funkcji.
Test if odniecie sukces tylko gdy funkcja zostanie wywołana po raz pierwszy, ponieważ ustawiliśmy first_time na FAŁSZ w bloku if.
Teraz tworzymy objeklt QTime midnight który reprezentuje czas 00:00:00. Dalej, pobieramy liczbę sekund jakie upłynęły od północy i i używamy go jako ziarna przypadkowości. Przygądnij się dokumentacji QDate, QTime i QDateTime.
Na koniec obliczamy centralny punkt celu. Trzymamy go w prostokącie
(x=200,y=35,szerokość=190,wysokość=255),
Dzieki eksperymentom udało się umnieścić go zawsze w zasięgu slotu.
Zauważ, że rand() zwraca przypadkową liczbę >= 0.
void CannonField::moveShot() { QRegion r( shotRect() ); timerCount++; QRect shotR = shotRect();Ta część wydarzenia timera nie zmieniła się od poprzedniego rozdziału.
if ( shotR.intersects( targetRect() ) ) { autoShootTimer->stop(); emit hit();if sprawdza czy prostokąty nałożyły się na siebie. Jeżeli tak to pocisk trafił do celu (auuu !). zatrzymujemy timer strzału i emitujemy sygnał hit(), aby powiedzieć światu zewnętrznemu, że cel został zniszczony a następnie wracamy.
} else if ( shotR.x() > width() || shotR.y() > height() ) { autoShootTimer->stop(); emit missed();Dyrektywa if jest identyczna jak ta w poprzednim przykładzie, z tym, że teraz emituje sygnał missed() aby powiedzieć światu zewnętrznemu o niepowodzeniu.
} else {Reszta funkcji jest taka sama jak wcześniek
CannonField::paintEvent() jak i wcześniej, ale dodano to:
if ( updateR.intersects( targetRect() ) ) paintTarget( &p );Te dwie linie upewniają się czy cel także wymaga przemalowania.
void CannonField::paintTarget( QPainter *p ) { p->setBrush( red ); p->setPen( black ); p->drawRect( targetRect() ); }Ta prywatna funkcja rysuje cel; czerwony prostokąt z czarną obwódką.
QRect CannonField::targetRect() const { QRect r( 0, 0, 20, 10 ); r.moveCenter( QPoint(target.x(),height() - 1 - target.y()) ); return r; }Ta prywatna fdunkcja zwraca prostokąt otaczający cel.
LCDRange *angle = new LCDRange( "ANGLE", this, "angle" );Ustawiamy tekst etykiety kąta na "ANGLE".
LCDRange *force = new LCDRange( "FORCE", this, "force" );Ustawiamy tekst etykiety siły na "FORCE".
Widety LCDRange wyglądają troche dziwnie - wbudowany zystem rozstawienia QVBox daje za dużo przestrzeni. Naprawimy to w następnym rozdziale.
Stwórz poruszający się cel.
Możesz teraz przejść do rozdziału trzynastego.
[Poprzedni tutorial] [Następny tutorial] [Główna strona tutoriala]
Copyright (c) 2000 Troll Tech | Znaki towarowe |
Wersja Qt 2.1.0
|