لطفا وارد شوید یا ثبت‌نام کنید تا به انجمن‌ها دسترسی کامل داشته باشید.



 
امتياز موضوع :
  • 0 رأي - معدل امتيازات : 0
  • 1
  • 2
  • 3
  • 4
  • 5
آموزش توابع Qt قسمت هشتم
2004-09-06, 01:25 AM,
ارسال : #1
آموزش توابع Qt قسمت هشتم
فصل هشتم : Preparing for Battle

دراين مثال، ما اولين شيء سفارشي را كه مي تواند خود را با رنگ و شكل پر كند معرفي مي كنيم. ما همچنين يك رابط صفحه كليد مفيد را نيز اضافه مي كنيم ( با دو خط كد نويسي ).
[ltr]lcdrange.h[/ltr]
[ltr]
کد :
#ifndef        LCDRANGE_H
#define       LCDRANGE_H

#include     <qvbox.h>

class      LCDRange    :    public    QVBox
{
    Q_OBJECT
    public :
        LCDRange ( QWidget     *parent = 0 , const   char    *name = 0 );
        int     value ( )  const;
    public slots:
        void     setValue ( int );
        void    setRange ( int    minVal, int     maxVal );
    signals
void       valueChanged ( int );
    private:
        QSlider      *slider;
};

#endif      //   LCDRANGE_H
[/ltr]

[ltr]lcdrange.cpp [/ltr]
[ltr]
کد :
#include       “lcdrange.h”
#include       <qslider.h>
#include       <qlcdnumber.h>

LCDRange::LCDRange ( QWidget     *parent , const   char    *name )   :   QVBox ( parent , name )
{
    QLCDNumber     *lcd = new    QLCDNumber ( 2 , this , “lcd” );
    slider = new    Qslider ( Horizontal , this , “slider” );
    slider -> setRange ( 0 , 99 );
    slider -> setValue ( 0 );
    connect ( slider , SIGNAL ( valueChanged ( int ) ) , lcd , SLOT ( display ( int ) ) ) ;
    connect ( slider , SIGNAL ( valueChanged (int ) ) , SIGNAL ( valueChanged ( int ) ) );
    setFocusProxy ( slider );
}

int     LCDRange::value ( )  const
{
    return     slider -> value ( );
}

void    LCDRange::setValue( int value )
{
    slider -> setValue ( value );
}

void     LCDRange::setRange ( int    minVal , int    maxVal )
{
    if   ( minVal  <  0  | |  maxVal  >  99  | |   minVal   >   maxVal ) {
        qWarning ( “LCDRange::setRange ( %d , %d ) \n “
                  “\t Range  must be 0 .. 99\n”
                  “\t and   minVal  must no be greater than  maxVal”,
                  minVal , maxVal );
        return;
    }
    slider -> setRange ( minVal , maxVal );
}
[/ltr]

[ltr]cannon.h[/ltr]
[ltr]
کد :
#ifndef        CANNON_H
#define       CANNON_H

#include     <qwidget.h>

class       CannonField   :   public     QWidget  
{
    Q_OBJECT
    public :
        CannonField ( QWidget     *parent = 0 , const   char   *name = 0 );
        int    angle ( )  const   { return    ang; }
        QSizePolicy    sizePolicy ( )   const;
    public  slots:
        void      setAngle ( int    degrees ) ;
    signals :
        void      angleChanged ( int );
    protected :
        void      paintEvent ( QPaintEvent   * );
    private :
        int    ang;
};

#endif     //    CANNON_H
[/ltr]

[ltr]cannon.cpp[/ltr]
[ltr]
کد :
#include      “cannon.h”
#include      <qpainter.h>

CannonField::CannonField ( QWidget      *parent , const   char  *name )  :  QWidget ( parent , name )
{
    ang = 45;
    setPalette ( QPalette ( QColor ( 250 , 250 , 200 ) ) );
}

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 );
}

void     CannonField::paintEvent ( QPaintEvent   * )
{
    QString   s =  “Angle  = “ + QString::number ( ang );
    QPainter   p ( this );
p.drawText ( 200 , 200 , s );
}

QSizePolicy     CannonField::sizePolicy ( )  const
{
    return     QSizePolicy ( QSizePolicy::Expanding , QSizePolicy::Expanding ) ;
}
[/ltr]

[ltr]main.cpp[/ltr]
[ltr]
کد :
#include      <qapplication.h>
#include      <qpushbutton.h>
#include      <qlcdnumber.h>
#include      <qfont.h>
#include      <qlayout.h>
#include      “lcdrange.h”
#include      “cannon.h”

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

