Hi,
Is it possible to draw a rectangle with rounded corners to a given width and height
on a Window? The dimensions are 9.906mm wide x 3.387mm deep
It's a sticky label, and I want to draw it onscreen so that I can test if my
text is going to fit into it, before printing
Thanks a lot,
Brian
			
			
			
				Maybe this can give you an idea. Just skip the text label lines and experiment with the variables X3 and Y3 in the API declaration (e.g. smaller values than 10 iused in my example) .
DECLARE "gdi32.dll",RoundRect(hdc As int, X1 As int, Y1 As int, X2 As int, Y2 As int, X3 As int, Y3 As int),int  
DECLARE gbox(x:int,y:int,w:int,h:int,msg$:string)  
SUB gbox(x:int,y:int,w:int,h:int,msg$:string) 
def right,bottom,hdc:int  
	right  = x+w  
	bottom = y+h  
	hdc = GetHDC win  
	RoundRect(hdc, x,y, right, bottom, 10, 10)   
	RELEASEHDC(win,hdc)  
	move win, x+12,y-8		' positioning text label  
	print win, msg$			' printing text label  
RETURN   
EndSub
Good luck!
Egil
			
			
			
				OK, the RoundRect API call has worked perfectly. How do I translate
the size of my rectangle on screen to size it in millimetres?
What do I need to look for in API calls?
Thanks a lot,
Brian
			
			
			
				Don't know if there is one.
If it was me I would draw some on screen and hold a label up to the screen until it looks the same size.
Once it looks the same then print it out to see how close it is(to save paper print several different sizes on one piece of paper)
Keep making adjustments until you get it right.
Be sure and pick a font that is the same on both the screen and the printer.
Just remembered, it seems like the DDocs program lets you enter dimensions.
LarryMc
			
			
			
				Larry,
Just been looking, and I think it's something to do with SetMapMode, although
it seems a little complicated for me. I don't think I know enough about it to
get a Device Context for a DrawRect object
Brian
			
			
			
				This is an example with millimeters <-> pixels conversion - it creates 80*40mm window.
Because GetDeviceCaps does not return real dimensions of the monitor, measure your visible display with a ruler and apply the correct dimensions :)
The values 305,185 are valid for my monitor!
$include "windowssdk.inc"
WINDOW back
int screenX = GetSystemMetrics(SM_CXSCREEN)
int screenY = GetSystemMetrics(SM_CYSCREEN)
OPENWINDOW back,0,0,screenX,screenY,@NOCAPTION,0,"Metrics test",&MainWndProc
SETWINDOWCOLOR back,RGB(0,255,0)
HDC hdcDevice = GETHDC(back)
' draw a round rectangle
HBRUSH hbr = SelectObject(hdcDevice, CreateSolidBrush(RGB(128,255,128)))
HPEN   pen = SelectObject(hdcDevice, CreatePen(PS_SOLID, 3, RGB(255,0,0)))
RoundRect(hdcDevice, /*top-left XY*/20, 20, /*right-bottom XY*/screenX-40, screenY-40, 60/*width of ellipse*/, 60/*height of ellipse*/)
DeleteObject(SelectObject(hdcDevice,pen))
DeleteObject(SelectObject(hdcDevice,hbr))
int Hpixels = GetDeviceCaps(hdcDevice, HORZRES)  ' display width in pixels
int Vpixels = GetDeviceCaps(hdcDevice, VERTRES)  ' display height in pixels
int Hmillimeters = GetDeviceCaps(hdcDevice, HORZSIZE) ' display width in mm
int Vmillimeters = GetDeviceCaps(hdcDevice, VERTSIZE) ' display height in mm
' note: HORZSIZE,VERTSIZE may be not accurate.
'Hmillimeters = 25.4 * Hpixels / GetDeviceCaps(hdcDevice, LOGPIXELSX)
'Vmillimeters = 25.4 * Vpixels / GetDeviceCaps(hdcDevice, LOGPIXELSY)
Hmillimeters = 305 ' fix HORZSIZE
Vmillimeters = 185 ' fix VERTSIZE
RELEASEHDC(back, hdcDevice)
double PixelsPerMillimeter_H = Hpixels / (Hmillimeters+0.0)
double PixelsPerMillimeter_V = Vpixels / (Vmillimeters+0.0)
double MillimetersPerPixel_H = Hmillimeters / (Hpixels+0.0)
double MillimetersPerPixel_V = Vmillimeters / (Vpixels+0.0)
MESSAGEBOX 0, USING("This monitor has # pixels (# millimeters) horizontally\nand # pixels (# millimeters) vertically.\n\nIn other words, one pixel has #.##mm * #.##mm",_
	Hpixels,Hmillimeters,_
	Vpixels,Vmillimeters,_
	MillimetersPerPixel_H,MillimetersPerPixel_V), "", MB_TOPMOST
