Click here to Skip to main content
15,884,425 members
Please Sign up or sign in to vote.
2.50/5 (2 votes)
See more:
Hi everybody,

I have the following problem. I decided to create a ruler application in MFC. I derived CRuler class from CWnd and simply override OnPaint() method (see code below). The ruler is painted well, but there is one mistake. I wand 1 unit on the ruler to be 1cm = 10mm. The problem is that if I measure the unit on the screen by a real ruler, the length is smaller then 10mm. What i wrong ??? The following is the OnPaint() code:
C++
WCHAR txt[4];
CPaintDC dc(this);
CRect rect;
GetClientRect(&rect);

// MM_LOMETRIC ... 1 logical unit on the screen is 0.1mm 
dc.SetMapMode(MM_LOMETRIC);
// iPart ... 10mm = 1cm 
int iPart  = 100;

dc.SetBkMode(TRANSPARENT);

CFont font;
font.CreatePointFont(220, L"Arial");
dc.SelectObject(&font);

// here we get the wodth of the window in milimeters (1 inch = 25.4mm)
int iWidth = (int)((rect.Width() / (double)dc.GetDeviceCaps(LOGPIXELSX)) * 254);


dc.SelectObject(CreateSolidBrush(RGB(220, 220, 220)));
dc.Rectangle(0,0, iWidth, -80);
	
for (int i=1; i<=iWidth/iPart; i++)
{
	dc.MoveTo(i*iPart, -55);
	dc.LineTo(i*iPart, -80);
	
	swprintf(txt, L"%d", i);
	CString str(txt);
		CSize sz = dc.GetTextExtent(txt);
	if (i*iPart+sz.cx/2 < iWidth)
	        dc.TextOut(i*iPart-sz.cx/2, -10, txt, wcslen(txt));
}

I search info about this and found that 1 logical inch does not have to be exactly the same size as 1 phsical inch in the real. But I dont understand why and how to adjust it...

Thanx for help in advance,
J.K.
Posted
Comments
Sergey Alexandrovich Kryukov 26-May-13 17:22pm    
How about thinking just a bit, by yourself? The problem is way to obvious...
—SA
Kucera Jan 27-May-13 5:29am    
Many thanx for your advice. A lot of things are obvious, though sometimes cannot be seen. If you insinst on such point of you, do not bother to attend any forums.
J.K.
Sergey Alexandrovich Kryukov 27-May-13 10:38am    
Please, let me decide what to attempt and what not. Don't be rude, and people will gladly help you.
—SA
Philippe Mori 27-May-13 9:42am    
Exactly as you found on the web, a logical inch is not exactly equal to a physical inch. Main reason is mainly legacy. The information was not always available from monitors (and in case you have multiple monitors or use a projector, you can never know and by the way some monitors allows to adjust the exact image size). Also, since it is harder to read on screen, often 100% was defined to be somewhat bigger that on paper. You can try it with well known application like Office. You cannot do much about that. If you really need calibration on screen, then you will probably have to do it by yourself. Note that this is how it was many years ago. There might be a bit more information available now.

I'm afraid I don't think it's necessarily that easy - The information available to you is only what the driver(s) provides.

I think my first step would be to try getting HORZRES and divide by HORZSIZE and see if that gives you a different and/or gives you a correct line width (it will give you pixels / mm. (Divide HORZSIZE, or multiply HORZRES, by 25.4 to get DPI). Also check the value that HORZSIZE reports first to see if it matches your physical screen width.

Check that you are using the correct driver for your monitor (as that should presumably return the correct physical height and width, so that the resolution is calculated correct). However, I note there is "caveat" on the GetDeviceCaps[^] page that says "Unfortunately, a display driver that is implemented to the Windows Display Driver Model (WDDM) (introduced in Windows Vista) causes GDI to not get the info, so GetDeviceCaps must always calculate the info" (in other words, in this case it always assumes 96 DPI).

Otherwise, I'm afraid just to do some more research online. E.g. There are some interesting possible suggestions on this page: http://stackoverflow.com/questions/4631292/how-detect-current-screen-resolution[^]

As you'll see there, you may also need to do some work to deal with possible multiple monitor situations.

Regards,
Ian.
 
Share this answer
 
Comments
Espen Harlinn 27-May-13 17:29pm    
I'm afraid you're wrong - Windows identifies my screen as Dell 3007WFP.

OP has called dc.SetMapMode(MM_LOMETRIC); so to get things right he needs to forget about inches and concentrate on 0.1 mm, which is what he has specified.
Ian A Davidson 27-May-13 18:32pm    
1) I don't care what screen you have or what Windows identifies yours as. Windows will "identify" it as whatever driver you have used for it. You could as well use a generic driver, but in that case if it does return a physical size, it is likely to be wrong.

