PDA

View Full Version : پاك كردن اشكال گرافيكي



Ali.110
شنبه 12 اردیبهشت 1388, 22:11 عصر
با سلام :

بعد از ترسيم اشكال گرافيكي و نمايش آنها وقتي كه برنامه در حال اجرا است

آنها را به وسيله ي Point.x و Point.y جابجا مي كنم ولي آن شكلها به طور پيوسته

رسم مي شود مي خواهم اين اشكالي كه در بافر نقاط باقي مي مانند پاك شوند

و فقط يك شكل جابجا شود .

با تشكر.

Nima_NF
یک شنبه 13 اردیبهشت 1388, 01:20 صبح
اگر قطعه کد خود را در اینجا قرار دهید دوستان بهتر و بیشتر می توانند کمک کنند.

رسم اشکال گرافیکی باید در WM_PAINT یا همان OnDraw / OnPaint انجام شود. تا هر گاه نقطه مورد نظر رسم شکل عوض می شود کل تصویر refresh شود و شکل جدید رسم شود.
اگر در سایر توابع تغییر مکان انجام می شود باید InvalidateRect را فراخوانی کنید تا WM_PAINT فراخوانی شود.

Ali.110
یک شنبه 13 اردیبهشت 1388, 12:39 عصر
با سلام :

من مي خواهم بوسيله ي موشواره شكل را جابجا كنم و قبلا از OnPaint و Invalidate استفاده

كرده ام ولي آنها اين كار را به خوبي انجام نمي دهند اگر اين كار بوسيله ي InvalidateRect به

خوبي انجام مي شود لطفا در مورد ...LPCRECT توضيح دهيد.

با تشكر .

Nima_NF
یک شنبه 13 اردیبهشت 1388, 13:29 عصر
InvalidateRect هم اگر LPCRECT را NULL قرار دهید همان Invalidate هست .در اینجا فرقی ندارند. شما باید در رویداد موس Invalidate را فراخوانی کنید (با پارامتر TRUE) و رسم را در OnPaint انجام دهید (با مختصات جدید)

شما قطعه کد خود را قرار ندادید تا بگم کجای آن را اشتباه کرده اید یا باید تغییر دهید...

Sir.Achilles
شنبه 19 اردیبهشت 1388, 23:57 عصر
InvalidateRect هم اگر LPCRECT را NULL قرار دهید همان Invalidate هست .در اینجا فرقی ندارند. شما باید در رویداد موس Invalidate را فراخوانی کنید (با پارامتر TRUE) و رسم را در OnPaint انجام دهید (با مختصات جدید)

شما قطعه کد خود را قرار ندادید تا بگم کجای آن را اشتباه کرده اید یا باید تغییر دهید...

با سلام . من هم دقیقا قصد نوشتن این برنامه رو دارم . روشی که در نظر دارم اینه که وقتی یک box کشیده میشه box قبلی با رنگ پس زمینه رنگ بشه . مشکلی که در پیاده سازیه این روشش دارم اینه که نمیدونم کد رنگ پس زمینه چیه . البته مشکل اصلی اینه که ویژوال ++c رو بلد اصولی بلد نیستم و در کنار ++c دارم یاد میگیرم . ایده ی شما هم خوب به نظر میاد و من خواستم امتحانش کنم که نتونستم . با Invalidate کل صفحه refresh میشه . و اصلا مستطیلی نشون داده نمیشه . اگر میشه یکم پایه ای تر با فرض اینکه من خیلی مبتدی هستم توضیح بدید . در ضمن نظرتون راجع به راه حل خودم چیه ؟ حتی این فکر به نظرم رسید که رنگ dialog رو عوض کنم که باز از کداش سر در نیاوردم .

Nima_NF
یک شنبه 20 اردیبهشت 1388, 01:47 صبح
برای گرفتن رنگ پس زمینه از GetBkColor استفاده کنید :




void CMyView::OnDraw(CDC* pDC)
{
COLORREF backColor = GetBkColor();


CBrush brushBg(backColor);
CBrush* pOldBrush = pDC->SelectObject(&brushBg);

pDC->Rectangle(10, 10, 30, 30);

pDC->SelectObject(pOldBrush);
pDC->SelectObject(pOldPen);
}




در مثال فوق همه چیز باید در همان OnDraw رسم شود. پس هرجا Invalidate را فراخوانی کنید این OnDraw اجرا می شود. شما نباید تنها در سایر توابع رسم شکل انجام دهید، اگر هم انجام می دهید باید در این تابع و یا توابع مشابه در سایر کلاس های (OnPaint و ..) همان شکل رسم شود تا بعد از refresh پاک نشود.

همیشه کدهای خودتان را قرار دهید تا بتوانیم راحت تر مشکل کار شما را بگوییم و به حدس روی نیاوریم.

Sir.Achilles
دوشنبه 21 اردیبهشت 1388, 00:18 صبح
برای گرفتن رنگ پس زمینه از GetBkColor استفاده کنید :