WINDOW w
OPENWINDOW w,0,0,0,0,@MINBOX|@MAXBOX,0,"Metrics test",&MainWndProc
WINRECT rc
' number of pixels = PixelsPerMillimeter * number of millimeters
rc.right  = PixelsPerMillimeter_H * 80
rc.bottom = PixelsPerMillimeter_V * 40
AdjustWindowRectEx(&rc, GetWindowLong(w.hWnd, GWL_STYLE), 0, GetWindowLong(w.hWnd, GWL_EXSTYLE))
SetWindowPos(w.hWnd, HWND_TOPMOST, 0,0,rc.right,rc.bottom,SWP_NOMOVE)
CENTERWINDOW w
PRINT w, "This window should be 80mm * 40mm"
MOVE  w, 0, 24
PRINT w, "If it is not, adjust Hmillimeters"
MOVE  w, 0, 48
PRINT w, "and Ymillimeters with a ruler."
waituntil w.hWnd=0
end
sub MainWndProc(),int
	select @MESSAGE
		case @IDCLOSEWINDOW
			CLOSEWINDOW *<WINDOW>@HITWINDOW
	endselect
	return 0
endsub
			
			
			
				Sapero,
I do appreciate your help here, and I will attempt to include your code, but it does
make you wonder how all these DTP programs work. I have Quark XPress at home,
and you can work in most printers' measurements, ie, inches, points, centimetres,
millimetres, etc. They must have a way of translating what you draw or type to the
screen from the measuring system you have chosen
Brian
			
			
			
				QuoteI have Quark XPress at home, and you can work in most printers' measurements, ie, inches, points, centimetres, millimetres, etc. They must have a way of translating what you draw or type to the screen from the measuring system you have chosen
Hi Brian, 
the printers use fixed (and known) values as page sizes and printing density, while the actual density in pixels/millimeter of screens, as  said by Sapero is controlled by the size of your monitor and graphics resolution. This problem, quite important for setting the correct aspect ratio for  forms drawing, is somewhat complicated because of the wide variety of monitor (normal, wide) today available. 
Cheers
Sergio
			
 
			
			
				Quote from: Brian Pugh on November 22, 2010, 02:49:35 AM
They must have a way of translating what you draw or type to the
screen from the measuring system you have chosen
Most printers use resolutions defined as dots per inch. Maybe I'm wrong, but there ought to be a way to figure out how many screen pixels there is to such a dot???  If you find that relationship, the rest of your problem would become simple to calculate.
			
 
			
			
				Hi,
I do appreciate all and any answers to my questions. But I would just like to say
that I have been in printing for 44 years (newspaper), and know a fair bit about
DPI, dot screens, resolutions and such. It's just that I can't figure out the relation
between screen and printers for my own ends!
Thanks,
Brian
			
			
			
				Quote from: Brian Pugh on November 22, 2010, 08:53:24 AM
