تبلیغات
Qt Developer Blog - Basic Qt tutorial(mines)-part 2
 
Qt Developer Blog
کیوتی ساده و آسان برای همه
                                                        
درباره وبلاگ

در این وبلاگ کیوتی که مجموعه ای از کلاس ها برای برنامه نویسی دلپذیر تر با سی پلاس پلاس هست آموزش داده میشود
مدیر وبلاگ : سعید دادخواه
نظرسنجی
آموزش ها به چه صورتی باشد






آمار وبلاگ
  • کل بازدید :
  • بازدید امروز :
  • بازدید دیروز :
  • بازدید این ماه :
  • بازدید ماه قبل :
  • تعداد نویسندگان :
  • تعداد کل پست ها :
  • آخرین بازدید :
  • آخرین بروز رسانی :
سه شنبه 30 فروردین 1390 :: نویسنده : علی میریان
سلام.
در قسمت قبل صفحه ی بازی رو به صورت انتزاعی طراحی کردیم و الان وقت این رسیده که ظاهرش رو پیاده سازی کنیم، و رویدادهای مربوطه رو کنترل کتیم. در این قسمت صفحه ی بازی رو رسم می کنیم و در قسمت بعد، رویداد کلیک موس بر روی صفحه ی بازی رو مدیریت می کنیم.
کلا توی Qt هر موقع بخوایم روی سطح یک ویدجت چیزی بکشیم، باید با رویداد paintEvent کار کنیم. paintEvent در واقع یه تابع هست که، هر موقع که نیاز باشه ویدجت دوباره کشیده بشه(مثلا وقتی ویدجت جابجا بشه یا مینیمایز یا ماکسیمایز بشه و...)  و یا هر موقع که ما بخوایم(از طریق صدا زدن تابع update) به صورت اتوماتیک صدا زده میشه و ما میتونیم با بازنویسی این رویداد، اون جوری که دوست داریم ویدجت رو نقاشی کنیم.
پس ما تابع PaintEvent رو بازنویسی میکنیم تا بسته به اینکه صفحه ی بازی در چه وضعیتیه، اون رو ترسیم کنیم. و البته لازمه که هر موقه که تغییری توی صفحه ی بازی ایجاد شد، صفحه رو مجددا ترسیم کنیم(update کنیم).
یک متغییر  بولین به اسم lost در نظر میگیریم و در ابتدای کار مقدارش رو false می کنیم و تا وقتی بازی رو نباختیم، false هستش و اگه بازنده بشیم، اون رو true  میکنیم. این کار رو می کنیم چون نحوه ترسیم صفحه ی بازی بستگی به این داره که بازی ادامه داره، یا باختیم. در تابع paintEvent که کدش رو در زیر آوردم، بسته به مقدار lost، صفحه رو ترسیم می کنیم. توضیحات کد رو بعد از کد خواهم گفت.


void MinesBoard::paintEvent(QPaintEvent *e){   
       QPainter painter(this);
       painter.setPen(QColor(Qt::gray));   
       painter.setRenderHint(QPainter::Antialiasing);   
       painter.setFont(QFont("tahoma",CELL_LENGTH/2));   
    for(int i=0;i<=size; i++)// draw horizontal lines
               painter.drawLine(QPoint(0,i*CELL_LENGTH),QPoint(size*CELL_LENGTH,i*CELL_LENGTH));
    for(int i=0;i<=size; i++)// draw vertical lines
               painter.drawLine(QPoint(i*CELL_LENGTH,0),QPoint(i*CELL_LENGTH,size*CELL_LENGTH));   
    if(!lost)    {       
        for(int i=0; i<size; i++)           
            for(int j=0; j<size; j++)            {               
                switch(currentState[i][j])                {
                case notChecked:                   
                                       painter.drawPixmap(j*CELL_LENGTH,i*CELL_LENGTH,CELL_LENGTH,CELL_LENGTH,*cellPixmap);
                    break;               
                case markedAsMine:                   
                                       painter.drawPixmap(j*CELL_LENGTH,i*CELL_LENGTH,CELL_LENGTH,CELL_LENGTH,*mineCellPixmap);                                        break;               
                case markedAsUnkown:                   
                                       painter.drawPixmap(j*CELL_LENGTH,i*CELL_LENGTH,CELL_LENGTH,CELL_LENGTH,*unknownCellPixmap);                                        break;               
                case checked:
                    if( board[i][j] != 0)                    {                       
                        switch(board[i][j])// set color of QPaniter's pen according to the board[i][j]                        {
                            case 1:                            painter.setPen(QColor(Qt::green));                           
                                break;                       
                            case 2:                            painter.setPen(QColor(Qt::green).darker());                           
                                break;                       
                            case 3:                            painter.setPen(QColor(Qt::blue));                           
                                break;                       
                            case 4:                            painter.setPen(QColor(Qt::blue).darker());                           
                                break;
                            case 5:                            painter.setPen(QColor(Qt::red));
                                break;                       
                            case 6:                       
                            case 7:                       
                            case 8:                            painter.setPen(QColor(Qt::red).darker());                           
                                break;                       
                        }                       
                                               painter.drawText(QRect(j*CELL_LENGTH,i*CELL_LENGTH,CELL_LENGTH,CELL_LENGTH),Qt::AlignCenter,QString::number(board[i][j]));
                    }
                    break;
                }
            }
        }
 }