MyWidget::MyWidget ( QWidget     *parent , const  char  *name )  :  QWidget ( parent , name )
{
    QPushButton     *quit = new     QPushButton ( “Quit” , this , “quit” );
    quit -> setFont ( Qfont ( “Times” , 18 , Qfont::Bold ) );
    connect ( quit , SIGNAL ( clicked ( ) ) , qApp , SLOT ( quit ( ) ) );
    LCDRange     *angle = new    LCDRange ( this , “angle” );
    angle -> setRange ( 5 , 70 );
    CannonField     *cannonField = new     CannonField ( this , “cannonField” );
    connect ( angle , SIGNAL ( valueChanged ( int ) ) , cannonField , SLOT ( setAngle ( int ) ) );
    connect ( cannonField , SIGNAL ( angleChanged ( int ) ) , angle , SLOT ( setValue ( int ) ) );
    QGridLayout     *grid = new    QGridLayout ( this , 2 , 2 , 10 );  // 2x2, 10 pixel  border
    grid -> addWidget ( quit , 0 , 0);
    grid -> addWidget ( angle , 1 , 0 , Qt::AlignTop );
    grid -> addWidget ( cannonField , 1 , 1 );
    grid -> setColStretch ( 1 , 10 );
    angle -> setValue ( 60 );
    angle -> setFocus ( );
}

int      main ( int   argc , char    **argv )
{
    QApplication      a ( argc , argv );
    MyWidget    w;
    w.setGeometry( 100 , 100 , 500 , 355 );
    a.setMainWidget ( &w );
    w.show ( );
    return     a.exec ( );
}
[/ltr]
بررسي خط به خط برنامه:
فايل lcdrange.h بسيار به فايل lcdrange.h در فصل هفتم شبيه است. ما يك اسلات به آن اضافه كرده ايم : setRange ( ).
[ltr]
کد :
        void    setRange ( int    minVal, int     maxVal );
[/ltr]
با اينكار امكان تنظيم محدوده LCDRange را به آن اضافه كرده ايم. تا كنون، در 99..0 ثابت مانده است.

فايل lcdrange.cpp در سازنده اش تغييري ايجاد شده است ( ما بعداًدرمورد آن بحث خواهيم كرد).
[ltr]
کد :
void     LCDRange::setRange ( int    minVal , int    maxVal )
{
    if   ( minVal  <  0  | |  maxVal  >  99  | |   minVal   >   maxVal ) {
        qWarning ( “LCDRange::setRange ( %d , %d ) \n “
                  “\t Range  must be 0 .. 99\n”
                  “\t and   minVal  must no be greater than  maxVal”,
                  minVal , maxVal );
        return;
    }
[/ltr]
تابع setRange ( ) محدوده اسلايدر را در LCDRange تعيين مي كند. بخاطراينكه ما تعيين كرده ايم كه شيء QLCDNumber هميشه دو عدد را نشان دهد، مي خواهيم محدوده ممكن minVal و maxVal را به 99.. 0 جهت پرهيز از سرريزي QLCDNumber تعيين كنيم. اگر آرگومانها غيرمجاز بودند، ما از تابع qWarning ( ) براي صادر كردن يك هشدار به كاربر و بازگشت اضطراري استفاده مي كنيم. qWarning ( ) تابعي شبيه به printf است كه بصورت پيش فرض خروجي خود را به stderr مي فرستد. اگر شما مي خواهيد ، مي توانيد توابع مديريت خطاي خود را توسط ::qInstallMsgHandler ( ) بكار گيريد.

در فايل cannon.h ، شيء CannonField يك شيء سفارشي جديد است كه مي داند چگونه خود را نمايش دهد.
[ltr]
کد :
class       CannonField   :   public     QWidget  
{
    Q_OBJECT
    public :
        CannonField ( QWidget     *parent = 0 , const   char   *name = 0 );
[/ltr]
شيء CannonField ، شيء QWidget را به ارث مي برد، و ما از روشي مشابه LCDRange استفاده مي كنيم.
[ltr]
کد :
        int    angle ( )  const   { return    ang; }
        QSizePolicy    sizePolicy ( )   const;
    public  slots:
        void      setAngle ( int    degrees ) ;
    signals :
        void      angleChanged ( int );
[/ltr]
عجالتاً، CannonField تنها شامل يك متغير angle است كه ما از آن بعنوان واسط استفاده مي كنيم، همانند روشي كه براي متغير value در LCDRange استفاده كرديم.
[ltr]
کد :
    protected :
        void      paintEvent ( QPaintEvent   * );
[/ltr]
اين رخداد يكي از توابع زياد كنترل رخداد QWidget است كه ما با آن روبرو شده ايم. اين تابع مجازي ( virtual function ) زماني كه يك شيء نياز به بروزرساني داشته باشد توسط Qt فراخواني مي شود، به بيان ديگر چهره شيء را طراحي مي كند.

فايل cannon.cpp :
[ltr]
کد :
CannonField::CannonField ( QWidget      *parent , const   char  *name )  :  QWidget ( parent , name )
{
[/ltr]
دوباره ، ما از روشي مشابه روشي كه براي LCDRange در فصل قبل استفاده كرديم در اينجا بكار مي گيريم.
[ltr]
کد :
    ang = 45;
    setPalette ( QPalette ( QColor ( 250 , 250 , 200 ) ) );
}
[/ltr]
سازنده 45 درجه را به متغير angle به عنوان مقدار اوليه مي دهد و الگويي سفارشي را براي شيء در نظر مي گيرد. اين الگو از رنگ مشخص شده به عنوان پس زمينه استفاده مي كند و ديگر رنگها را بطور شايسته انتخاب كرده و بكار مي گيرد. ( تنها براي اين شيء رنگ پس زمينه و نوشته واقعاً استفاده شده است.)
[ltr]
کد :
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 );
}
[/ltr]
اين تابع مقدار زاويه را مشخص مي كند. ما محدوده اي مجاز از 70 .. 5 را انتخاب كرده ايم و بر طبق آن تعداد درجه هاي داده شده را تنظيم كرده ايم. ما مشخص نكرده ايم كه اگر زاويه جديد خارج از محدوده باشد هشداري صادر گردد. اگر زاويه جديد با قبلي يكي بود، ما فوراً باز مي گرديم. اين مهم است كه سيگنال angleChanged ( ) تنها زماني صادر شود كه واقعاً مقدار زاويه تغيير كرده باشد. سپس ما مقدار زاويه جديد را تعيين مي كنيم و شيء خود را دوباره رسم مي كنيم. تابع QWidget::repaint ( ) شيء را پاكيزه و دوباره ترسيم مي كند ( معمولاً آنرا با رنگ پس زمينه پر مي كند) و يك رخداد paint به شيء ارسال مي كند. اين نتايج در فراخواني يك رخداد paint شيء بدست مي آيد.
سرانجام، ما سيگنال angleChanged() را براي اينكه به جهان بيروني بگوييم كه زاويه تغيير كرده است منتشر مي كنيم. كلمه كليدي emit براي Qt منحصر بفرد است و تركيبي قانوني از C++ نمي باشد. در حقيقت، يك ماكرو است.
[ltr]
کد :
void   CannonField::paintEvent ( QPaintEvent  * )
{
    QString  s = “Angle  = “ + QString::number ( ang );
    QPainter  p( this );
    p.drawText ( 200 , 200 , s );
}
[/ltr]
اين اولين تلاش ما براي نوشتن يك دستگيره رخداد است. آرگومان رخداد شرحي از رخداد paint را شامل مي شود. QPaintEvent مختصات منطقه اي از شيء را كه بايد به روزرساني شود دارا مي باشد. بخاطر زمان و عجالتاً ما تنبل مي شويم و همه چيز را بروزرساني مي كنيم.
كد ما مقدار زاويه را در مكان مشخص شده در شيء نشان مي دهد. ابتدا ما يك QString را همراه با مقداري متن و زاويه ايجاد مي كنيم. سپس يك QPainter را كه دراين شيء كار مي كند و از آن براي ترسيم رشته متني استفاده مي كنيم را ايجاد مي كنيم. بعداً دوباره به سراغ QPainter خواهيم آمد، اين شيء كارهاي زيادي مي تواند انجام دهد.