void CMyView::OnDraw(CDC* pDC)
{
COLORREF backColor = GetBkColor();


CBrush brushBg(backColor);
CBrush* pOldBrush = pDC->SelectObject(&brushBg);

pDC->Rectangle(10, 10, 30, 30);

pDC->SelectObject(pOldBrush);
pDC->SelectObject(pOldPen);
}




در مثال فوق همه چیز باید در همان OnDraw رسم شود. پس هرجا Invalidate را فراخوانی کنید این OnDraw اجرا می شود. شما نباید تنها در سایر توابع رسم شکل انجام دهید، اگر هم انجام می دهید باید در این تابع و یا توابع مشابه در سایر کلاس های (OnPaint و ..) همان شکل رسم شود تا بعد از refresh پاک نشود.

همیشه کدهای خودتان را قرار دهید تا بتوانیم راحت تر مشکل کار شما را بگوییم و به حدس روی نیاوریم.


با سلام . خیلی ممنون از پاسختون . گفتید که همه چیز رو در OnDraw بنویسم . این OnDraw کجاست . تو Event ها نبود . (گفتم خیلی مبتدیم ). چون کدتون رو تو mosemove یا هر جای دیگه میزدم error می داد . اصلا چرا باید فقط تو اون قسمت باشه . چیزی که من متوجه شدم اینه که COLORREF یعنی تعریف یک متغیر از نوع رنگ که برابر رنگ پس زمینه قرارش میدیم. میشه بیشتر توضیح بدید؟!
درباره ی ایده ی refresh دادن من کدم رو براتون قرار دادم . اگر منظورتون این که بازم مستطیلی نمایش داده نمیشود. البته کلا این ایده زیاد قشنگ نیست چون وقتی صفحه refresh میشه برنامه حالت زیبایی نداره.
مطلب بعد این که یک راه حل دیگه هم اینه که رنگ پس زمینه رو عوض کنم تا اصلا RGB اون دست خودم باشه . اگر درست فهمیده باشم باید از SetBkColor استفاده کنم . تو msdn هم search کردم ولی بازم چیز زیادی نفهمیدم . بازم اگر درست فهمیده باشم Onpaint یه چیزی مثل رخداد FormLoad هست . پس باید بشه تو این قسمت صفحه رو با این تابع رنگ کرد ولی چه ج. اگر کمک کنید ممنون میشم .
مشکل اینجاست که من دارم برای انجام پروژه ای ویژوال ++c رو خودآموزی میکنم . درس اصلیمون
++c هست و ویژوال رو پایه ای بلد نیستم.




void CTamrinBOXDlg::OnPaint()
{
CClientDC dc(this);
CBrush brush(RGB(245,0,120));
dc.SelectObject(&brush);
dc.Rectangle(i,j,i+50,j+25);

if (IsIconic())
{

CPaintDC dc(this); // device context for painting


SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;

// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{

CDialog::OnPaint();
}
}

[/RIGHT]







void CTamrinBOXDlg::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default


if(click==1)
{
i=point.x;
j=point.y;
CClientDC dc(this);
CBrush brush(RGB(245,0,120));
dc.SelectObject(&brush);
dc.Rectangle(point.x,point.y,point.x+50,point.y+25 );
Invalidate();


}//end if

}

[/RIGHT]



متغیر click در LBUTTONUP مقدار 1 و در LBUTTONDOWN مقدار 0 میگیرد

Nima_NF
دوشنبه 21 اردیبهشت 1388, 04:21 صبح
همانطور که گفتم با قرار دادن قطعه کد خودتان راحت تر به نتیجه خواهید رسید .


. این OnDraw کجاست . تو Event ها نبود .این بستگی به این دارد که در نمای view هستید یا در نمای یک دیالوگ. در دیالوگ که همان مثال شما هست همان OnPaint ارسال می شود (یعنی همان پیام WM_PAINT).

فقط نکته ای وجود دارد، در OnPaint نمی توانید از هر نوع تخصیص DC برای رسم استفاده کنید، شما باید از CPaintDC استفاده کنید نه CClientDC . (چون با فراخوانی CPaintDC دو تابع BeginPaint و EndPaint اتومات فراخوانی می شوند که یک نیاز برای رسم در این پیام هست ).

پس فقط کافی هست CPaintDC را در بالا تعریف کنید (تنها یک مرتبه، پس دومی را پاک کنید):