2) I've not specified whether OP should use imperial or metric, merely provided some possible calculations to determine screen resolution (in either measurement system). I'm sure he is competent enough to convert, as indeed the sample code does.

The information I have provided is correct.

Cheers,
Ian.
Espen Harlinn 27-May-13 18:51pm    
1) In my experience Windows usually gets this right. "as whatever driver you have used for it" Certainly, it's not magic, and the info is provided through a driver ...



Windows managed to identify the correct display because modern displays do provide a bit of information, including maximum horizontal and vertical image size in centimeters, have a look at: http://en.wikipedia.org/wiki/Extended_display_identification_data



You can also download a nice tool from MS,EDID 1.3 and DDC Test: http://msdn.microsoft.com/en-us/library/windows/hardware/jj124739.aspx

2)I've not specified whether OP should use imperial or metric You didn't, OP managed that himself, take a look at his source code, near the top ...
Ian A Davidson 27-May-13 19:06pm    
So I still don't get your problem with my answer. Stop talking gibberish and stick to trying to provide useful information as in your own solution below. Regards,
Ian.
Espen Harlinn 27-May-13 20:28pm    
gibberish? I'm just telling you that the physical measurements is available through the EDID Basic display parameters, which is provided by most modern monitors - and that Windows retrieves this information. You can use an inf file to override the info provided by EDID, but that's rather unusual these days.

>> So I still don't get your problem with my answer
Not a problem really, you wrote: "I'm afraid I don't think it's necessarily that easy" - It is easy, OP is having a bit of trouble because he tries to do his own mapping instead of using the functions provided by Windows for that purpose.

I just thought you would be interested, that's all ...
I noticed that you're calling the SetMapMode[^] with MM_LOMETRIC as the argument, so why are you not calling DPtoLP[^] to get the width and height of the display in logical units?

The following function
void DeviceContextExampleForm::DrawScreenWidthAndHeight(const std::shared_ptr<DeviceContextHandle>& dc,RECT& rect )
{
 auto height = Environment::SystemMetrics::CaptionHeight();
 rect.top = rect.top + ( ((rect.bottom - rect.top)/2) - (height/2) );

 auto screenHeight = Environment::SystemMetrics::ScreenHeight();
 auto screenWidth  = Environment::SystemMetrics::ScreenWidth();

 MapMode mapMode = dc->MapMode();
 dc->SetMapMode(MapMode::LoMetric);

 POINT pt = {(LONG)screenWidth,(LONG)screenHeight};
 ::DPtoLP(dc->GetHDC(),&pt,1);

 dc->SetMapMode(mapMode);

 String s = String::Format(L"Width %d, Height %d",pt.x,pt.y);

 dc->DrawStateW(s,rect.left,rect.top,DrawStateFlags::Normal);
}

draws 'Width: 9031, Height: -5644' - and it turns out that the screen really is about 90 cm wide and 56 cm high.

The code was added to the DeviceContextExample distributed with: Windows Development in C++, working with menus[^]

String::Format is not yet a part of the distribution ...

The changes can be downloaded from http://harlinnwindows.codeplex.com/[^]


Best regards
Espen Harlinn
 
Share this answer
 
v3

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
Top Experts
Last 24hrsThis month


CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900