فايل main.cpp:
[ltr]
کد :
#include     “cannon.h”
[/ltr]
ما كلاس جديد خود را ضميمه مي كنيم.
[ltr]
کد :
class   MyWidget  :  public    QWidget
{
    public :
        MyWidget  ( QWidget   * parent = 0 , const  char  *name = 0 );
};
[/ltr]
در اين لحظه ما يك LCDRange تنها و يك CannonField را به شيء سطح بالاي خود اظافه مي كنيم.
[ltr]
کد :
    LCDRange   *angle = new  LCDRange ( this , “angle” );
[/ltr]
در سازنده، ما LCDRange خود را ايجاد و تنظيم مي كنيم.
[ltr]
کد :
    angle -> setRange ( 5 , 70 );
[/ltr]
LCDRange را طوري تنظيم مي كنيم كه درجه هاي بين 5 تا 70 را بپذيرد.
[ltr]
کد :
    CannonField  *cannonField = new  CannonField ( this , “cannonField” );
[/ltr]
CannonField خود را ايجاد مي كنيم.
[ltr]
کد :
connect ( angle , SIGNAL ( valueChanged ( int ) ) , cannonField , SLOT ( setAngle ( int ) ) );
connect ( cannonField , SIGNAL ( angleChanged ( int ) ) , angle , SLOT( setValue ( int ) ) );
[/ltr]
دراينجا ما سيگنال valueChanged( ) از شيء LCDRange را به اسلات setAngle ( ) از CannonField متصل كرده ايم. اين كار باعث مي شود زماني كه كاربر روي LCDRange كاركند مقدار زاويه CannonField بروزرساني شود. همچنين ما اتصال را بصورت برعكس نيز برقرار كرده ايم كه زماني مقدار زاويه در CannonField تغيير كند مقدار LCDRange نيز بروزرساني مي شود. در مثال ما هرگز مستقيماً زاويه را تغيير نمي دهيم. ولي با برقراري آخرين ارتباط توسط connect( ) مطمئن مي شويم كه تغييرات آينده خللي در همزماني دو مقدار ايجاد نمي كند.
اين موضوع قدرت برنامه نويسي مؤلفه و بسته بندي صحيح را شرح مي دهد.
توجه كنيد كه چقدر مهم است كه سيگنال angleChanged( ) تنها زماني كه زاويه واقعاً تغيير مي كند منتشر گردد. اگر هردوي LCDRange و CannonField باهم اين وضعيت را منتشر كده باشند، برنامه بمحض اينكه يكي از مقادير تغيير كند وارد يك حلقه نامتنهاهي مي شود.
[ltr]
کد :
    QGridLayout   *grid = new  QGridLayout  ( this , 2 , 2 , 10 );   // 2x2 , 10 pixel border