...
It's just that I can't figure out the relation
between screen and printers for my own ends!
...
Hi Brian,
Unfortunately, the "intentions" of converting screen real estate to results on paper is not yet an exact science AFAIK.  As a help and to make sure I get things right I use an engineer's scale (http://en.wikipedia.org/wiki/Engineer%27s_scale) to measure an example on screen and then measure the same printout on paper.  Since the engineer's scale (http://en.wikipedia.org/wiki/Engineer%27s_scale) is graduated in decimals, a useful factor can be easily derived.
Hope this helps,
Calvin
			
 
			
			
				Hello Brian,
Your solution is basically to find out the exact DPI of the monitor, often 72 DPI is used as a default value, but this is most of the time not the exact value at all.
When using a CRT monitor, you can only do what Calvin suggested, measure it out, and calculate the DPI manually, since the image can be stretched, there is no way to determine this otherwise.
But when it is a LCD monitor, it can be calculated without measuring, on the condition that the screen's pixels are perfect squares (luckily almost all monitors have square pixels).
H = Horizontal resolution of monitor in pixels.
V = Vertical resolution of monitor in pixels.
D = Diagonal size of the monitor in Inches.
DPI = SQRT(H^2 + V^2) / D
For my monitor for example: SQRT(1600^2 + 1200^2) / 20.1 = 99.502487562189 DPI
When I now make a frame of 1024 pixels wide, it should measure 1024 / DPI * 25.4 = 261.39648 mm
This corresponds with a measurement on the screen here, so in this case the theory seems correct...  :)
In your program you could make a setting where you could fill in the calculated DPI of your monitor, and store this value...
Maybe this value is calculated and stored somewhere deep into the internal labyrinths of Windows, but who knows where to find this?
Further you can calculate the sizes from pixels to inch to millimetre to whatever.
And when you know the DPI of the printer (which is normally known), you could recalculate the sizes I suppose.
Actually, the formula from Sapero is correct with the LCD monitors that I tested:
DPI_H = GetDeviceCaps(hdcDevice, HORZRES) / (GetDeviceCaps(hdcDevice, HORZSIZE)+0.0) * 25.4
DPI_V = GetDeviceCaps(hdcDevice, VERTRES) / (GetDeviceCaps(hdcDevice, VERTSIZE)+0.0) * 25.4
Hope this helps a bit.
Greetings,
Johnny
			
			
			
				Johnny,
That's a great answer, thanks. I will try this tonight. Unfortunately, Sapero's
code made the box on my Samsung LCD screen 10cm x 6cm, and I couldn't
work out what my calculation should be to correct it
I will try your solution later
Thanks,
Brian
			
			
			
				Johnny and Sapero,
I have now got to a point where I can draw a Rectangle on my screen that
measures exactly 90.906mm x 30.387 (well, near enough!)
But I had to sit here manually putting in dimensions into the Rect until I got
the dimensions right
I need somehow to work backwards, by saying I need a box xx amount of
mms wide and xx amount of millimetres deep, and using code to convert them
into pixels
Any ideas?
Brian
			
			
			
				Brian, have a look at the two programs below.