QPainter ابزاریه که باهاش میتونیم روی سطح ویدجت ترسیم کنیم. (توضیحات کامل راجع به QPainter و انواع توابع ترسیمیش رو میتونید از اینجا بخونید)
ابتدا با رنگ خاکستری خط های افقی و عمودی رو میکشیم تا خونه های جدول شکل بگیره. اگر هنوز نباخته باشیم، برای ترسیم هر خونه، 2 حالت امکان داره. یا خونه قبلا باز شده(که قطعا  مین زیرش نبوده چون هنوز نباختیم)، که در این حالت عدد مربوط به اون خونه رو داخلش مینویسیم(با استفاده از تابع drawText از QPainter) و یا اینکه خونه هنوز باز نشده که خودش سه حالت داره:
  1. خونه به عنوان "مین" علامت گذاری شده باشه Cell_mine
  2. خونه به عنوان "نامعلوم" علامت گذاری شده باشه(همون که یه علامت سوال نشون میده) Cell_unknown
  3. خونه علامت گذاری نشده باشه(notChecked باشه) Cell
من این 3 تا عکسی که میبینید رو برای این سه نوع خونه ی جدول بازی در نظر گرفتم. به ازای همه ی خونه هایی که هنوز باز نشده، بسته به این که وضعیت اون خونه کدوم باشه، یکی از این عکس ها رو با استفاده از تابع drawPixmap از کلاس QPainter در محل اون خونه رسم می کنیم. برای این منظور، سه اشاره گر به QPixmap با اسم های cellPixmap، mineCellPixmap و UnknownCellPixmap به کلاس MinesBoard اضافه کردیم و در تابع سازنده 3 تا Qpixmap میسازیم و مسیر فایل اون سه تا عکس در نظر گرفته شده رو بهشون میدیم. نکته ای که وجود داره اینه که میتونیم عکس ها رو در کنار فایل اجرایی برنامه بگذاریم، ولی بهتره که اون ها رو به منابع برنامه (resources) اضافه کنیم تا داخل فایل اجرایی گنجونده بشه(embeded) و برنامه وابسته به فایل های عکس کنارش نباشه.(برای آشنایی با سیستم منابع یا همون resource system در Qt، داکیومنت اصلی کیوتی و یا این پست از همین وبلاگ رو بخونید)
من همیشه عادت دارم منابعی که استفاده می کنم رو بر حسب نوع دسته بندی کنم، مثلا به تصاویر یک پیشوند images/ میدم. با استفاده از ویزارد QtCreator میتونید خیلی راحت یک فایل  (qrc.) یا همون resource به پروژه اضافه کنید و با ویرایش گر منابع QtCreator اون رو ویرایش کنید و فایل های خودتون رو اضافه کنید. (اگه این تیکه رو خوب متوجه نمیشید حتما یه سر به اون لینکایی که بالا تر بهش اشاره کردم بزنید ).
QtCreator resource editor
خوب تا اینجا یک بازی مین داریم که فعلا هیچ کاری با هیچ کدوم از خونه هاش نمی تونیم انجام بدیم ولی دیدیم که چه جوری می تونیم با استفاده از QPainter و بازنویسی رویداد PaintEvent چطوری ویدجتی بسازیم که ظاهرش اون جوری که ما می خوایمه.
در نهایت ما یک شیئ از این MinesBoard میسازیم و داخل پنجره ی اصلی بازی قرار میدیم( به همراه قسمت های دیگه ی بازی مثل منو ها و...) ولی فعلا که هنوز وارد بحث پنجره ی اصلی نشدیم، برای اینکه نتیجه ی کار تا اینجا رو ببینیم، در تابع main یک شیئ از MinesBoard میسازیم و کاری به کار MinesWindow نداریم. کد تابع main:

int main(int argc, char *argv[])
{

       QApplication a(argc, argv);   
    //MinesWindow w;

       MinesBoard w;
       w.show();   
    return
a.exec();
}

اگه برنامه رو اجرا بکنید یه چیزی شبیه این می بینید:
part2_screenshot
کد مربوط به این قسمت رو میتونید از اینجا بردارید




نوع مطلب :
برچسب ها :