[/ltr]
تاكنون ما از اشيائي از QVBox و QGrid كه به مجموعه و گروه نياز نداشته اند براي مديريت geometry استفاده كرده ايم. اكنون، بنابراين، مي خواهيم كه مقدار بيشتري بر روي طرح كنترل داشته باشيم، و به كلاس قدرتمندتري بنام QGridLayout سوئيچ مي كنيم. QGridLayout يك شيء نيست، كلاسي متفاوت است كه مي تواند فرزندي از هر شيء را مديريت كند.
به عنوان توضيح، ما آرايه اي 2*2 با حاشيه 10 پيكسل ايجاد كرده ايم. ( سازندة QGridLayout مي تواند كمي مرموز باشد، همچنين براي قراردادن اينگونه توضيحات خوب است)
[ltr]
کد :
    grid -> addWidget ( quit , 0 , 0 );
[/ltr]
ما دكمه Quit را در قسمت بالا و چپ صفحه اضافه مي كنيم : 0.0 .
[ltr]
کد :
    grid -> addWidget ( angle , 1 , 0 , Qt::AlignTop );
[/ltr]
زاويه LCDRange را در قسمت پايين و چپ قرار مي دهيم، تنظيم شده نسبت به خانه بالايي خود. ( همترازي يكي از چيزهايي است كه QGridLayout اجازه استفاده از آنرا مي دهد ولي QGrid اين كار را نمي كند.)
[ltr]
کد :
    grid -> addWidget ( cannonField , 1 , 1 );
[/ltr]
شيء CannonField را در قسمت پايين و راست قرار مي دهيم. ( خانه بالا و چپ خاليست).
[ltr]
کد :
    grid -> setColStretch ( 1 , 10 );
[/ltr]
ما به QGridLayout مي گوييم كه ستون سمت راست ( ستون 1) بسط يافتني است. چون ستون سمت چپ بسط يافتني نيست، QGridLayout سعي خواهد كرد كه اندازه اشياء سمت چپ تغيير نكند و تنها اندازه CannonField وقتي كه اندازه MyWidget تغيير مي كند، تغيير كند.
[ltr]
کد :
    angle -> setValue ( 60 );
[/ltr]
ما مقدار زاويه اوليه را تنظيم مي كنيم. توجه كنيد كه ارتباط بين LCDRange و CannonField را برخواهد انگيخت.
[ltr]
کد :
    angle -> setFocus ( );
[/ltr]
آخرين عمل ما تنظيم تمركز صفحه كليد روي زاويه است بنابراين ورودي صفحه كليد بصورت پيش فرض به شيء LCDRange فرستاده مي شود.
LCDRange شامل هيچگونه KeyPressEvent( ) نمي باشد، بنابراين بنظر خواهد رسيد خيلي مفيد نباشد. بنابراين ،به سازنده اش خطي جديد اضافه مي شود :
[ltr]
کد :
    setFocusProxy ( slider );
[/ltr]
LCDRange اسلايدر به عنوان نماينده تمركز (focus proxy) تنظيم مي كند. اين بدان معني است كه زماني كه كسي (برنامه يا كاربر) بخواهد تمركز صفحه كليد را به LCDRange بدهد، اسلايدر آنرا دريافت مي كند. QSlider يك رابط محبوب صفحه كليد دارد، بنابراين تنها با يك خط كد نويسي يك رابط همانند آنرا به LCDRange داده ايم.

عملكرد برنامه:
حالا صفحه كليد كارهايي انجام مي دهد ـ كليدهاي جهت دار، Home، End، PageUp، و PageDown همه كارهاي قابل درك را انجام مي دهند.
وقتي كه روي اسلايدر كاري انجام شد، CannonField مقدار جديد زاويه را نشان مي دهد. بمحض تغيير اندازه، CannonField تاحد ممكن فاضاي بيشتري را مي گيرد.

تمرينات :
سعي كنيد اندازه پنجره را تغيير دهيد. اگر شما آنرا واقعاً تنگ و يا واقعاً گشاد كنيد چه اتفاقي مي افتند؟
اگر شما همترازي از بالا (AlignTop) را حذف كنيد، چه اتفاقي براي مكان و اندازهLCDRange مي افتد؟ چرا؟
اگر شما قابليت بسط يافتن را به ستون سمت چپ بدهيد، وقتي كه شما اندازه پنجره را تفيير مي دهيد چه اتفاقي مي افتد؟
از setFocus( ) صرفنظر كنيد. كدام رفتار را ترجيح مي دهيد؟
سعي كنيد “Quit” را در فراخواني QButton:ConfusedetText( ) به “&Quit” تغيير دهيد. چهره دكمه چه تغييري مي كند؟ چه اتفاقي مي افتد اگر در هنگام اجراي برنامه شما كليد Alt+Q را بزنيد؟ (در بعضي صفحه كليدها بصورت Meta+Q است)
متن درون CannonField را به وسط آن هدايت كنيد.
حالا شما براي فصل نهم آماده هستيد.
جستجوی تمامی ارسال های کاربر
نقل قول این ارسال در یک پاسخ
2011-04-18, 09:18 AM,
ارسال : #2
Re: آموزش توابع Qt قسمت هشتم
xigmacorporation نویسنده :فصل هشتم : Preparing for Battle

