
W tym przykładzie wprowadzimy rysowanie w pixmapach aby zapobiec migotaniu. dodamy także kontrolę siły.
int angle() const { return ang; }
int force() const { return f; }
public slots:
void setAngle( int degrees );
void setForce( int newton );
signals:
void angleChanged( int );
void forceChanged( int );
Interfejs dla słiły posiada tą samą precuzję co dla kąta.
private: QRect cannonRect() const;Musimy umieścić definicję prostokąta zawierającego działo w osobnej funkcji.
int ang; int f; };Siła jest przechowywana w rzeczywistej liczbie f.
#include <qpixmap.h>Dołączamy definicję klasy QPixmap.
CannonField::CannonField( QWidget *parent, const char *name )
: QWidget( parent, name )
{
ang = 45;
f = 0;
setPalette( QPalette( QColor( 250, 250, 200) ) );
}
Siła (f) jest inicjalizowana przez zero.
void CannonField::setAngle( int degrees )
{
if ( degrees < 5 )
degrees = 5;
if ( degrees > 70 )
degrees = 70;
if ( ang == degrees )
return;
ang = degrees;
repaint( cannonRect(), FALSE );
emit angleChanged( ang );
}
Dokonaliśmy małych zmian w funkcji setAngle(). Przemalowuje tylko część
widgetu, który zawiera działo. Argument FALSE wskazuje, że prostokąt nie
powinien być wymazywany zanim do widgetu zostanie wysłane wydarzenie rysowania.
To przyśpiesza i upłynnia malowanie.
void CannonField::setForce( int newton )
{
if ( newton < 0 )
newton = 0;
if ( f == newton )
return;
f = newton;
emit forceChanged( f );
}
Implementacja setForce() jest dość podobna do setAngle(). Jedyną różnicą
jest to, że skoro nie pokazujemy wartości siły, to nie musimy przemalowywać
widgetu.
void CannonField::paintEvent( QPaintEvent *e )
{
if ( !e->rect().intersects( cannonRect() ) )
return;
Zoptymalizowaliśmy wydarzenie rysowania tak, aby przerysowywać te części
który wymagają uaktualnienia. Najpierw więc sprawdzamy czy musimy coś przesysowywać,
jeżeli nie to wracamy.
QRect cr = cannonRect(); QPixmap pix( cr.size() );Teraz utworzymy tymczasową pixmapę, której użyjemy do rysowania bez migotania. Wszystkie operacje rysownicze będą teraz wykonywane na tej pixmapie, a ona bedzie rysowana na ekranie pojedynczą operacją.
Jest to esencja rysowania be zmigotania: Narysuj każdy piksel dokładnie jeden raz. Mniej i dostaniesz błędy rysowania. Więcej i bedziesz miał migotanie.
pix.fill( this, cr.topLeft() );Wypełniamy pixmapę tłem z tego widgetu.
QPainter p( &pix ); p.setBrush( blue ); p.setPen( NoPen ); p.translate( 0, pix.height() - 1 ); p.drawPie( QRect( -35,-35, 70, 70 ), 0, 90*16 ); p.rotate( -ang ); p.drawRect( QRect(33, -4, 15, 8) ); p.end();Rysujemy, tak jak w rozdziale 9, lecz teraz rysujemy w pixmapie.
W tym punkcie, mamy zmienną rysowniczą i pixmapę, która wygląda dokładnie dobrze, ale ciągle nie rysowaliśmy na ekranie.
p.begin( this ); p.drawPixmap( cr.topLeft(), pix );Tak więc otwieramy rysownika na CannonField itself i rysujemy pixmapę.
To wszystko !
QRect CannonField::cannonRect() const
{
QRect r( 0, 0, 50, 50 );
r.moveBottomLeft( rect().bottomLeft() );
return r;
}
Tak funkcja zwraca prostokątne granice zawierające działo w koordynatach
widgetów. Najpierw tworzymy Kwadrat 50x50, potem je przesuwamy, tak że
lewy dolny brzeg równa się lewemu dolnemu brzegowi widgetu.
Funkcja QWidget::rect() zwraca brzegi prostokąta widge w własnych koordynatach widgetu (gdzie górny lewy róg to 0,0).
MyWidget::MyWidget( QWidget *parent, const char *name )
: QWidget( parent, name )
{
Konstruktor jest praktycznie ten sam, lecz dodaliśmy kilka linii.
LCDRange *force = new LCDRange( this, "force" ); force->setRange( 10, 50 );Dodamy drugi LCDRange, który będzie używany dla siły.
connect( force, SIGNAL(valueChanged(int)), cannonField, SLOT(setForce(int)) ); connect( cannonField, SIGNAL(forceChanged(int)), force, SLOT(setValue(int)) );Łączymy widget force z widgetem cannonField zupełnie tak jak to robiliśmy z widgetem angle.
QVBoxLayout *leftBox = new QVBoxLayout; grid->addLayout( leftBox, 1, 0 ); leftBox->addWidget( angle ); leftBox->addWidget( force );W rozdziale 9, umiesciliśmy angle w dolnej lewej komórce. Teraz chcemy umieścić dwa widgety w tej komórce, więc tworzymy pionowy prostokąt, w umieszczamy angle i range w pionowym prostokącie.
force->setValue( 25 );Inicjalizujemy wartość siły przez 25.
Umieść działo w prawym dolnym rogu.
Dodaj lepszą obsługę klawiatury. Na przykład niech + i - zwiększają siłę a enter to strzał. Podpowiedź: QAccel i nowe sloty addStep() i subtractStep() w LCDRange, tak jak w QSlider::addStep().
Możesz teraz przejść do rozdziału jedenastego.
[Poprzedni tutorial] [Następny tutorial] [Główna strona tutoriala]
| Copyright (c) 2000 Troll Tech | Znaki towarowe |
Wersja Qt 2.1.0
|