# Native Code > برنامه نویسی با C > برنامه نویسی در محیط QT و هم خانواده هایش >  سوال در مورد qt

## nasrin55

این چه معنی می دهد؟ کارش چیست؟
setFocusProxy


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. QSlider has a decent keyboard interface, so with just one line of code we've given LCDRange one. 

همین طور مفهوم این جمله چیه؟


توی تکه کد زیر چه کاری را انجام می دهد؟

LCDRange::LCDRange(QWidget *parent)
     : QWidget(parent)
 {
     QLCDNumber *lcd = new QLCDNumber(2);
     lcd->setSegmentStyle(QLCDNumber::Filled);

     slider = new QSlider(Qt::Horizontal);
     slider->setRange(0, 99);
     slider->setValue(0);

     connect(slider, SIGNAL(valueChanged(int)),
             lcd, SLOT(display(int)));
     connect(slider, SIGNAL(valueChanged(int)),
             this, SIGNAL(valueChanged(int)));

     QVBoxLayout *layout = new QVBoxLayout;
     layout->addWidget(lcd);
     layout->addWidget(slider);
     setLayout(layout);

     setFocusProxy(slider);
 }

----------


## حامد مصافی

تابع setFocusProxy به focusProxy مقدار می دهد. اگر یک widget فوکوس بگیرد می تواند آن را به یک widget دیگر پاس دهد، در واقع widget دوم نماینده دریافت فوکوس از سیستم عامل خواهد بود. در این مثال slider نماینده کلاس LCDRange خواهد بود. یعنی در موقع کلاس LCDRange فوکوس بگیرد آن را مستقیماً به slider انتقال خواهد داد و سایر widget ها (مانند lcd) توانایی دریافت فوکوس نخواهند داشت.

----------


## nasrin55

یعنی چی که "تابع setFocusProxy به focusProxy مقدار می دهد"؟؟ این مقدار یعنی فوکوس یعنی چی ؟  ما که جایی از widget دومی که فوکوس میگیره استفاده نمی کنیم.  
اگر که ما این خط آخر یعنی  setfocousproxy(slider) را نمی نوشتیم چه اتفاقی می افتاد ؟؟

----------


## حامد مصافی

کلاس شما دو widget در خود دارد با نام های lcd و slider. در حالت عادی کاربر می تواند روی هر یک از آنها کلیک کند و فوکوس به طور طبیعی به widget کلیک شده انتقال می یابد. اما در خط آخر دریافت فوکوس این کلاس به شی slider منتقل خواهد شد. یعنی چنانچه کاربر روی widget شما کلیک کند شی slider دارای فوکوس خواهد شد حتی اگر کاربر lcd را کلیک کرده باشد.

----------


## nasrin55

یه سوال دیگه هم داشتم اینکه تو این تکه کد ما می توانیم مختصات حرکت یه گلوله را تعیین کنیم. برای حرکت دادن گلوله از movecenter استفاده میکنیم. این movecenter دقیقا چه کاری انجام میده؟؟ مقداری که به عنوان ورودی میگیره را چطوری ازش استفاده میکنه؟؟


QRect CannonField::shotRect() const
 {
     const double gravity = 4;

     double time = timerCount / 20.0;
     double velocity = shootForce;
     double radians = shootAngle * 3.14159265 / 180;

     double velx = velocity * cos(radians);
     double vely = velocity * sin(radians);
     double x0 = (barrelRect.right() + 5) * cos(radians);
     double y0 = (barrelRect.right() + 5) * sin(radians);
     double x = x0 + velx * time;
     double y = y0 + vely * time - 0.5 * gravity * time * time;

     QRect result(0, 0, 6, 6);
     result.moveCenter(QPoint(qRound(x), height() - 1 - qRound(y)));
    
     return result;
 }

سوال دیگه هم این که qround در Qpoint چه کاری انجام میده؟؟ اصلا برای چی از Qpoint استفاده میکنیم؟؟

----------


## حامد مصافی

movecenter:
مختصات یک نقطه را می گیرد و QRect را طوری جابه جا می کند که مرکز QRect منطبق بر نقطه مزبور باشد.




> سوال دیگه هم این که qround در Qpoint چه کاری انجام میده؟؟


qRound در QPoint نیست. این یک تابع استاتیک در QtGlobal است که به منظور حذف قسمت بعد از ممیز در اعداد کاربرد دارد.





> اصلا برای چی از Qpoint استفاده میکنیم؟؟