دراين مثال، ما اولين شيء سفارشي را كه مي تواند خود را با رنگ و شكل پر كند معرفي مي كنيم. ما همچنين يك رابط صفحه كليد مفيد را نيز اضافه مي كنيم ( با دو خط كد نويسي ).
[ltr]lcdrange.h[/ltr]
[ltr]
کد :
#ifndef        LCDRANGE_H
#define       LCDRANGE_H

#include     <qvbox.h>

class      LCDRange    :    public    QVBox
{
    Q_OBJECT
    public :
        LCDRange ( QWidget     *parent = 0 , const   char    *name = 0 );
        int     value ( )  const;
    public slots:
        void     setValue ( int );
        void    setRange ( int    minVal, int     maxVal );
    signals
void       valueChanged ( int );
    private:
        QSlider      *slider;
};

#endif      //   LCDRANGE_H
[/ltr]

[ltr]lcdrange.cpp [/ltr]
[ltr]
کد :
#include       “lcdrange.h”
#include       <qslider.h>
#include       <qlcdnumber.h>

LCDRange::LCDRange ( QWidget     *parent , const   char    *name )   :   QVBox ( parent , name )
{
    QLCDNumber     *lcd = new    QLCDNumber ( 2 , this , “lcd” );
    slider = new    Qslider ( Horizontal , this , “slider” );
    slider -> setRange ( 0 , 99 );
    slider -> setValue ( 0 );
    connect ( slider , SIGNAL ( valueChanged ( int ) ) , lcd , SLOT ( display ( int ) ) ) ;
    connect ( slider , SIGNAL ( valueChanged (int ) ) , SIGNAL ( valueChanged ( int ) ) );
    setFocusProxy ( slider );
}

int     LCDRange::value ( )  const
{
    return     slider -> value ( );
}

void    LCDRange::setValue( int value )
{
    slider -> setValue ( value );
}

void     LCDRange::setRange ( int    minVal , int    maxVal )
{
    if   ( minVal  <  0  | |  maxVal  >  99  | |   minVal   >   maxVal ) {
        qWarning ( “LCDRange::setRange ( %d , %d ) \n “
                  “\t Range  must be 0 .. 99\n”
                  “\t and   minVal  must no be greater than  maxVal”,
                  minVal , maxVal );
        return;
    }
    slider -> setRange ( minVal , maxVal );
}
[/ltr]

[ltr]cannon.h[/ltr]
[ltr]
کد :
#ifndef        CANNON_H
#define       CANNON_H

#include     <qwidget.h>

class       CannonField   :   public     QWidget  
{
    Q_OBJECT
    public :
        CannonField ( QWidget     *parent = 0 , const   char   *name = 0 );
        int    angle ( )  const   { return    ang; }
        QSizePolicy    sizePolicy ( )   const;
    public  slots:
        void      setAngle ( int    degrees ) ;
    signals :
        void      angleChanged ( int );
    protected :
        void      paintEvent ( QPaintEvent   * );
    private :
        int    ang;
};

#endif     //    CANNON_H
[/ltr]

[ltr]cannon.cpp[/ltr]
[ltr]
کد :
#include      “cannon.h”
#include      <qpainter.h>

CannonField::CannonField ( QWidget      *parent , const   char  *name )  :  QWidget ( parent , name )
{
    ang = 45;
    setPalette ( QPalette ( QColor ( 250 , 250 , 200 ) ) );
}

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 );
}

void     CannonField::paintEvent ( QPaintEvent   * )
{
    QString   s =  “Angle  = “ + QString::number ( ang );
    QPainter   p ( this );
p.drawText ( 200 , 200 , s );
}

QSizePolicy     CannonField::sizePolicy ( )  const
{
    return     QSizePolicy ( QSizePolicy::Expanding , QSizePolicy::Expanding ) ;
}
[/ltr]

[ltr]main.cpp[/ltr]
[ltr]
کد :
#include      <qapplication.h>
#include      <qpushbutton.h>
#include      <qlcdnumber.h>
#include      <qfont.h>
#include      <qlayout.h>
#include      “lcdrange.h”
#include      “cannon.h”

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

MyWidget::MyWidget ( QWidget     *parent , const  char  *name )  :  QWidget ( parent , name )
{
    QPushButton     *quit = new     QPushButton ( “Quit” , this , “quit” );
    quit -> setFont ( Qfont ( “Times” , 18 , Qfont::Bold ) );
    connect ( quit , SIGNAL ( clicked ( ) ) , qApp , SLOT ( quit ( ) ) );
    LCDRange     *angle = new    LCDRange ( this , “angle” );
    angle -> setRange ( 5 , 70 );
    CannonField     *cannonField = new     CannonField ( this , “cannonField” );
    connect ( angle , SIGNAL ( valueChanged ( int ) ) , cannonField , SLOT ( setAngle ( int ) ) );
    connect ( cannonField , SIGNAL ( angleChanged ( int ) ) , angle , SLOT ( setValue ( int ) ) );
    QGridLayout     *grid = new    QGridLayout ( this , 2 , 2 , 10 );  // 2x2, 10 pixel  border
    grid -> addWidget ( quit , 0 , 0);
    grid -> addWidget ( angle , 1 , 0 , Qt::AlignTop );
    grid -> addWidget ( cannonField , 1 , 1 );
    grid -> setColStretch ( 1 , 10 );
    angle -> setValue ( 60 );
    angle -> setFocus ( );
}

