Related
This is my code. I hope it can draw a circle when users press button. The circel is centered around the point where the mouse key pressed. But the program doesn't run as expected. It clears the pre-circles and draws a new circle. Are there some functions to solve this problem?
My codes:
#include <gtk/gtk.h>
static void do_drawing(cairo_t *);
struct {
int count;
double coordx[100];
double coordy[100];
} glob;
static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,
gpointer user_data)
{
do_drawing(cr);
return FALSE;
}
static void do_drawing(cairo_t *cr)
{
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_set_line_width(cr, 0.5);
if(glob.count)
{
cairo_set_font_size(cr, 20);
cairo_new_sub_path(cr);
cairo_arc(cr, glob.coordx[glob.count-1], glob.coordy[glob.count-1], 20, 0, 2*G_PI);
cairo_move_to(cr, glob.coordx[glob.count-1]-3, glob.coordy[glob.count-1] + 7);
cairo_show_text(cr, "i");
cairo_stroke(cr);
}
}
static gboolean clicked(GtkWidget *widget, GdkEventButton *event,
gpointer user_data)
{
if (event->button == 1) {
glob.coordx[glob.count] = event->x;
glob.coordy[glob.count++] = event->y;
gtk_widget_queue_draw(widget);
}
return TRUE;
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *darea;
glob.count = 0;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
darea = gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER(window), darea);
gtk_widget_add_events(darea, GDK_BUTTON_PRESS_MASK);
g_signal_connect(G_OBJECT(darea), "draw",
G_CALLBACK(on_draw_event), NULL);
g_signal_connect(window, "destroy",
G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(darea, "button-press-event",
G_CALLBACK(clicked), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 400, 300);
gtk_window_set_title(GTK_WINDOW(window), "Lines");
gtk_widget_show_all(window);
gtk_main();
return 0;
}
I know the gtk_widget_queue_draw(widget) will redraw the GtkDrawingArea entirely, So which function can replace it? I have another question: If I wan to draw on GtkDrawingArea, should I create cairo_t before drawing? How to create a cairo_t for GtkDrawingArea?
CURRENT UI
NEW UI
I want to change the background color of a button in MFC application. I have created my user interface(UI) in MFC .I have added every controls from the toolbox.But the problem is that i want to change the background and foreground properties of a button and window.How it is possible?
please help me to change the properties of controls in MFC.In windows application we can directly change the properties in the property window.
But in the case of MFC application that is not possible.
please help me..i have not enough experience in MFC application development.....
Thanks in advance......................
code from dialer.h
class CButtonDialer : public CButton
{
// Construction
public:
CButtonDialer();
// Attributes
public:
CButton m_button;
// CButton IDC_KEY_1;
CBrush m_brush;
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CButtonDialer)
public:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
// Implementation
public:
virtual ~CButtonDialer();
// Generated message map functions
protected:
//{{AFX_MSG(CButtonDialer)
// NOTE - the ClassWizard will add and remove member functions here.
//}}AFX_MSG
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
CFont m_FontLetters;
CMapStringToString m_map;
HTHEME m_hTheme;
void OpenTheme() { m_hTheme = OpenThemeData(m_hWnd, L"Button"); }
void CloseTheme() {
if (m_hTheme) { CloseThemeData(m_hTheme); m_hTheme = NULL; }
}
DECLARE_MESSAGE_MAP()
virtual void PreSubclassWindow();
afx_msg LRESULT OnThemeChanged();
afx_msg void OnMouseMove(UINT,CPoint);
afx_msg void OnSize(UINT type, int w, int h);
};
code from dialer.cpp file
#include "stdafx.h"
#include "ButtonDialer.h"
#include "Strsafe.h"
#include "const.h"
/////////////////////////////////////////////////////////////////////////////
// CButtonDialer
CButtonDialer::CButtonDialer()
{
//255,255,255
m_brush.CreateSolidBrush(
(173, 41, 41));
m_map.SetAt(_T("1"),_T(""));
m_map.SetAt(_T("2"),_T("ABC"));
m_map.SetAt(_T("3"),_T("DEF"));
m_map.SetAt(_T("4"),_T("GHI"));
m_map.SetAt(_T("5"),_T("JKL"));
m_map.SetAt(_T("6"),_T("MNO"));
m_map.SetAt(_T("7"),_T("PQRS"));
m_map.SetAt(_T("8"),_T("TUV"));
m_map.SetAt(_T("9"),_T("WXYZ"));
m_map.SetAt(_T("0"),_T(""));
m_map.SetAt(_T("*"),_T(""));
m_map.SetAt(_T("#"),_T(""));
}
CButtonDialer::~CButtonDialer()
{
CloseTheme();
}
BEGIN_MESSAGE_MAP(CButtonDialer, CButton)
ON_WM_THEMECHANGED()
ON_WM_MOUSEMOVE()
ON_WM_SIZE()
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CButtonDialer message handlers
void CButtonDialer::PreSubclassWindow()
{
OpenTheme();
HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
LOGFONT lf;
GetObject(hFont, sizeof(LOGFONT), &lf);
lf.lfHeight = 14;
StringCchCopy(lf.lfFaceName,LF_FACESIZE,_T("Microsoft Sans Serif"));
m_FontLetters.CreateFontIndirect(&lf);
DWORD dwStyle = ::GetClassLong(m_hWnd, GCL_STYLE);
dwStyle &= ~CS_DBLCLKS;
::SetClassLong(m_hWnd, GCL_STYLE, dwStyle);
}
LRESULT CButtonDialer::OnThemeChanged()
{
CloseTheme();
OpenTheme();
return 0L;
}
void CButtonDialer::OnSize(UINT type, int w, int h)
{
CButton::OnSize(type, w, h);
}
void CButtonDialer::OnMouseMove(UINT nFlags,CPoint point)
{
CRect rect;
GetClientRect(&rect);
if (rect.PtInRect(point)) {
if (GetCapture() != this) {
SetCapture();
Invalidate();
}
}
else {
ReleaseCapture();
Invalidate();
}
CButton::OnMouseMove(nFlags, point);
}
void CButtonDialer::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC dc;
dc.Attach(lpDrawItemStruct->hDC); //Get device context object
CRect rt;
rt = lpDrawItemStruct->rcItem; //Get button rect
dc.FillSolidRect(rt,dc.GetBkColor());
dc.SetBkMode(TRANSPARENT);
CRect rtl = rt;
UINT state = lpDrawItemStruct->itemState; //Get state of the button
if (!m_hTheme) {
UINT uStyle = DFCS_BUTTONPUSH;
if ( (state & ODS_SELECTED) ) {
uStyle |= DFCS_PUSHED;
rtl.left+=1;
rtl.top+=1;
}
dc.DrawFrameControl(rt, DFC_BUTTON, uStyle);
} else {
UINT uStyleTheme = RBS_NORMAL;
if ( (state & ODS_SELECTED) ) {
uStyleTheme = PBS_PRESSED;
} else if (GetCapture()==this) {
uStyleTheme = PBS_HOT;
}
DrawThemeBackground(m_hTheme, dc.m_hDC,
BP_PUSHBUTTON, uStyleTheme,
rt, NULL);
}
CString strTemp;
GetWindowText(strTemp); // Get the caption which have been set
rtl.top += 4;
CString letters;
COLORREF crOldColor;
if (m_map.Lookup(strTemp,letters)) {
rtl.left+=15;
dc.DrawText(strTemp,rtl,DT_LEFT|DT_TOP|DT_SINGLELINE); // Draw out the caption
HFONT hOldFont = (HFONT)SelectObject(dc.m_hDC, m_FontLetters);
// Do your text drawing
rtl.left += 13;
rtl.top += 4;
rtl.right -=4;
crOldColor = dc.SetTextColor(RGB(148, 167, 70));
dc.DrawText(letters,rtl,DT_LEFT | DT_TOP | DT_SINGLELINE);
dc.SetTextColor(crOldColor);
// Always select the old font back into the DC
SelectObject(dc.m_hDC, hOldFont);
} else {
//127,127,127
crOldColor = dc.SetTextColor(RGB(148, 167, 70));
dc.DrawText(strTemp,rtl,DT_CENTER|DT_TOP|DT_SINGLELINE); // Draw out the caption
dc.SetTextColor(crOldColor);
}
if ( (state & ODS_FOCUS ) ) // If the button is focused
{
int iChange = 3;
rt.top += iChange;
rt.left += iChange;
rt.right -= iChange;
rt.bottom -= iChange;
dc.DrawFocusRect(rt);
}
dc.Detach();
}
BOOL CButtonDialer::OnEraseBkgnd(CDC* pDC)
{
CRect rect;
GetClientRect(&rect);
//255,255,255
CBrush myBrush(RGB(173, 41, 41)); // dialog background color
CBrush *pOld = pDC->SelectObject(&myBrush);
BOOL bRes = pDC->PatBlt(0, 0, rect.Width(), rect.Height(), PATCOPY);
pDC->SelectObject(pOld); // restore old brush
return bRes; // CDialog::OnEraseBkgnd(pDC);
}
You need to provide a message handler for the WM_ERASEBKGND message and paint the background yourself.
Put a normal button on the Resource Editor.
On the .h file of the form where you use it, declare a CMFCButton variable like m_btnRead.
In the DoDataExchange method of your form append a line
DDX_Control(pDX, IDC_BUTTON_READ, m_btnRead);
On the method where you initialize your form (OnInitDialog, Create, etc.) append a line
m_btnRead.SetFaceColor(RGB(0, 255, 255));
and now you are done!
I am working in an MFC windows application. I am using check boxes in Check List Box control. Some of the check boxes are disabled. How can I implement the tool tips for disabled check boxes?
Ran Wainstein was implemented the tool tip for each item in the list box control. This can be extended to the Check List Box control also.
MyCheckListBox.h
class CMyCheckListBox : public CCheckListBox
{
DECLARE_DYNAMIC(CMyCheckListBox)
public:
CMyCheckListBox(){};
virtual ~CMyCheckListBox(){};
afx_msg int OnToolHitTest(CPoint point, TOOLINFO * pTI) const;
UINT ItemFromPoint2(CPoint pt, BOOL& bOutside) const;
BOOL OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult );
protected:
virtual void PreSubclassWindow();
DECLARE_MESSAGE_MAP()
};
MyCheckListBox.cpp
This will work only for Unicode strings.
IMPLEMENT_DYNAMIC(CMyCheckListBox, CCheckListBox)
BEGIN_MESSAGE_MAP(CMyCheckListBox, CCheckListBox)
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXT, 0, 0xFFFF, OnToolTipText)
END_MESSAGE_MAP()
void CMyCheckListBox::PreSubclassWindow() {
CCheckListBox::PreSubclassWindow();
EnableToolTips(TRUE);
}
int CMyCheckListBox::OnToolHitTest(CPoint point, TOOLINFO * pTI) const{
int row;
RECT cellrect;
BOOL tmp = FALSE;
row = ItemFromPoint(point,tmp);
if ( row == -1 )
return -1;
GetItemRect(row,&cellrect);
pTI->rect = cellrect;
pTI->hwnd = m_hWnd;
pTI->uId = (UINT)((row));
pTI->lpszText = LPSTR_TEXTCALLBACK;
return pTI->uId;
}
BOOL CMyCheckListBox::OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult ){
TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
CString strTipText;
UINT nID = pNMHDR->idFrom;
GetText( nID ,strTipText);
lstrcpyn(pTTTW->szText, strTipText, 80);
*pResult = 0;
return TRUE;
}
UINT CMyCheckListBox::ItemFromPoint2(CPoint pt, BOOL& bOutside) const{
int nFirstIndex, nLastIndex;
nFirstIndex = GetTopIndex();
nLastIndex = nFirstIndex + GetCount();
bOutside = TRUE;
CRect Rect;
int nResult = -1;
for (int i = nFirstIndex; nResult == -1 && i <= nLastIndex; i++){
if (GetItemRect(i, &Rect) != LB_ERR){
if (Rect.PtInRect(pt)){
nResult = i;
bOutside = FALSE;
}
}
}
return nResult;
}
Finally implement Check List Box control in the corresponding dialog box.The output is
I have a class which inherits from CStatic, which is owner drawn and calculates the region the window should have using SetWindowRgn.
In my DrawItem override I attempt to use FillRgn passing in the same region as was calculated but the method returns FALSE. The Documentation says
Return Value: Nonzero if the function is successful; otherwise 0.
But when I GetLastError the message is "The operation completed successfully".
The window's region is definitely getting the set fine as I have managed to receive WM_LBUTTONUP messages.
Here is my class:
.h file
class Country : public CStatic
{
DECLARE_DYNAMIC(Country)
public:
Country(HBITMAP hBm, CPoint point);
virtual ~Country();
protected:
DECLARE_MESSAGE_MAP()
CPoint m_point;
HBITMAP m_hBm;
BITMAP m_bm;
HDC m_dcBm;
HRGN m_hRgn;
void CreateWindowRgn();
public:
void CreateCountryWindow(CWnd * pParent);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
};
.cpp
void Country::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
CRgn * clientRgn = CRgn::FromHandle(m_hRgn);
CBrush blackBrush(RGB(0,0,0));
if(!(pDC->FillRgn(clientRgn, &blackBrush)))
{
AfxMessageBox(GetLastErrorMessage());
}
}
void Country::CreateCountryWindow(CWnd * pParent)
{
if(Create(
_T(""),
WS_CHILD | WS_VISIBLE | SS_NOTIFY | SS_OWNERDRAW,
CRect(m_point.x, QUESTION_PANEL_HEIGHT + m_point.y, m_bm.bmWidth, m_bm.bmHeight),
pParent))
{
ShowWindow(SW_SHOW);
CreateWindowRgn();
}
}
void Country::CreateWindowRgn()
{
HRGN hTmpRgn;
m_hRgn = CreateRectRgn(0,0,m_bm.bmWidth, m_bm.bmHeight);
for(int i = 0; i < m_bm.bmWidth; i++)
{
for(int j = 0; j < m_bm.bmHeight; j++)
{
COLORREF c = GetPixel(m_dcBm,i,j);
if(GetRValue(c) < 10 && GetGValue(c) < 10 && GetBValue(c) < 10)
{
hTmpRgn = CreateRectRgn(i, j, i+1, j+1);
CombineRgn(m_hRgn, m_hRgn, hTmpRgn, RGN_XOR);
DeleteObject(hTmpRgn);
}
}
}
SetWindowRgn(m_hRgn, TRUE);
}
void Country::OnLButtonUp(UINT nFlags, CPoint point)
{
AfxMessageBox(_T("Hello World"));
CStatic::OnLButtonUp(nFlags, point);
}
As with most MFC problems the answer lies in the documentation:
The system does not make a copy of the region. Thus, do not make
further function calls with this region handle.
Documentation
Im using GDI+ in C++ to draw a chart control. I want to know if there is any performance difference between the above 2 functions. I am not lazy to write code for DrawLines() but it is that doing so makes my code complex. So im weighin the chances of whether to make code execution faster at the expense of reducing readability and potentially increasing errors and bugs.
Any help wud be appreciated.
Eraj.
There shouldn't be a significant difference between the two for most drawing activities, but to be sure, I wrote up a test project to compare the difference between them (well, actually 3 of them).
For a very large number of lines (x25000) on my machine, DrawLines() (640ms) was about 50% faster over DrawLine() (420ms). To be honest here, I also misread the question the first time around and wrote my initial test in C#. Performance was about the same between the two, which is to be expected as .NET Graphics are based upon GDI+.
Just out of curiosity, I tried regular GDI, which I expect would be faster. Using the win32 PolyLine() (530ms) function was about 20% faster, with 45000 lines. This is 116% faster than using GDI+ DrawLines(). Even more stunning, perhaps, is that using win32 LineTo() instead of GDI+ DrawLine() results in times under 125ms. With an assumed time of 125ms and 45000 lines, this method is at least 800% faster. (Timer resolution and thread timing make it difficult to measure performance in this threshold without resorting to QueryPerformanceCounter and other timing methods of higher frequency.)
However, I should caution against making the assumption that this is a significant bottleneck in drawing code. Many of the performance improvements that can be made will have nothing to do with what objects have to be drawn. I would guess that your requirements will probably dictate that a few hundred items may need to be drawn in normal operation for your control. In that case, I would recommend you write your drawing code to be as straightforward and bug-free as you can, as debugging drawing issues can be an expensive use of time and potentially less beneficial as improving the rest of your control or your application.
Also, if you need to actively update thousands of items, you will see much higher performance gains by moving to a back-buffered solution. This should also make it easier to develop code to draw your control, aside from managing the off-screen buffer.
Here are my source code examples. Each of them handles mouse clicks to alternate between using bulk drawing versus itemized drawing.
GDI+, hosted in a barebones MFC SDI App
This assumes that someone has already declared GDI+ headers and written code to initialize/teardown GDI+.
In ChildView.h
// Attributes
public:
bool m_bCompositeMode;
// Operations
public:
void RedrawScene(Graphics &g, int lineCount, int width, int height);
PointF *CreatePoints(int lineCount, int width, int height);
void ReportTime(Graphics &g, int lineCount, DWORD tickSpan);
public:
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
In ChildView.cpp, added to PreCreateWindow()
m_bCompositeMode = false;
Remainder of ChildView.cpp, including OnPaint() and Message Map changes.
BEGIN_MESSAGE_MAP(CChildView, CWnd)
ON_WM_PAINT()
ON_WM_LBUTTONUP()
END_MESSAGE_MAP()
void CChildView::OnPaint()
{
CPaintDC dc(this); // device context for painting
RECT rcClient;
::GetClientRect(this->GetSafeHwnd(), &rcClient);
Graphics g(dc.GetSafeHdc());
g.Clear(Color(0, 0, 0));
RedrawScene(g, 25000, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top);
}
void CChildView::RedrawScene(Graphics &g, int lineCount, int width, int height)
{
DWORD tickStart = 0;
DWORD tickEnd = 0;
Pen p(Color(0, 0, 0x7F));
PointF *pts = CreatePoints(lineCount, width, height);
tickStart = GetTickCount();
if (m_bCompositeMode)
{
g.DrawLines(&p, pts, lineCount);
}
else
{
int i = 0;
int imax = lineCount - 1;
for (i = 0; i < imax; i++)
{
g.DrawLine(&p, pts[i], pts[i + 1]);
}
}
tickEnd = GetTickCount();
delete[] pts;
ReportTime(g, lineCount, tickEnd - tickStart);
}
void CChildView::ReportTime(Graphics &g, int lineCount, DWORD tickSpan)
{
CString strDisp;
if(m_bCompositeMode)
{
strDisp.Format(_T("Graphics::DrawLines(Pen *, PointF *, INT) x%d took %dms"), lineCount, tickSpan);
}
else
{
strDisp.Format(_T("Graphics::DrawLine(Pen *, PointF, PointF) x%d took %dms"), lineCount, tickSpan);
}
// Note: sloppy, but simple.
Font font(L"Arial", 14.0f);
PointF ptOrigin(0.0f, 0.0f);
SolidBrush br(Color(255, 255, 255));
Status s = g.DrawString(strDisp, -1, &font, ptOrigin, &br);
}
PointF* CChildView::CreatePoints(int lineCount, int width, int height)
{
if(lineCount <= 0)
{
PointF *ptEmpty = new PointF[2];
ptEmpty[0].X = 0;
ptEmpty[0].Y = 0;
ptEmpty[1].X = 0;
ptEmpty[1].Y = 0;
return ptEmpty;
}
PointF *pts = new PointF[lineCount + 1];
int i = 1;
while(i < lineCount)
{
pts[i].X = (float)(rand() % width);
pts[i].Y = (float)(rand() % height);
i++;
}
return pts;
}
void CChildView::OnLButtonUp(UINT nFlags, CPoint point)
{
m_bCompositeMode = !m_bCompositeMode;
this->Invalidate();
CWnd::OnLButtonUp(nFlags, point);
}
C#.NET, hosted in a basebones WinForms App, with default class Form1
Set a default size for the form, equal to the size of the MFC version if you are comparing the two. A size-change handler could be added as well.
public Form1()
{
InitializeComponent();
bCompositeMode = false;
}
bool bCompositeMode;
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(Color.Black);
RedrawScene(e.Graphics, 25000, this.ClientRectangle.Width, this.ClientRectangle.Height);
}
private void RedrawScene(Graphics g, int lineCount, int width, int height)
{
DateTime dtStart = DateTime.MinValue;
DateTime dtEnd = DateTime.MinValue;
using (Pen p = new Pen(Color.Navy))
{
Point[] pts = CreatePoints(lineCount, width, height);
dtStart = DateTime.Now;
if (bCompositeMode)
{
g.DrawLines(p, pts);
}
else
{
int i = 0;
int imax = pts.Length - 1;
for (i = 0; i < imax; i++)
{
g.DrawLine(p, pts[i], pts[i + 1]);
}
}
dtEnd = DateTime.Now;
}
ReportTime(g, lineCount, dtEnd - dtStart);
}
private void ReportTime(Graphics g, int lineCount, TimeSpan ts)
{
string strDisp = null;
if (bCompositeMode)
{
strDisp = string.Format("DrawLines(Pen, Point[]) x{0} took {1}ms", lineCount, ts.Milliseconds);
}
else
{
strDisp = string.Format("DrawLine(Pen, Point, Point) x{0} took {1}ms", lineCount, ts.Milliseconds);
}
// Note: sloppy, but simple.
using (Font font = new Font(FontFamily.GenericSansSerif, 14.0f, FontStyle.Regular))
{
g.DrawString(strDisp, font, Brushes.White, 0.0f, 0.0f);
}
}
private Point[] CreatePoints(int count, int width, int height)
{
Random rnd = new Random();
if (count <= 0) { return new Point[] { new Point(0,0), new Point(0,0)}; }
Point[] pts = new Point[count + 1];
pts[0] = new Point(0, 0);
int i = 1;
while (i <= count)
{
pts[i] = new Point(rnd.Next(width), rnd.Next(height));
i++;
}
return pts;
}
private void Form1_Click(object sender, EventArgs e)
{
bCompositeMode = !bCompositeMode;
Invalidate();
}
Regular GDI, hosted in a barebones MFC SDI App
In ChildView.h
// Attributes
public:
bool m_bCompositeMode;
// Operations
public:
void RedrawScene(HDC hdc, int lineCount, int width, int height);
POINT *CreatePoints(int lineCount, int width, int height);
void ReportTime(HDC hdc, int lineCount, DWORD tickSpan);
public:
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
In ChildView.cpp
Update PreCreateWindow() just as in the GDI+ sample.
BEGIN_MESSAGE_MAP(CChildView, CWnd)
ON_WM_PAINT()
ON_WM_LBUTTONUP()
END_MESSAGE_MAP()
void CChildView::OnPaint()
{
CPaintDC dc(this); // device context for painting
HDC hdc = dc.GetSafeHdc();
HBRUSH brClear = (HBRUSH)::GetStockObject(BLACK_BRUSH);
RECT rcClient;
::GetClientRect(this->m_hWnd, &rcClient);
::FillRect(hdc, &rcClient, brClear);
::DeleteObject(brClear);
RedrawScene(hdc, 45000, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top);
}
void CChildView::RedrawScene(HDC hdc, int lineCount, int width, int height)
{
DWORD tickStart = 0;
DWORD tickEnd = 0;
HPEN p = ::CreatePen(PS_SOLID, 1, RGB(0, 0, 0x7F));
POINT *pts = CreatePoints(lineCount, width, height);
HGDIOBJ prevPen = SelectObject(hdc, p);
tickStart = GetTickCount();
if(m_bCompositeMode)
{
::Polyline(hdc, pts, lineCount);
}
else
{
::MoveToEx(hdc, pts[0].x, pts[0].y, &(pts[0]));
int i = 0;
int imax = lineCount;
for(i = 1; i < imax; i++)
{
::LineTo(hdc, pts[i].x, pts[i].y);
}
}
tickEnd = GetTickCount();
::SelectObject(hdc, prevPen);
delete pts;
::DeleteObject(p);
ReportTime(hdc, lineCount, tickEnd - tickStart);
}
POINT *CChildView::CreatePoints(int lineCount, int width, int height)
{
if(lineCount <= 0)
{
POINT *ptEmpty = new POINT[2];
memset(&ptEmpty, 0, sizeof(POINT) * 2);
return ptEmpty;
}
POINT *pts = new POINT[lineCount + 1];
int i = 1;
while(i < lineCount)
{
pts[i].x = rand() % width;
pts[i].y = rand() % height;
i++;
}
return pts;
}
void CChildView::ReportTime(HDC hdc, int lineCount, DWORD tickSpan)
{
CString strDisp;
if(m_bCompositeMode)
{
strDisp.Format(_T("PolyLine(HDC, POINT *, int) x%d took %dms"), lineCount, tickSpan);
}
else
{
strDisp.Format(_T("LineTo(HDC, HPEN, int, int) x%d took %dms"), lineCount, tickSpan);
}
HFONT font = (HFONT)::GetStockObject(SYSTEM_FONT);
HFONT fontPrev = (HFONT)::SelectObject(hdc, font);
RECT rcClient;
::GetClientRect(this->m_hWnd, &rcClient);
::ExtTextOut(hdc, 0, 0, ETO_CLIPPED, &rcClient, strDisp.GetString(), strDisp.GetLength(), NULL);
::SelectObject(hdc, fontPrev);
::DeleteObject(font);
}
void CChildView::OnLButtonUp(UINT nFlags, CPoint point)
{
m_bCompositeMode = !m_bCompositeMode;
this->Invalidate();
CWnd::OnLButtonUp(nFlags, point);
}