The first one is used to calibrate. It draws a rectangle and asks you to measure it with a ruler. The result (for current display settings) is then saved in registry.
The second program uses the saved scales to draw 10mm*10mm grid.
After you change display settings (size, frequency or number of colors), run the calibration again to store missing dpi's.
Calibration:$define WIN32_LEAN_AND_MEAN
$include "windowssdk.inc"
WINDOW g_win
int g_screenX = GetSystemMetrics(SM_CXSCREEN)
int g_screenY = GetSystemMetrics(SM_CYSCREEN)
OPENWINDOW g_win,0,0,g_screenX,g_screenY,@NOCAPTION,0,"Metrics test",&MainWndProc
' draw a centered rectangle, take 90% of the screen
int g_rectWidth = g_screenX * 0.9
int g_rectHeight = g_screenY * 0.9
do
	SETWINDOWCOLOR g_win,RGB(128,128,128)
	int g_rectLeft = (g_screenX - g_rectWidth) / 2
	int g_rectTop  = (g_screenY - g_rectHeight) / 2
	int g_rectRight = g_rectLeft+g_rectWidth-1
	int g_rectBottom = g_rectTop+g_rectHeight-1
	RECT g_win, g_rectLeft, g_rectTop, g_rectWidth, g_rectHeight, RGB(255,255,255), RGB(128,128,128)
	FRONTPEN g_win, RGB(00,00,00)
	' horizontal
	LINE g_win, g_rectLeft-1, g_rectTop, g_rectLeft-10, g_rectTop
	LINE g_win, g_rectLeft-1, g_rectBottom, g_rectLeft-10, g_rectBottom
	LINE g_win, g_rectLeft-10, g_rectTop, g_rectLeft-10, g_rectTop+g_rectHeight
	LINE g_win, g_rectLeft-10, g_rectTop, g_rectLeft-10+4, g_rectTop+24 ' arrow
	LINE g_win, g_rectLeft-10, g_rectTop, g_rectLeft-10-4, g_rectTop+24 ' arrow
	LINE g_win, g_rectLeft-10, g_rectBottom, g_rectLeft-10+4, g_rectBottom-24 ' arrow
	LINE g_win, g_rectLeft-10, g_rectBottom, g_rectLeft-10-4, g_rectBottom-24 ' arrow
	' vertical
	LINE g_win, g_rectLeft, g_rectTop-1, g_rectLeft, g_rectTop-1-10
	LINE g_win, g_rectRight, g_rectTop-1, g_rectRight, g_rectTop-1-10
	LINE g_win, g_rectLeft, g_rectTop-1-10, g_rectRight, g_rectTop-1-10
	LINE g_win, g_rectLeft, g_rectTop-1-10, g_rectLeft+24, g_rectTop-1-10+4
	LINE g_win, g_rectLeft, g_rectTop-1-10, g_rectLeft+24, g_rectTop-1-10-4
	LINE g_win, g_rectRight, g_rectTop-1-10, g_rectRight-24, g_rectTop-1-10+4
	LINE g_win, g_rectRight, g_rectTop-1-10, g_rectRight-24, g_rectTop-1-10-4
	int answer = MESSAGEBOX(g_win, "Do you see a complete rectange, and have big enough ruler to measure it?", "", MB_YESNOCANCEL|MB_ICONINFORMATION)
	select (answer)
		case IDCANCEL
			end
		'case IDYES
		case IDNO
			g_rectWidth = g_rectWidth * 0.9
			g_rectHeight = g_rectHeight * 0.9
	endselect
	if ((g_rectWidth < 50) or (g_rectHeight < 50))
		MESSAGEBOX g_win, "Do not cheat!\n\nBye bye!", ""
		end
	endif
until (answer=IDYES)
CONST IDC_QUESTION = 1000
CONST IDC_VALUE = 1001
'calibration
type MYDIALOG
	WINDOW  w
	pointer pszQuestion
	double  Value
endtype
MYDIALOG g_dlgAsk
CREATEDIALOG g_dlgAsk,0,0,300,111,0x80C80080,0,"Calibration",&d1_handler
CONTROL g_dlgAsk,@STATIC,"Static",29,19,248,20,0x5000010B,IDC_QUESTION
CONTROL g_dlgAsk,@EDIT,"",90,47,80,20,0x50800000,IDC_VALUE
CONTROL g_dlgAsk,@SYSBUTTON,"Cancel",56,79,70,20,0x50010000,IDCANCEL
CONTROL g_dlgAsk,@SYSBUTTON,"OK",138,80,70,20,0x50010001,IDOK
' g_screenX - HORZSIZE
' g_rectWidth      - ?           ?=g_rectWidth*HORZSIZE/g_screenX
HDC g_hdcWin = GETHDC(g_win)
float g_dpiH = (GetDeviceCaps(g_hdcWin, HORZSIZE)+0.0) / g_screenX
float g_dpiV = (GetDeviceCaps(g_hdcWin, VERTSIZE)+0.0) / g_screenY
' if you already know the width and height of the white rectangle (real_w, real_h), use
' float real_w = 275f ' mm
' float real_h = 164f ' mm
' g_dpiH = real_w / g_rectWidth
' g_dpiV = real_h / g_rectHeight
' or better read saved DPI
DEVMODE g_devMode
if (!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &g_devMode))
	MESSAGEBOX g_win, "Failed to query current display settings", "Error"
	end
endif
HKEY g_hk
string g_regpath
' query DPI for current display settings: with, height, number of colors and refresh frequency
wsprintf(&g_regpath, "Control Panel\\DPI %d.%d.%d.%d", g_devMode.dmPelsWidth, g_devMode.dmPelsHeight, g_devMode.dmBitsPerPel, g_devMode.dmDisplayFrequency)
if (!RegOpenKeyEx(HKEY_CURRENT_USER, &g_regpath, 0, KEY_READ, &g_hk))
	int g_cb = len(g_dpiH)
	RegQueryValueEx(g_hk, "H", NULL, NULL, &g_dpiH, &g_cb)
	g_cb = len(g_dpiV)
	RegQueryValueEx(g_hk, "V", NULL, NULL, &g_dpiV, &g_cb)
	RegCloseKey(g_hk)