int      main ( int   argc , char    **argv )
{
    QApplication      a ( argc , argv );
    MyWidget    w;
    w.setGeometry( 100 , 100 , 500 , 355 );
    a.setMainWidget ( &w );
    w.show ( );
    return     a.exec ( );
}
[/ltr]
بررسي خط به خط برنامه:
فايل lcdrange.h بسيار به فايل lcdrange.h در فصل هفتم شبيه است. ما يك اسلات به آن اضافه كرده ايم : setRange ( ).
[ltr]
کد :
        void    setRange ( int    minVal, int     maxVal );
[/ltr]
با اينكار امكان تنظيم محدوده LCDRange را به آن اضافه كرده ايم. تا كنون، در 99..0 ثابت مانده است.

فايل lcdrange.cpp در سازنده اش تغييري ايجاد شده است ( ما بعداًدرمورد آن بحث خواهيم كرد).
[ltr]
کد :
void     LCDRange::setRange ( int    minVal , int    maxVal )
{
    if   ( minVal  <  0  | |  maxVal  >  99  | |   minVal   >   maxVal ) {
        qWarning ( “LCDRange::setRange ( %d , %d ) \n “
                  “\t Range  must be 0 .. 99\n”
                  “\t and   minVal  must no be greater than  maxVal”,
                  minVal , maxVal );
        return;
    }
[/ltr]
تابع setRange ( ) محدوده اسلايدر را در LCDRange تعيين مي كند. بخاطراينكه ما تعيين كرده ايم كه شيء QLCDNumber هميشه دو عدد را نشان دهد، مي خواهيم محدوده ممكن minVal و maxVal را به 99.. 0 جهت پرهيز از سرريزي QLCDNumber تعيين كنيم. اگر آرگومانها غيرمجاز بودند، ما از تابع qWarning ( ) براي صادر كردن يك هشدار به كاربر و بازگشت اضطراري استفاده مي كنيم. qWarning ( ) تابعي شبيه به printf است كه بصورت پيش فرض خروجي خود را به stderr مي فرستد. اگر شما مي خواهيد ، مي توانيد توابع مديريت خطاي خود را توسط ::qInstallMsgHandler ( ) بكار گيريد.

در فايل cannon.h ، شيء CannonField يك شيء سفارشي جديد است كه مي داند چگونه خود را نمايش دهد.
[ltr]
کد :
class       CannonField   :   public     QWidget  
{
    Q_OBJECT
    public :
        CannonField ( QWidget     *parent = 0 , const   char   *name = 0 );
[/ltr]
شيء CannonField ، شيء QWidget را به ارث مي برد، و ما از روشي مشابه LCDRange استفاده مي كنيم.
[ltr]
کد :
        int    angle ( )  const   { return    ang; }
        QSizePolicy    sizePolicy ( )   const;
    public  slots:
        void      setAngle ( int    degrees ) ;
    signals :
        void      angleChanged ( int );
[/ltr]
عجالتاً، CannonField تنها شامل يك متغير angle است كه ما از آن بعنوان واسط استفاده مي كنيم، همانند روشي كه براي متغير value در LCDRange استفاده كرديم.
[ltr]
کد :
    protected :
        void      paintEvent ( QPaintEvent   * );
[/ltr]
اين رخداد يكي از توابع زياد كنترل رخداد QWidget است كه ما با آن روبرو شده ايم. اين تابع مجازي ( virtual function ) زماني كه يك شيء نياز به بروزرساني داشته باشد توسط Qt فراخواني مي شود، به بيان ديگر چهره شيء را طراحي مي كند.

فايل cannon.cpp :
[ltr]
کد :
CannonField::CannonField ( QWidget      *parent , const   char  *name )  :  QWidget ( parent , name )
{
[/ltr]
دوباره ، ما از روشي مشابه روشي كه براي LCDRange در فصل قبل استفاده كرديم در اينجا بكار مي گيريم.
[ltr]
کد :
    ang = 45;
    setPalette ( QPalette ( QColor ( 250 , 250 , 200 ) ) );
}
[/ltr]
سازنده 45 درجه را به متغير angle به عنوان مقدار اوليه مي دهد و الگويي سفارشي را براي شيء در نظر مي گيرد. اين الگو از رنگ مشخص شده به عنوان پس زمينه استفاده مي كند و ديگر رنگها را بطور شايسته انتخاب كرده و بكار مي گيرد. ( تنها براي اين شيء رنگ پس زمينه و نوشته واقعاً استفاده شده است.)
[ltr]
کد :
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 );
}
[/ltr]
اين تابع مقدار زاويه را مشخص مي كند. ما محدوده اي مجاز از 70 .. 5 را انتخاب كرده ايم و بر طبق آن تعداد درجه هاي داده شده را تنظيم كرده ايم. ما مشخص نكرده ايم كه اگر زاويه جديد خارج از محدوده باشد هشداري صادر گردد. اگر زاويه جديد با قبلي يكي بود، ما فوراً باز مي گرديم. اين مهم است كه سيگنال angleChanged ( ) تنها زماني صادر شود كه واقعاً مقدار زاويه تغيير كرده باشد. سپس ما مقدار زاويه جديد را تعيين مي كنيم و شيء خود را دوباره رسم مي كنيم. تابع QWidget::repaint ( ) شيء را پاكيزه و دوباره ترسيم مي كند ( معمولاً آنرا با رنگ پس زمينه پر مي كند) و يك رخداد paint به شيء ارسال مي كند. اين نتايج در فراخواني يك رخداد paint شيء بدست مي آيد.
سرانجام، ما سيگنال angleChanged() را براي اينكه به جهان بيروني بگوييم كه زاويه تغيير كرده است منتشر مي كنيم. كلمه كليدي emit براي Qt منحصر بفرد است و تركيبي قانوني از C++ نمي باشد. در حقيقت، يك ماكرو است.
[ltr]
کد :
void   CannonField::paintEvent ( QPaintEvent  * )
{
    QString  s = “Angle  = “ + QString::number ( ang );
    QPainter  p( this );
    p.drawText ( 200 , 200 , s );
}
[/ltr]
اين اولين تلاش ما براي نوشتن يك دستگيره رخداد است. آرگومان رخداد شرحي از رخداد paint را شامل مي شود. QPaintEvent مختصات منطقه اي از شيء را كه بايد به روزرساني شود دارا مي باشد. بخاطر زمان و عجالتاً ما تنبل مي شويم و همه چيز را بروزرساني مي كنيم.
كد ما مقدار زاويه را در مكان مشخص شده در شيء نشان مي دهد. ابتدا ما يك QString را همراه با مقداري متن و زاويه ايجاد مي كنيم. سپس يك QPainter را كه دراين شيء كار مي كند و از آن براي ترسيم رشته متني استفاده مي كنيم را ايجاد مي كنيم. بعداً دوباره به سراغ QPainter خواهيم آمد، اين شيء كارهاي زيادي مي تواند انجام دهد.