چون پارامتر ورودی تابع movecenter از نوع QPoint است. به بیان دیگر یک QPoint به منظور ذخیره سازی مختصات یک نقطه (با خصوصیات x و y) کاربرد دارد.

----------


## nasrin55

در تابع moveshot زیر ، این خط
region= region.unite(shotR)
 چه معنی می دهد؟


void CannonField::moveShot()
 {
     QRegion region = shotRect();
     ++timerCount;

     QRect shotR = shotRect();

     if (shotR.x() > width() || shotR.y() > height()) {
         autoShootTimer->stop();
     } else {
         region = region.unite(shotR);
     }
     update(region);
 }

----------


## حامد مصافی

اول اینکه QRegion به منظور مشخص کردن یک ناحیه در Qt استفاده می شود.
تابع unite دو ناحیه را با هم ادغام می کند و اجتماع آن دو را بر می گرداند. برای مثال در خط فوق الذکر توسط شما اجتماع shotR با region در region قرار می گیرد.

----------


## nasrin55

با تشکر بسیار از شما که سوالات  من را جواب دادید.

یه سوال دیگه داشتم اینکه در تابع زیر intersects برای چی به کار رفته؟؟ درسته که میخواسته وقتی گلوله به هدف برخورد می کنه emit سیگنال hit را ، ولی چرا از intersect استفاده کرده؟؟ آیا میخواد محل برخورد گلوله با هدف را مشخص کنه؟؟ 



 void CannonField::moveShot()
 {
     QRegion region = shotRect();
     ++timerCount;

     QRect shotR = shotRect();

     if (shotR.intersects(targetRect())) {
         autoShootTimer->stop();
         emit hit();
     } else if (shotR.x() > width() || shotR.y() > height()) {
         autoShootTimer->stop();
         emit missed();
     } else {
         region = region.unite(shotR);
     }
     update(region);
 }

----------


## حامد مصافی