endif
g_dlgAsk.pszQuestion = "Please enter the horizontal width, in millimeters"
g_dlgAsk.Value       = g_rectWidth * g_dpiH
if (DOMODAL(g_dlgAsk, g_win) = IDOK)
	' save in registry
	if (RegCreateKeyEx(HKEY_CURRENT_USER, &g_regpath, 0, NULL, 0, KEY_WRITE, 0, &g_hk, NULL))
		MESSAGEBOX g_win, "Failed to create HKCU\\"+g_regpath, "Error"
	else
		'double real_width_mm = g_dlgAsk.Value
		g_dpiH = g_dlgAsk.Value / g_rectWidth
		if (RegSetValueEx(g_hk, "H", 0, REG_BINARY, &g_dpiH, len(g_dpiH)))
			MESSAGEBOX g_win, "Failed to write 'dpiH' as 'H' in HKCU\\"+g_regpath, "Error"
		endif
		g_dlgAsk.pszQuestion = "Please enter the vertical height, in millimeters"
		g_dlgAsk.Value       = g_rectHeight * g_dpiV
		if (DOMODAL(g_dlgAsk, g_win) = IDOK)
			g_dpiV = g_dlgAsk.Value / g_rectHeight
			if (RegSetValueEx(g_hk, "V", 0, REG_BINARY, &g_dpiV, len(g_dpiV)))
				MESSAGEBOX g_win, "Failed to write 'dpiV' as 'V' in HKCU\\"+g_regpath, "Error"
			else
				MESSAGEBOX g_win, "Saved new DPI in HKCU\\"+g_regpath, "OK"
			endif
		endif
		RegCloseKey(g_hk)
	endif
endif
RELEASEHDC(g_win, g_hdcWin)
PostMessage(g_win.hWnd, WM_CLOSE, 0, 0)
waituntil (g_win.hWnd=0)
end
sub MainWndProc(),int
	select @MESSAGE
		case @IDCLOSEWINDOW
			CLOSEWINDOW *<WINDOW>@HITWINDOW
		case @IDKEYDOWN
			if (@WPARAM = VK_ESCAPE) then CLOSEWINDOW *<WINDOW>@HITWINDOW
	endselect
	return 0
endsub
SUB d1_handler(),int
	SELECT @MESSAGE
		CASE @IDINITDIALOG
			CENTERWINDOW *<WINDOW>@HITWINDOW
			SETCONTROLTEXT g_dlgAsk, IDC_QUESTION, *<MYDIALOG>@HITWINDOW.*<STRING>pszQuestion
			SETCONTROLTEXT g_dlgAsk, IDC_VALUE, USING("#.###", *<MYDIALOG>@HITWINDOW.Value)
		CASE @IDCLOSEWINDOW
			CLOSEDIALOG *<WINDOW>@HITWINDOW,@IDCANCEL
		CASE @IDCONTROL
			SELECT @WPARAM
				CASE IDCANCEL
					CLOSEDIALOG *<WINDOW>@HITWINDOW,@IDCANCEL
				CASE IDOK
					
					CLOSEDIALOG *<WINDOW>@HITWINDOW,@IDOK
			ENDSELECT
	ENDSELECT
	RETURN 0
ENDSUB
The second program (press escape to close):' 10*10 mm grid
$define WIN32_LEAN_AND_MEAN
$include "windowssdk.inc"
class CDPI
	declare CDPI()
	' call Update to reload DPI for current desplay settings
	declare Update(),BOOL
	' width to millimeters
	declare width2mm(float width),float
	' height to millimeters
	declare height2mm(float height),float
	' millimeters to width
	declare mm2width(float width),float
	' millimeters to height
	declare mm2height(float height),float
	float m_dpiH, m_dpiV ' millimeters / pixels
	BOOL  m_Initialized
endclass
WINDOW g_win
CDPI   dpi
if (!dpi.m_Initialized)
	MESSAGEBOX 0, "Please calibrate first", "Error"
	end
