# Visual C++ & C++ Programming > Visual C++ Programming >  Help with mfc

## pdk5

Hello All,
Merry Christmas and Happy new year ..

I have to again do some changes to legacy MFC code !

There is some renderer function to draw lines..But now i need to add a rectangle to display the list of cells and their power levels.

I have added a following function:


```
void EmfCellListRend::DrawRectangle(EmfCellListRendDrawingParams* pParams, TDC& dc, CEmfCellList *pCelllist)
{
	ILogicalLayerManager&	rLogLayManager  = DataManager::GetInstance().GetLogicalLayer();

	//Rectangle(dc.GetHDC(), midPointX - m_markerSize, midPointY - m_markerSize, midPointX + m_markerSize, midPointY + m_markerSize);
	//GetWindowRect ( dc.GetHDC()
	//int rectHeight = DrawText( hMemDc, text.c_str(), text.size(), &rc, DT_CALCRECT |DT_WORDBREAK ); 
	// Get formating rectangle height

	//  Populate the cell list got from the renderer.  

	tstring message = _T("EMF Cell list");
	for (int i = 0; i < (int)pParams->GetNumCovCells(); i++)
	{
		const MultiTechCell* pObjCell((const MultiTechCell*)rLogLayManager.Find(OT_MULTI_TECH_CELL, pCelllist[i].m_CellKey));
	tstring str3 = _T("\n");
    tstring str4 = _T(pObjCell->GetID());
    tstring str5 = _T(std::to_string(pCelllist[i].m_fRxSignal_dBm));

		message	 +=str3+str4+str5;
	}
	HWND hwnd = WindowFromDC(dc);

	RECT rect;
	HWND bgHandle(0);
	GetClientRect(hwnd, &rect);
	SetTextColor(dc, 0x00000000);
	SetBkMode(dc, TRANSPARENT);
	rect.left = 40;
	rect.top = 10;
	DrawText(dc, message.c_str(), -1, &rect, DT_SINGLELINE | DT_NOCLIP );
	//DrawText(dc, message.c_str(), -1, &rect, DT_CALCRECT|DT_WORDBREAK );
	
	DeleteDC(dc);

	dc.RestorePen();
}
```


The above drawtext somehow doesnot honour new lines..
Also if i change to below commented Drawtext, it doesnot display anything at all..


I tried to install and create a new MFC project in my home PC,  and both of above DrawText doesnot work !!!... I knew little MFC but never drew with MFC

Thanks a lot for the help

----------


## ovidiucucu

At a first look, your sample code contains not any MFC stuff. For example, TDC seems to be a Borland's OWL Library class and further are called just plain WinAPI functions (not MFC). I know, sometimes dealing with legacy code can be a real mess, but no problem, always is a place to make it better. So my advice is the following: when you are dealing with MFC, use as much as possible only MFC stuff. In this particular case, use MFC device context classes (CDC or CClientDC) instead of plain WinAPI functions calls, CString instead std::string, CRect instead of RECT structure. That can further make peogrammer's life much more reasier. 

So far, here are some remarks, based on your sample code.
 if pass *DT_CALCRECT* format flag, the function *DrawText* just adjust the necessary rectangle and draws nothing; if pass *DT_SINGLELINE* format flag, carriage returns ('\r') and line feeds ('\n') do not break the line; do not call *DeleteDC* for a device context whose handle was obtained by calling the *GetDC*. 
See also:
 DrawText function DeleteDC function CDC Class CClientDC Class CRect Class
And here is a simplified example of drawing a text in an MFC application:


```
void CDemoSdiView::RenderText(CDC* pDC, int left, int top, const CString& strText)
{
    CRect rc;
    // calculate the necessary rectangle
    pDC->DrawText(strText, rc, DT_LEFT|DT_TOP|DT_CALCRECT);
    // offset the rectangle to top-left coordinates
    rc.OffsetRect(left, top);
    // finally draw the text
    pDC->DrawText(strText, rc, DT_LEFT|DT_TOP);
}

void CDemoSdiView::OnDraw(CDC* pDC)
{
    CString strText = _T("Ala\nBala\nPortocala");
    RenderText(pDC, 10, 10, strText);
}
```

Enjoy, and good luck!

----------


## pdk5

@ovidiucucu : Thankyou very much. Sorry i missed the above post.

Btw, I had my drawtext working with the following code:



```
 void EmfCellListRend::DrawRectangle(EmfCellListRendDrawingParams* pParams, TDC& dc, CEmfCellList *pCelllist)
{
	ILogicalLayerManager&	rLogLayManager  = DataManager::GetInstance().GetLogicalLayer();

	tstring message = _T("EMF Cell list");
	for (int i = 0; i < (int)pParams->GetNumCovCells(); i++)
	{
		const MultiTechCell* pObjCell((const MultiTechCell*)rLogLayManager.Find(OT_MULTI_TECH_CELL, pCelllist[i].m_CellKey));
		tstring		sNewLine	= _T("\n");
		TgNetType	eTechType	= 	pObjCell->GetActiveTechnologyMode();
		CString		strTechType = MAIN_NET_TYPE_STRINGS_SWITCH( eTechType );
		std::string std(strTechType, strTechType.GetLength());
		tstring sTechtype		= _T(std);
		tstring		sCellId		= _T(pObjCell->GetID());
		tstring		sEmf		= _T(std::to_string(pCelllist[i].m_dCellEMF_Vm));

		message	 +=sNewLine+sTechtype+" "+sCellId+"  "+sEmf;
	}
	HWND hwnd = WindowFromDC(dc);
	RECT rc={ 0, 0, 200, 0 };
	UINT format = DT_LEFT | DT_TOP | DT_EDITCONTROL | DT_WORDBREAK;
	DrawText(dc, message.c_str(), -1, &rc, format | DT_CALCRECT);
	DrawText(dc, message.c_str(), -1, &rc, format);
	DeleteDC(dc);

	dc.RestorePen();
}
```

Now this works ok. But the font is too big. Could MFC gurus help me, with these please ? Thankyou very much in advance

----------


## VictorN

Use HDC function SelectObject to set a preferable font to the device context (dc) you are using to draw,
You can either a  create some new font  or just get a used font of some window using WM_GETFONT message

----------


## pdk5

Thankyou very much Victor. I tried to extract the HDC from the owl context.

But somehow it doesnot work


```

HDC hdc = dc.GetHDC();
	CFont* pCurrent = hdc.GetCurrentFont();

LOGFONT lf ;
pCurrent->GetLogFont(&lf) ;
lf.lfHeight -= -4 ; // make the font larger by 4
// yopu may need to check what you actually get in the LOGFONT object at this point
// to make sure you adjust the correct parameter, in the right direction to make the font bigger
CFont local_font ;

local_font.CreateFontIndirect(&lf) ;

pDC->SelectObject(&local_font) ;
DrawText(...) ;
pDC->SelectObject(pCurrent) ;
```

----------


## pdk5

I tried to the following way : But it didnot work  ( means font remained unchanged)



```
 void EmfCellListRend::DrawRectangle(EmfCellListRendDrawingParams* pParams, TDC& dc, CEmfCellList *pCelllist)
 {
	ILogicalLayerManager&	rLogLayManager  = DataManager::GetInstance().GetLogicalLayer();

	CDC* pDC = CDC::FromHandle(dc.GetHDC());

	CFont* pCurrent = pDC->GetCurrentFont();

	LOGFONT lf;

	pCurrent->GetLogFont(&lf) ;

	lf.lfWeight = FW_EXTRABOLD;
	lf.lfHeight /= 10; // make the font larger by 4
```

Not sure the blue coloured line is correct ? (Eventhough it compiles , but the font size is not reduced)

----------


## pdk5

@ ovidiucucu, Victor Or Arjay, could you please help with how to convert the owl context TDC to MFC drawing context. The above code doesnot change the font.

----------


## 2kaud

I don't know MFC/OWL, but after you're changed lf don't you need to select that font back into the device context?

----------


## VictorN

> @ ovidiucucu, Victor Or Arjay, could you please help with how to convert the owl context TDC to MFC drawing context. The above code doesnot change the font.


1. What is *TDC*?
2. Ovidiu already showed you an example (MFC!) to draw the text properly. Why don't you use it?

----------


## 2kaud

TDC is from Borland's C++ Builder OWL (as ovidiucucu said above)
https://owlnext.sourceforge.net/help...1_1_t_d_c.html

But you don't mix Owl and MFC in the same project. You either use one or the other!

@pdk5 - are you using OWL or MFC?

----------


## ovidiucucu

You've probably got the "System" font, which size can be modified only from the system settings. Or can be another font that does not support the size you have provided.
Anyway it's not a good idea to get the current font from the device context and modify its attributes "on the fly".
Just create your own font! Here is an example:


```
void CDemoSdiView::RenderText(CDC* pDC, int left, int top, const CString& strText)
{
    CFont font;
    font.CreatePointFont(80, _T("Verdana"));
    CFont* pOldFont = pDC->SelectObject(&font);
    int nOldMapMode = pDC->SetMapMode(MM_TEXT);

    CRect rc;
    // calculate the necessary rectangle
    pDC->DrawText(strText, rc, DT_LEFT|DT_TOP|DT_CALCRECT);
    // offset the rectangle to top-left coordinates
    rc.OffsetRect(left, top);
    // filally draw the text
    pDC->DrawText(strText, rc, DT_LEFT|DT_TOP);

    // restore DC status
    pDC->SetMapMode(nOldMapMode);
    pDC->SelectObject(pOldFont);
}
```

Additional notes:
 After drawing, do not forget to restore the initial DC status, as shown in the above example. Alternatively, you can use CDC::SaveDC and CDC::RestoreDC for doing that easier.


```
    // save the DC status    
    int nDCStatus = pDC->SaveDC();
    // ...
    // ...
    // restore DC status
    pDC->RestoreDC(nDCStatus);
```

 For simplicity, I used in my example CFont::CreatePointFont. If you want to also set other custom attributes, like weight for example, call CFont::CreateFont, CFont::CreateFontIndirect, or CFont::CreatePointFontIndirect. See CFont Class in Microsoft Learn documentation. The fizical size of a text depends on DC type and mapping mode. That's the reason I called CDC::SetMapMode. For more info, have a look at LOGFONT Structure documentation.

----------


## pdk5

Thankyou very much. (somehow my email is getting filled with spam and not getting notify when there is response, i need to sort that out.) sorry for the delay.

ovidiucucu : I tried the new font option and font size is exactly the size i was looking for and it works very well. Thankyou very much. 
I need to tweak somethings, and going ahead also when i have sometime, need to check why the owl and MFC context , was not working
Btw, i also now need to make sure, that the rectangle is top left if the selected pixel is top down. Just to make sure the text doesnot overwrite the pixel.. But i.e next task.. May be i'll be disturbing you ppl in the forum 

Thankyou again, kaud, victor and ovidiucucu ..Very helpful  :Smilie:

----------


## 2kaud

> need to check why the owl and MFC context


Which compiler are you using? MFC is for MS VS. OWL (replaced by VCL in 1997) is for Embarcadero C++ Builder.

There is now OWLNext which can be used with either C++ Builder or VS providing you have an existing OWL licence.
https://sourceforge.net/p/owlnext/wiki/Main_Page/

----------


## pdk5

Thankyou kaud  :Smilie: 
Were using visual studio . Mostly MFC, but there is legacy owl still there.  Not sure how VS handles that  :Smilie:

----------


## pdk5

Btw, Im trying to position the rectangle, on parent dialog at the top right. Then the issue is , i donot know the size of parent dialog.  :Mad:

----------


## 2kaud

> Thankyou kaud 
> Were using visual studio . Mostly MFC, but there is legacy owl still there.  Not sure how VS handles that


Probably you have OWLNext. How OWL interacts with MFC.........

----------


## pdk5

Sorry, but I actually donot understand the legacy concepts .. (but i was told, some code, still inherits from owl  :Confused:  ). 

Btw, now i am trying to see if i can use the ScreenToClient to move the rectangle to the right corner. Actually issue is that i donot know the width of parent window

----------


## 2kaud

> Actually issue is that i donot know the width of parent window


Well if you have the handle of a child window, you can get the handle of its parent and from that you can get the size of that window.

GetParent()
https://learn.microsoft.com/en-us/wi...user-getparent

GetWindowInfo()
https://learn.microsoft.com/en-us/wi...-getwindowinfo

These are WIN32 functions. There'll be similar MFC methods.

----------


## pdk5

Thankyou very much kaud, ill check..

I also need to make sure the co-ordinates need to match the screen co-ordinates  :Confused:

----------


## 2kaud

To get the size of the screen, use GetSystemMetrics()
https://learn.microsoft.com/en-us/wi...ectedfrom=MSDN

See SM_CXFULLSCREEN, SM_CYFULLSCREEN

There's loads of info about Windows available.

----------


## ovidiucucu

Aside note...

Dealing with legacy projects is not an easy task and requires some knowledge and experience. Simply getting tweaks from old sources is not enough. This particular case requires at least basic understanding of Windows concepts. 

Especially for GUI part, I kindly recommend *Win32 Programming* by Brent E. Rector and Joseph M. Newcomer. It's an old book, but still 
actual and it was more  than a "bible" for me. 

Then, programming with MFC or OWL, which are just C++ wrappers around plain Windows API, is like a walking in the park.  :Smilie:

----------


## ovidiucucu

Returning to our sheep... 

First note that all Windows controls like buttons, list boxes, combo boxes, and so on are windows, as well. You can see that in plain WinAPI: all are created by a call of CreateWindow(Ex). Also, in MFC CButton, CListBox, CComboBox etc. are derived from CWnd. 