فايل main.cpp:
[ltr]
کد :
#include     “cannon.h”
[/ltr]
ما كلاس جديد خود را ضميمه مي كنيم.
[ltr]
کد :
class   MyWidget  :  public    QWidget
{
    public :
        MyWidget  ( QWidget   * parent = 0 , const  char  *name = 0 );
};
[/ltr]
در اين لحظه ما يك LCDRange تنها و يك CannonField را به شيء سطح بالاي خود اظافه مي كنيم.
[ltr]
کد :
    LCDRange   *angle = new  LCDRange ( this , “angle” );
[/ltr]
در سازنده، ما LCDRange خود را ايجاد و تنظيم مي كنيم.
[ltr]
کد :
    angle -> setRange ( 5 , 70 );
[/ltr]
LCDRange را طوري تنظيم مي كنيم كه درجه هاي بين 5 تا 70 را بپذيرد.
[ltr]
کد :
    CannonField  *cannonField = new  CannonField ( this , “cannonField” );
[/ltr]
CannonField خود را ايجاد مي كنيم.
[ltr]
کد :
connect ( angle , SIGNAL ( valueChanged ( int ) ) , cannonField , SLOT ( setAngle ( int ) ) );
connect ( cannonField , SIGNAL ( angleChanged ( int ) ) , angle , SLOT( setValue ( int ) ) );
[/ltr]
دراينجا ما سيگنال valueChanged( ) از شيء LCDRange را به اسلات setAngle ( ) از CannonField متصل كرده ايم. اين كار باعث مي شود زماني كه كاربر روي LCDRange كاركند مقدار زاويه CannonField بروزرساني شود. همچنين ما اتصال را بصورت برعكس نيز برقرار كرده ايم كه زماني مقدار زاويه در CannonField تغيير كند مقدار LCDRange نيز بروزرساني مي شود. در مثال ما هرگز مستقيماً زاويه را تغيير نمي دهيم. ولي با برقراري آخرين ارتباط توسط connect( ) مطمئن مي شويم كه تغييرات آينده خللي در همزماني دو مقدار ايجاد نمي كند.
اين موضوع قدرت برنامه نويسي مؤلفه و بسته بندي صحيح را شرح مي دهد.
توجه كنيد كه چقدر مهم است كه سيگنال angleChanged( ) تنها زماني كه زاويه واقعاً تغيير مي كند منتشر گردد. اگر هردوي LCDRange و CannonField باهم اين وضعيت را منتشر كده باشند، برنامه بمحض اينكه يكي از مقادير تغيير كند وارد يك حلقه نامتنهاهي مي شود.
[ltr]
کد :
    QGridLayout   *grid = new  QGridLayout  ( this , 2 , 2 , 10 );   // 2x2 , 10 pixel border
[/ltr]
تاكنون ما از اشيائي از QVBox و QGrid كه به مجموعه و گروه نياز نداشته اند براي مديريت geometry استفاده كرده ايم. اكنون، بنابراين، مي خواهيم كه مقدار بيشتري بر روي طرح كنترل داشته باشيم، و به كلاس قدرتمندتري بنام QGridLayout سوئيچ مي كنيم. QGridLayout يك شيء نيست، كلاسي متفاوت است كه مي تواند فرزندي از هر شيء را مديريت كند.
به عنوان توضيح، ما آرايه اي 2*2 با حاشيه 10 پيكسل ايجاد كرده ايم. ( سازندة QGridLayout مي تواند كمي مرموز باشد، همچنين براي قراردادن اينگونه توضيحات خوب است)
[ltr]
کد :
    grid -> addWidget ( quit , 0 , 0 );