void CTamrinBOXDlg::OnPaint()
{
CPaintDC dc(this); // add this
CBrush brush(RGB(245,0,120));
dc.SelectObject(&brush);
dc.Rectangle(i,j,i+50,j+25);

if (IsIconic())
{
// CPaintDC dc(this); <--- remove this

SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;

// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}

به این شکل با فراخوانی Invalidate برنامه درست کار می کند. روش کار همین طور هست.

- حالا OnPaint یا همان پیام WM_PAINT چه هست؟
هر وقت برنامه نیاز به refresh کردن داشت، این تابع/پیام اجرا می شود. مثلا وقتی پنجره روی پنجره شما می آید یا حتی کرسر mouse روی آن می رود و نیاز مجدد به رسم دارد.


چیزی که من متوجه شدم اینه که COLORREF یعنی تعریف یک متغیر از نوع رنگ که برابر رنگ پس زمینه قرارش میدیم. میشه بیشتر توضیح بدید؟!خیلی ساده یک ساختار یک متغیر عددی برای نگهداری 3 رنگ شما. برای این کار از ماکرو RGB استفاده کنید، مثلا:



COLORREF red = RGB(255,0,0);

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


مطلب بعد این که یک راه حل دیگه هم اینه که رنگ پس زمینه رو عوض کنم تا اصلا RGB اون دست خودم باشه . اگر درست فهمیده باشم باید از SetBkColor استفاده کنم



تغییر رنگ دیالوگ ها به همین راحتی نیست و نباید از SetBkColor یا GetBkColor استفاده کنید. شما باید در پیام WM_CTLCOLORDLG یا همان OnCtlColor (در بخش messeges) رنگ دیالوگ را بگیرید، ذخیره کنید و استفاده کنید یا کلا تغییر دهید و آن را return کنید تا رنگ پس زمینه شود.

توضیحات در این لینک ها:
http://barnamenevis.org/forum/showthread.php?t=95523
http://barnamenevis.org/forum/showthread.php?t=74998

تذکر: اگر قرار هست محتویات داخل یک شکل کلا همان زنگ پس زمینه باشد، اصلا نیاز به این کار های نیست، فقط کافیست که قبل از رسم، Brush ما از نوع NULL_BRUSH باشد (با CreateStockObject):



CPaintDC dc(this);
CBrush brush;
brush.CreateStockObject(NULL_BRUSH);

dc.SelectObject(&brush);
dc.Rectangle(10,10,50,25);

Sir.Achilles
جمعه 08 خرداد 1388, 02:30 صبح
خیلی ممنون از کمکتون . من با استفاده از onpaint تونستم برنامه رو بنویسم ولی همون طوذر که گفتم این روش قشنگی نیست و اگر بتوان رنگ پس زمینه رو تغییر داد یا از پس زمینه رنگ گرفت . در رابطه با تغییر رنگ پس زمینه که گفته بودید سخته تاپیک مورد نظر رو نگاه کردم و کدی که در ارتباط با یه Dialog box خاکستری گذاشته بودن رو امتحان کردم ولی error گرفتم . در ارتباط با گرفتن رنگ از پس زمینه میشه بیشتر کمک کنید.
از GetBkColor چطور باید در CTLColor استفاده کنم ؟ منظور از بخش messages چیه و مگه CTLColor مسیج برمیگردونن .

Nima_NF
جمعه 08 خرداد 1388, 17:56 عصر
قبل از هر چیز مجددا تاکید می کنم که تابع GetBkColor یا SetBkColor را کلا فراموش کنید، این تابع آن چیزی نیست که شما فکر می کنید و برای تغییر رنگ هم استفاده نمی شود، بلکه برای تغیر رنگ پس زمینه نوشته ها هست و آن هم در نمای client-area .

شما در برنامه نویسی همواره با پیام ها کار می کنید، اگر کسی بگوید فلان پیام را override کنید شما چه کار می کنید؟

در هر حال این هم توضیحات کامل:
به نمای طراحی دیالوگ بروید (کنرتلی را انتخاب نکنید، فقط خود دیالوگ)، سپس در پنجره properties چند آیکن وجود دارد، یکی از آن ها با نام Messages هست.
بعد از کلیک کردن بر روی آن در قسمت پیام WM_CTLCOLOR تابع با نام OnCtlColor را بسازید و کد زیر را در آن بنویسید:




HBRUSH CMFC_MyDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

if (nCtlColor == CTLCOLOR_DLG )
hbr = (HBRUSH)redBrush;

return hbr;
}

تابع فوق ابتدا hbr را می گیرد (همان رنگ اصلی کنترل یا دیالوگ)، سپس اگر دیالوگ بود redBrush که همان رنگی هست که مد نظر شما هست را جایگزین زنگ پیش فرض می کند (اگر قرار هست رنگ پس زمینه نوشته ها و کنترل ها هم عوض شود کلا if را حذف کنید و فقط redBrush را در هر حالت در hbr کپی کنید)

حال نیاز هست تا این brush را بسازید، متغیری از کلاس CBrush به شکل زیر در فایل .h کلاس دیالوگ بسازید:



CBrush redBrush;

سپس در قسمت OnInitDialog قطعه کد زیر را اضافه کنید تا brush را بسازد:



redBrush.CreateSolidBrush(RGB(255,50,50));