On the other hand, the shapes drawn using GDI, like Rectangle, Ellipse and so on, ARE NOT windows.

So, when we say "parent window", we refer to a control, which generally is a "child window" and not to a shape. 
See also: *What is a child window*.  
When we are talking about drawing a shape, simply refer to (the clent area of) a window. 

Leaving a little bit theory away, here is an example of drawing a rectangle in the client area of a dialog.


```
void CDemoDlg::OnPaint()
{
        // do not call base class method!
        // CDialog::OnPaint();

        // get device context for painting
        CClientDC dc(this);

        const int nTopMargin = 10; // just for demo purpose
        const int nRightMargin = 15;
        const int nShapeWidth = 60;
        const int hShapeHeight = 30;

        // get the dialog's client area
        CRect rcClient;
        GetClientRect(rcClient);

        // calculate the shape coordinates
        int x = rcClient.right - nShapeWidth - nRightMargin;
        int y = rcClient.top + nTopMargin;

        // set the shape rectangle
        CRect rcShape(CPoint(x, y), CSize(nShapeWidth, hShapeHeight));

        // draw the shape
        dc.Rectangle(rcShape);
}
```

Additional notes
 client area is the area that excludes the frame, caption and menu; a dialog is a special type of window, designed as a container for child controls (buttons, listboxes, and so on) and not for drawing; I gave just an example based on your question, but generally prefer drawing in a view (see MFC classes CView and CScrollView); if have to show some drawing in a dialog, then place it in a custom or ActiveX clild control.

----------


## 2kaud

> Especially for GUI part, I kindly recommend Win32 Programming by Brent E. Rector and Joseph M. Newcomer. It's an old book, but still
> actual and it was more than a "bible" for me.


The 'classic' book is Programming Windows by Charles Petzold (5th edition 1998). This book was so used that it was often referred to just as Petzold.
https://www.amazon.com/Programming-W...95X/ref=sr_1_4

For MFC, the 'classic' book is Programming Windows with MFC by Jeoff Prosise (2nd edition 1999) . This is for MFC what Petzold was to Windows.
https://www.amazon.com/Programming-W...50/ref=sr_1_10