[/ltr]
ما دكمه Quit را در قسمت بالا و چپ صفحه اضافه مي كنيم : 0.0 .
[ltr]
کد :
    grid -> addWidget ( angle , 1 , 0 , Qt::AlignTop );
[/ltr]
زاويه LCDRange را در قسمت پايين و چپ قرار مي دهيم، تنظيم شده نسبت به خانه بالايي خود. ( همترازي يكي از چيزهايي است كه QGridLayout اجازه استفاده از آنرا مي دهد ولي QGrid اين كار را نمي كند.)
[ltr]
کد :
    grid -> addWidget ( cannonField , 1 , 1 );
[/ltr]
شيء CannonField را در قسمت پايين و راست قرار مي دهيم. ( خانه بالا و چپ خاليست).
[ltr]
کد :
    grid -> setColStretch ( 1 , 10 );
[/ltr]
ما به QGridLayout مي گوييم كه ستون سمت راست ( ستون 1) بسط يافتني است. چون ستون سمت چپ بسط يافتني نيست، QGridLayout سعي خواهد كرد كه اندازه اشياء سمت چپ تغيير نكند و تنها اندازه CannonField وقتي كه اندازه MyWidget تغيير مي كند، تغيير كند.
[ltr]
کد :
    angle -> setValue ( 60 );
[/ltr]
ما مقدار زاويه اوليه را تنظيم مي كنيم. توجه كنيد كه ارتباط بين LCDRange و CannonField را برخواهد انگيخت.
[ltr]
کد :
    angle -> setFocus ( );
[/ltr]
آخرين عمل ما تنظيم تمركز صفحه كليد روي زاويه است بنابراين ورودي صفحه كليد بصورت پيش فرض به شيء LCDRange فرستاده مي شود.
LCDRange شامل هيچگونه KeyPressEvent( ) نمي باشد، بنابراين بنظر خواهد رسيد خيلي مفيد نباشد. بنابراين ،به سازنده اش خطي جديد اضافه مي شود :
[ltr]
کد :
    setFocusProxy ( slider );
[/ltr]
LCDRange اسلايدر به عنوان نماينده تمركز (focus proxy) تنظيم مي كند. اين بدان معني است كه زماني كه كسي (برنامه يا كاربر) بخواهد تمركز صفحه كليد را به LCDRange بدهد، اسلايدر آنرا دريافت مي كند. QSlider يك رابط محبوب صفحه كليد دارد، بنابراين تنها با يك خط كد نويسي يك رابط همانند آنرا به LCDRange داده ايم.

عملكرد برنامه:
حالا صفحه كليد كارهايي انجام مي دهد ـ كليدهاي جهت دار، Home، End، PageUp، و PageDown همه كارهاي قابل درك را انجام مي دهند.
وقتي كه روي اسلايدر كاري انجام شد، CannonField مقدار جديد زاويه را نشان مي دهد. بمحض تغيير اندازه، CannonField تاحد ممكن فاضاي بيشتري را مي گيرد.

تمرينات :
سعي كنيد اندازه پنجره را تغيير دهيد. اگر شما آنرا واقعاً تنگ و يا واقعاً گشاد كنيد چه اتفاقي مي افتند؟
اگر شما همترازي از بالا (AlignTop) را حذف كنيد، چه اتفاقي براي مكان و اندازهLCDRange مي افتد؟ چرا؟
اگر شما قابليت بسط يافتن را به ستون سمت چپ بدهيد، وقتي كه شما اندازه پنجره را تفيير مي دهيد چه اتفاقي مي افتد؟
از setFocus( ) صرفنظر كنيد. كدام رفتار را ترجيح مي دهيد؟
سعي كنيد “Quit” را در فراخواني QButton:ConfusedetText( ) به “&Quit” تغيير دهيد. چهره دكمه چه تغييري مي كند؟ چه اتفاقي مي افتد اگر در هنگام اجراي برنامه شما كليد Alt+Q را بزنيد؟ (در بعضي صفحه كليدها بصورت Meta+Q است)
متن درون CannonField را به وسط آن هدايت كنيد.
حالا شما براي فصل نهم آماده هستيد.
نقل قول این ارسال در یک پاسخ
2011-04-18, 09:19 PM,
ارسال : #3
پاسخ: Re: آموزش توابع Qt قسمت هشتم
آقا دست شما درد نکنه، من با pyqt قبلا یه مقدار کار کرده بودم. فقط خواستم قدردانی کنم ازتون.

Lenovo Thinkpad R61 , Arch 64Bit kernel 3.7, kde 4.10, chromium 25
<!-- m --><a class="postlink" href="http://ebrahimraeyat.blogfa.com/">http://ebrahimraeyat.blogfa.com/</a><!-- m -->
مشاهده تارنمای کاربر جستجوی تمامی ارسال های کاربر
نقل قول این ارسال در یک پاسخ


رفتن به انجمن :


کاربران در حال مشاهده موضوع : 1 مهمان