تابع intersects مشخص می کند که یک QRect با دیگری تداخل دارد یا خیر.
در مثال شما در صورتی که targetRect() با shotR تداخل داشته باشد (حداقل یک نقطه مشترک داشته باشند دستورات if اجرا خواهند شد.

----------


## lvlina_r

1>moc_player.obj : error LNK2019: unresolved external symbol "public: void __thiscall Player::hiting(int)" (?hiting@Player@@QAEXH@Z) referenced in function "public: virtual int __thiscall Player::qt_metacall(enum QMetaObject::Call,int,void * *)" (?qt_metacall@Player@@UAEHW4Call@QMetaObject@@HPAP  AX@Z)
1>debug\t13.exe : fatal error LNK1120: 1 unresolved externals
این ارور لینکی یعنی چه، وقتی slot hitting را بر می دارم دیگه این error را نمی ده.......

#ifndef BAZIKON_H
#define BAZIKON_H
#include <QWidget>
QT_BEGIN_NAMESPACE
class QLCDNumber;
class LCDRange;
QT_END_NAMESPACE
class Player : public QWidget
{
      Q_OBJECT
public :
    Player( QWidget *parent = 0);
     void init();
    QLCDNumber *shotsLeft ;
    QLCDNumber *hits;
    LCDRange  *angel;
    LCDRange *forse;
    
public slots:
      void hiting();

signals:
    void hitGame();

};

#endif

----------


## حامد مصافی

clean and rebuild project

----------


## lvlina_r

بازم ERROR می ده...... :خیلی عصبانی:

----------


## حامد مصافی

پس احتمالاً جایی که Player را تعریف کرده اید این slot را پیاده سازی نکرده اید.

----------


## lvlina_r

اره، comment کرده بودم، ممنون....، داشتم روانی می شدما...

----------


## lvlina_r

و یه سوال بازم فکر می کنم ساده و خنده دار
چرا این تابع
 void CannonField::newTarget()
 {
     static bool firstTime = true;

     if (firstTime)
     {
         firstTime = false;
         QTime midnight(0, 0, 0);
        qsrand(midnight.secsTo(QTime::currentTime()));
     }
     target = QPoint(200 + qrand() % 190, 10 + qrand() % 255);
     update();
 }

این error ها را میده، قبلا نمیداد....

1>.\cannonfield.cpp(72) : error C2079: 'midnight' uses undefined class 'QTime'
1>.\cannonfield.cpp(72) : error C2078: too many initializers
1>.\cannonfield.cpp(73) : error C2228: left of '.secsTo' must have class/struct/union
1>        type is 'int'
1>.\cannonfield.cpp(73) : error C2027: use of undefined type 'QTime'
1>        d:\qt\4.4.3\include\qtgui\../../src/gui/kernel/qwindowdefs.h(79) : see declaration of 'QTime'
1>.\cannonfield.cpp(73) : error C3861: 'currentTime': identifier not found

----------


## حامد مصافی

#include <qdatetime.h>

----------


## lvlina_r

> #include <qdatetime.h>


این include شده، ولی error می ده

----------


## حامد مصافی

> این include شده، ولی error می ده


لا ممکن. کل کد فایل را درج کنید.

----------


## lvlina_r

#include <QDateTime>
 #include <QMouseEvent>
 #include <QPaintEvent>
 #include <QPainter>
 #include <QTimer>

 #include <math.h>
 #include <stdlib.h>

 #include "cannonfield.h"

 CannonField::CannonField(QWidget *parent)
     : QWidget(parent)
 {
     currentAngle = 45;
     currentForce = 0;
     timerCount = 0;
     autoShootTimer = new QTimer(this);
     connect(autoShootTimer, SIGNAL(timeout()), this, SLOT(moveShot()));
     shootAngle = 0;
     shootForce = 0;
     target = QPoint(0, 0);
     gameEnded = false;
     barrelPressed = false;
     setPalette(QPalette(QColor(250, 250, 200)));
     setAutoFillBackground(true);
     newTarget();
 }

 void CannonField::setAngle(int angle)
 {
     if (angle < 5)
         angle = 5;
     if (angle > 70)
         angle = 70;
     if (currentAngle == angle)
         return;
     currentAngle = angle;
     update(cannonRect());
     emit angleChanged(currentAngle);
 }

 void CannonField::setForce(int force)
 {
     if (force < 0)
         force = 0;
     if (currentForce == force)
         return;
     currentForce = force;
     emit forceChanged(currentForce);
 }

 void CannonField::shoot()
 {
     if (isShooting())
         return;
     timerCount = 0;
     shootAngle = currentAngle;
     shootForce = currentForce;
     autoShootTimer->start(5);
     emit canShoot(false);
 }

 void CannonField::newTarget()
 {
     static bool firstTime = true;

     if (firstTime)
     {
         firstTime = false;
         QTime midnight(0, 0, 0);
        qsrand(midnight.secsTo(QTime::currentTime()));
     }
     target = QPoint(200 + qrand() % 190, 10 + qrand() % 255);
     update();
 }

 void CannonField::setGameOver()
 {
     if (gameEnded)
         return;
     if (isShooting())
         autoShootTimer->stop();
     gameEnded = true;
     update();
 }

 void CannonField::restartGame()
 {
     if (isShooting())
         autoShootTimer->stop();
     gameEnded = false;
     update();
     emit canShoot(true);
 }

 void CannonField::moveShot()
 {
     QRegion region = shotRect();
     ++timerCount;

     QRect shotR = shotRect();

     if (shotR.intersects(targetRect())) {
         autoShootTimer->stop();
         emit hit();
         emit canShoot(true);
     } else if (shotR.x() > width() || shotR.y() > height()
                || shotR.intersects(barrierRect())) {
         autoShootTimer->stop();
         emit missed();
         emit canShoot(true);
     } else {
         region = region.unite(shotR);
     }
     update(region);
 }

 void CannonField::mousePressEvent(QMouseEvent *event)
 {
     if (event->button() != Qt::LeftButton)
         return;
     if (barrelHit(event->pos()))
         barrelPressed = true;
 }

 void CannonField::mouseMoveEvent(QMouseEvent *event)
 {
     if (!barrelPressed)
         return;
     QPoint pos = event->pos();
     if (pos.x() <= 0)
         pos.setX(1);
     if (pos.y() >= height())
         pos.setY(height() - 1);
     double rad = atan(((double)rect().bottom() - pos.y()) / pos.x());
     setAngle(qRound(rad * 180 / 3.14159265));
 }

 void CannonField::mouseReleaseEvent(QMouseEvent *event)
 {
     if (event->button() == Qt::LeftButton)
         barrelPressed = false;
 }

 void CannonField::paintEvent(QPaintEvent * /* event */)
 {
     QPainter painter(this);

     if (gameEnded) {
         painter.setPen(Qt::black);
         painter.setFont(QFont("Courier", 48, QFont::Bold));
         painter.drawText(rect(), Qt::AlignCenter, tr("Game Over"));
     }
     paintCannon(painter);
     paintBarrier(painter);
     if (isShooting())
         paintShot(painter);
     if (!gameEnded)
         paintTarget(painter);
 }

 void CannonField::paintShot(QPainter &painter)
 {
     painter.setPen(Qt::NoPen);
     painter.setBrush(Qt::black);
     painter.drawRect(shotRect());
 }

 void CannonField::paintTarget(QPainter &painter)
 {
     painter.setPen(Qt::black);
     painter.setBrush(Qt::red);
     painter.drawRect(targetRect());
 }

 void CannonField::paintBarrier(QPainter &painter)
 {
     painter.setPen(Qt::black);
     painter.setBrush(Qt::yellow);
     painter.drawRect(barrierRect());
 }

 const QRect barrelRect(30, -5, 20, 10);

 void CannonField::paintCannon(QPainter &painter)
 {
     painter.setPen(Qt::NoPen);
     painter.setBrush(Qt::blue);

     painter.save();
     painter.translate(0, height());
     painter.drawPie(QRect(-35, -35, 70, 70), 0, 90 * 16);
     painter.rotate(-currentAngle);
     painter.drawRect(barrelRect);
     painter.restore();
 }

 QRect CannonField::cannonRect() const
 {
     QRect result(0, 0, 50, 50);
     result.moveBottomLeft(rect().bottomLeft());
     return result;
 }

 QRect CannonField::shotRect() const
 {
     const double gravity = 4;

     double time = timerCount / 20.0;
     double velocity = shootForce;
     double radians = shootAngle * 3.14159265 / 180;

     double velx = velocity * cos(radians);
     double vely = velocity * sin(radians);
     double x0 = (barrelRect.right() + 5) * cos(radians);
     double y0 = (barrelRect.right() + 5) * sin(radians);
     double x = x0 + velx * time;
     double y = y0 + vely * time - 0.5 * gravity * time * time;

     QRect result(0, 0, 6, 6);
     result.moveCenter(QPoint(qRound(x), height() - 1 - qRound(y)));
     return result;
 }

 QRect CannonField::targetRect() const
 {
     QRect result(0, 0, 20, 10);
     result.moveCenter(QPoint(target.x(), height() - 1 - target.y()));
     return result;
 }

 QRect CannonField::barrierRect() const
 {
     return QRect(145, height() - 100, 15, 99);
 }

 bool CannonField::barrelHit(const QPoint &pos) const
 {
     QMatrix matrix;
     matrix.translate(0, height());
     matrix.rotate(-currentAngle);
     matrix = matrix.inverted();
     return barrelRect.contains(matrix.map(pos));
 }

 bool CannonField::isShooting() const
 {
     return autoShootTimer->isActive();
 }

 QSize CannonField::sizeHint() const
 {
     return QSize(400, 300);
 }

----------


## lvlina_r

connect(B1->Shoot, SIGNAL(clicked()),
         this, SLOT(fire(B1)));

void GameBoard::fire(Player * B)
 {
     if (cannonField->gameOver() || cannonField->isShooting())
         return;
     B->shotsLeft->display(B->shotsLeft->intValue() - 1);
     cannonField->shoot();
 }
آیا کد بالا درسته، یعنی ای connect باعث می شه slot با پارامتر B1 به fire ()بره؟؟؟؟

----------


## حامد مصافی

خیر، امضاها یکسان نیستند؛ نام پارامتر نباید قید شود.

----------


## nasrin55

کسی میدونه که تابع setsizepolicy دقیقا چه کاری را انجام میده؟
و متغیرهای درونش چه فایده ای دارند؟
من توی یه مثال این خط را حذف کردم ولی برنامه هیچ تغییری نکرد؟

label->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);

پس گذاشتن اون چه فایده ای داره؟؟

----------


## حامد مصافی

رفتار پیش فرض ظاهر شی را تغییر می دهد.

برای مثال اگر شما یک لیبل را به همراه یک textbox در یک VerticalLayout قرار دهید به طور پیش فرض هر کدام از آنها نصف فضای موجود را در اختیار خواهند گرفت. به همین دلیل نیازمند خطی مانند خط فوق خواهید بود. برای مشاهده نتیجه حاصل از حذف خط فوق فرم را کمی بزرگ تر کنید. 
برای مشاهده جز خصوصیات QSizePolicy این لینک را ببینید.

----------


## Nima_NF

دوستان لطفا سوالات خود را در تاپیک های جداگانه و با عنوان مناسب بپرسید. کل این بخش برای سوالات Qt هست.

موفق باشید

----------