Note that these books (and also Rector's (1997) - which I agree is a good Windows book but IMO Petzold is easier to read) are quite old and reflect c/mfc programming as of the time they were written. Also note that they were written for Windows NT/95 - so don't include any windows functions since

But if you need to get to grips with old-style windows programming then these are recommended.

If you want to know what's available for Windows and have small demonstrative examples then there's Windows 2000 API Superbible which is based on Win 2000.
https://www.amazon.com/Windows-Super...WWI/ref=sr_1_3

----------


## pdk5

@ovidiucucu : Thankyou very much for the help. And yes, the help with the book, which i will try to read.
@kaud : Thanks for the help and reference books. 

Btw, sorry for the delay.
I am yet to go through the details you have given. 
Btw the day i posted the question, I got it with the following code :



```
void EmfCellListRend::DrawRectangle(EmfCellListRendDrawingParams* pParams, TDC& dc, CEmfCellList *pCelllist, int nEmfUnit, bool bDisplayRight)
 {
	ILogicalLayerManager&	rLogLayManager  = DataManager::GetInstance().GetLogicalLayer();

	// The font is not changing when i use the owl dc to mfc dc.
	// Need to check why !!!
	CDC* pDC		= CDC::FromHandle(dc.GetHDC());
	CFont* pCurrent = pDC->GetCurrentFont();
	
	// TODO_PRIYA_EMF3: Choosing a new font (unrelated to dc context works)
	CFont font;
	font.CreatePointFont(80, _T("Verdana"));

	CFont* pOldFont = pDC->SelectObject(&font);
	SetBkMode(dc,		OPAQUE);
	SetBkColor(dc,		TColor(RGB(0, 255, 0)));

	tstring sEmfUnit	=_T(TXPower2::GetEmfUnitString(TXPower2::GetCurrentEmfUnit()));
	tstring sFinaText	=_T("EMF Cell list ");
	sFinaText			+=sEmfUnit;
	for (int i = 0; i < (int)pParams->GetNumCovCells(); i++)
	{
		const MultiTechCell* pObjCell((const MultiTechCell*)rLogLayManager.Find(OT_MULTI_TECH_CELL, pCelllist[i].m_CellKey));
		tstring		sNewLine		= _T("\n");
		TgNetType	eTechType		= 	pObjCell->GetActiveTechnologyMode();
		CString		strTechType		= MAIN_NET_TYPE_STRINGS_SWITCH( eTechType );
		std::string str(strTechType, strTechType.GetLength());
		tstring		sTechtype		= _T(str);
		tstring		sCellId			= _T(pObjCell->GetID());

		const double dCurrentEmf_dBVm = pCelllist[i].m_dCellEMF_dBVm;
		ASSERT(dCurrentEmf_dBVm > -200.0);// If dCurrentEmf_dBVm is <= -200.0, we should probably force dCurrentEmf_dBVm to be -200 also ??

		// Convert dBV/m to dBmW/m2 if necessary
		TXPower2 helper(dCurrentEmf_dBVm, EMFUNIT::dBVm);
		const EMFUNIT emfUnit	= TXPower2::GetCurrentEmfUnit();					// The EMF unit chosen by the user in the preferences
		const double dEmf		= static_cast<float>(helper.EMFLevelAs( emfUnit ));	// Either dBV/m or dBmW/m2

		sFinaText+=sNewLine+sTechtype+" "+sCellId+"  "+_T(std::to_string(dEmf));
	}

	HWND hwnd = WindowFromDC(dc);
	CRect rect;
	GetClientRect(hwnd, &rect);

	RECT rc={ 0, 0, 400, 0 };
	UINT format = DT_LEFT | DT_TOP | DT_EDITCONTROL | DT_WORDBREAK;
	DrawText(dc, sFinaText.c_str(), -1, &rc, format | DT_CALCRECT);

	// Adjust co-ordinates of rectangle, to fit the parent window and shift 
	// rectangle to right.
	// From the mouse co-ordinates, check if co-ordinates fall on
	// right corner, choose to display on left and vice versa.
	if( bDisplayRight)
	{
		int long temp = rc.right - rc.left;
		rc.left = rect.right - temp;
		rc.right = rect.right;
		rc.top = rect.top;
	}

	DrawText(dc, sFinaText.c_str(), -1, &rc, format);

	pDC->SelectObject(pCurrent) ;

	DeleteDC(dc);

	dc.RestorePen();
```

Now the background is changed to the set colour (green). But it is only if the text is there (see the red marker i drew manually aroubd that )

----------


## ovidiucucu

And about moving the child windows (controls) inside the client area of the parent... 

One easy method is to get the client area of the parent (call CWnd::GetClientRect), calculate the the child coordinates relative to this area and then call CWnd::MoveWindow. 

Here is am example of moving child controls, relative to top-right corner of the parent dialog. 


```
void CDemoDlg::MoveControlTopRight(UINT nCtrlID, int nTopMargin, int nRightMargin)
{
    CRect rcClient;
    GetClientRect(rcClient);

    CWnd* pCtrl = GetDlgItem(IDOK);
    if (pCtrl->GetSafeHwnd())
    {
        // get the control's size
        CRect rcControl;
        pCtrl->GetWindowRect(rcControl);
        int nWidth = rcControl.Width();
        int nHeight = rcControl.Height();

        // calculate the new control's coordinates
        int x = rcClient.right - nWidth - nRightMargin;
        int y = rcClient.top + nTopMargin;

        // set the new control's rectangle
        CRect rcNew(CPoint(x, y), CSize(nWidth, nHeight));
        // move the control
        pCtrl->MoveWindow(rcNew);
    }
}
```

Now you can call it from CDemoDlg::OnInitDialog and CDemoDlg::OnSize (WM_SIZE message handler) for a bunch of controls. 
It looks not very complicated. However, if using MFC, there is even an easier method: can set the *Moving Type* (also *Sizing Type*) at design time. 

Have a look here: *Dynamic Layout*.

----------


## pdk5

@ovidiucucu :  Thankyou very much. I will go through this and try this idea. Just wanted to say, thankyou very much for your valuable time and patience in helping me. Really appreciated

----------


## ovidiucucu

You are welcome!

[off-topic]
Just joking a little bit: if I had to deal with that (legacy) code, I would be tempted to hit the monitor with the keyboard.  :Big Grin:  
But no problem, everything can be fixed. 

Now seriously: for each new problem, please open a new discussion thread. Otherwise, becomes hard to follow what we are talking about.
**
And please, give it a meaningful title, for example "DrawText - Problem with background color". Someting like  "Help with mfc" is too general and may be thousands of questions about that.

----------


## 2kaud

@pdk5 - you might find this book of interest/help when dealing with legacy code.

https://leanpub.com/legacycode

----------


## pdk5

@ovidiucucu : Thankyou very much for the comments . You being expert in this area, felt so bad about legacy code, you can think of my situation  :Cry:  
I will add a new topic for this issue  :Smilie: 

@kaud: Thankyou very much help and reference books..

----------