endif
int g_screenX = GetSystemMetrics(SM_CXSCREEN)
int g_screenY = GetSystemMetrics(SM_CYSCREEN)
OPENWINDOW g_win,0,0,g_screenX,g_screenY,@NOCAPTION,0,"Metrics test",&MainWndProc
' 10*10 mm grid
int monitorWidth  = dpi.width2mm(g_screenX) ' millimeters
int monitorHeight = dpi.width2mm(g_screenY) ' millimeters
int a
for a = 10 to monitorWidth step 10 ' a = millimeters
	LINE g_win, dpi.mm2width(a), 10, dpi.mm2width(a), g_screenY-10
next a
for a = 10 to monitorHeight step 10 ' a = millimeters
	LINE g_win, 10, dpi.mm2height(a), g_screenX-10, dpi.mm2height(a)
next a
waituntil (g_win.hWnd=0)
end
sub MainWndProc(),int
	select @MESSAGE
		case @IDCLOSEWINDOW
			CLOSEWINDOW *<WINDOW>@HITWINDOW
		case @IDKEYDOWN
			if (@WPARAM = VK_ESCAPE) then CLOSEWINDOW *<WINDOW>@HITWINDOW
	endselect
	return 0
endsub
'------------------------
sub CDPI::CDPI()
	m_Initialized = Update()
endsub
sub CDPI::Update(),BOOL
	string regpath
	DEVMODE dMode
	HKEY hk
	int cb
	BOOL result = FALSE
	EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dMode)
	wsprintf(®path, "Control Panel\\DPI %d.%d.%d.%d", dMode.dmPelsWidth, dMode.dmPelsHeight, dMode.dmBitsPerPel, dMode.dmDisplayFrequency)
	if (!RegOpenKeyEx(HKEY_CURRENT_USER, ®path, 0, KEY_READ, &hk))
		cb = len(m_dpiH)
		if (!RegQueryValueEx(hk, "H", NULL, NULL, &m_dpiH, &cb))
			cb = len(m_dpiV)
			result = !RegQueryValueEx(hk, "V", NULL, NULL, &m_dpiV, &cb)
		endif
		RegCloseKey(hk)
	endif
	return result
endsub
' dpi = mm / px   -> calibration
' px  = mm / dpi  -> mm2width, mm2width
' mm  = dpi * px  -> width2mm, height2mm
sub CDPI::width2mm(float width),float
	return m_dpiH * width
endsub
sub CDPI::height2mm(float height),float
	return m_dpiV * height
endsub
sub CDPI::mm2width(float width),float
	return width / m_dpiH
endsub
sub CDPI::mm2height(float height),float
	return height / m_dpiV
endsub
			
			
			
				Sapero,
I don't know where you get all this code from! Wish I had half of your brainpower!
OK, it's the weekend now, and I can spend a bit of time looking over your stuff,
and working out how to use it
Brian
			
			
			
				with my old xp computer and my SAMSUNG LCD monitor things appear taller than they should be on my computer.
Although  the specs on my monitor says the DPI are the same in both directions a square isn't square on my screen.
I tried the attached program on my wife's and grand-daughter's wide screen monitors and the square is wider than it is tall but I sort of expected that.
On my wife's laptop, the square is indeed square.  Sapero told me it was square on his computer.
I need more people to test for me.  I need to get comfortable that I can ignore the distortion on my computer and proceed with my control tutorial.
The window itself is 400x400 so it should be square
The red box is 200x200 so it should be square.
Any and all feedback will be appreciated.
LarryMc
			
			
			
				Larry,
I'm using a flat screen @ 1600 x 900 and the red box is definitely square. 
(Shows 201 x 201 from a screen capture and measurement)
-Doc-
			
			
			
				Looks square on my laptop.
Bill
			
			
			
				Window is square (400 x 400).
Red box is square (200 x 200).
Monitor is LCD 1920 x 1200.
Barney
			
			
			
				Window and box are square on both my monitors 1920x1080 resolution.
			
			
			
				Okay, thanks guys.  I reckon it's just a quirk of my ancient LCD display.
I'll press on.
Thanks guys.
LarryMc