P
Petr Danes
I use Stephen Lebans' PictureBox class in a database to draw things over a
map indicating where items in the database were found and collected. The
user (there is only one) of this database got a new computer a while back
and suddenly some (but not all) of the drawn objects were getting shifted to
the right. I spent a great deal of time chasing this and had a lot of evil
things to say about this computer, since it was the only one out of several
machines that exhibited this problem. The user finally thought to mention
that she'd changed some display setting away from standard.
Looking at the desktop display properties, I eventually noticed that she had
her DPI settings at 105%. Why she chose this odd number I have no idea
(she's out on a field trip for two weeks, which gave me a good block of
uninterrupted time on her computer), but changing it to 100% (96 dpi) made
everything line up correctly.
Has anyone run into this sort of thing? I have posted the code which
misbehaved if anyone would care to look at it. It's an added method to the
PictureBox class, drawing a grid. I originally used the line method
repeatedly, but that was slow to re-draw and I didn't need any single lines,
so I hacked it to produce a grid. It works fine at 100% but not at the
custom of 105%, nor the other standard of 125% (120 dpi). I do not know the
Stephen's original DrawLine method would work correctly at non-standard
settings; my modification long precedes the acquistion of this computer and
the user's experiment with non-standard dpi settings.
Obviously I overlooked something, the PictureBox class draws spots
correctly, using my modifications of the DrawCircle method, and naturally,
everything that I didn't touch in Stephen's original code works fine, but
the modified DrawLine method to make a grid has a problem.
It almost looks like the adjustment from non-standard is somehow taken into
account twice in the malfunctioning method, since the larger, non-standard
dpi settings cause the grid to progressively be farther and farther off to
the right and down in the image. The upper left corner is correct, the
further I get from there, the worse is the error.
Petr
' ---------------This is a mod of the DrawLine method and works only when
the monitor's dpi setting is 100%, i.e. 96dpi.----------------------
Public Sub DrawGrid(ByVal StartHorizontalOffset&, ByVal HorizontalStep&,
ByVal StartVerticalOffset&, ByVal VerticalStep&, Optional ByVal GridColor&,
Optional ByVal GridThickness&)
' pld Draw into image
' Do not display new image, because that is slow and there may be more calls
to other drawing routines
' Instead, caller must explicitly call the UpdateScreen routine
Dim i&, j&, gc&, gt&, lw&, lh&
Dim hNewPen&, hOldPen&
If IsMissing(GridColor) Then gc = m_ForeColor Else gc = GridColor
If IsMissing(GridThickness) Then gt = m_DrawWidth Else gt = GridThickness
hNewPen = apiCreatePen(PS_SOLID, gt, gc)
hOldPen = SelectObject(m_hDC, hNewPen)
lw = TwipsToPixels(m_ImageControl.Width, 0)
lh = TwipsToPixels(m_ImageControl.Height, 1)
'Debug.Print m_ImageControl.SizeMode, Choose(m_ImageControl.SizeMode + 1,
"Clip", "Stretch", "Unknown", "Zoom")
'Debug.Print m_ImageControl.Width, " Width"
'Debug.Print m_ImageControl.Height, " Height"
i = StartHorizontalOffset
j = TwipsToPixels(i, 0)
Do
Call apiMoveToEx(m_hDC, j, 0, ByVal 0&)
LineTo m_hDC, j, lh
i = i + HorizontalStep
j = TwipsToPixels(i, 0)
Loop Until j >= lw
i = StartVerticalOffset
If gt > 1 Then i = i + 20
j = TwipsToPixels(i, 1)
Do
Call apiMoveToEx(m_hDC, -1, j, ByVal 0&)
LineTo m_hDC, lw, j
i = i + VerticalStep
j = TwipsToPixels(i, 1)
Loop Until j >= lh
Call SelectObject(m_hDC, hOldPen)
Call DeleteObject(hNewPen)
GridVisible = True
End Sub
' ---------------This is a mod of the DrawCircle method and works perfectly,
no matter what the monitor's dpi setting.----------------------
Public Sub PaintBlot(ByVal LeftX&, ByVal TopY&, ByVal diameter&, ByVal
SpotColor&, Optional ByVal SpotCenter)
' pld Draw disks in image in specified color
' Do not display new image, because that is slow and there may be many calls
to this routine
' Instead, caller must explicitly call the UpdateScreen routine
Dim hNewPen&, hOldPen&
Dim hNewBrush&, hOldBrush&
' Draw spot using specified color. If no special color for center is
specified, make solid dot
hNewPen = apiCreatePen(PS_SOLID, m_DrawWidth + 1, SpotColor)
hNewBrush = apiCreateSolidBrush(IIf(IsMissing(SpotCenter), SpotColor,
SpotCenter))
hOldPen = SelectObject(m_hDC, hNewPen)
hOldBrush = SelectObject(m_hDC, hNewBrush)
apiEllipse m_hDC, LeftX, TopY, LeftX + diameter, TopY + diameter
Call SelectObject(m_hDC, hOldPen)
Call DeleteObject(hNewPen)
Call SelectObject(m_hDC, hOldBrush)
Call DeleteObject(hNewBrush)
DotsVisible = True
End Sub
map indicating where items in the database were found and collected. The
user (there is only one) of this database got a new computer a while back
and suddenly some (but not all) of the drawn objects were getting shifted to
the right. I spent a great deal of time chasing this and had a lot of evil
things to say about this computer, since it was the only one out of several
machines that exhibited this problem. The user finally thought to mention
that she'd changed some display setting away from standard.
Looking at the desktop display properties, I eventually noticed that she had
her DPI settings at 105%. Why she chose this odd number I have no idea
(she's out on a field trip for two weeks, which gave me a good block of
uninterrupted time on her computer), but changing it to 100% (96 dpi) made
everything line up correctly.
Has anyone run into this sort of thing? I have posted the code which
misbehaved if anyone would care to look at it. It's an added method to the
PictureBox class, drawing a grid. I originally used the line method
repeatedly, but that was slow to re-draw and I didn't need any single lines,
so I hacked it to produce a grid. It works fine at 100% but not at the
custom of 105%, nor the other standard of 125% (120 dpi). I do not know the
Stephen's original DrawLine method would work correctly at non-standard
settings; my modification long precedes the acquistion of this computer and
the user's experiment with non-standard dpi settings.
Obviously I overlooked something, the PictureBox class draws spots
correctly, using my modifications of the DrawCircle method, and naturally,
everything that I didn't touch in Stephen's original code works fine, but
the modified DrawLine method to make a grid has a problem.
It almost looks like the adjustment from non-standard is somehow taken into
account twice in the malfunctioning method, since the larger, non-standard
dpi settings cause the grid to progressively be farther and farther off to
the right and down in the image. The upper left corner is correct, the
further I get from there, the worse is the error.
Petr
' ---------------This is a mod of the DrawLine method and works only when
the monitor's dpi setting is 100%, i.e. 96dpi.----------------------
Public Sub DrawGrid(ByVal StartHorizontalOffset&, ByVal HorizontalStep&,
ByVal StartVerticalOffset&, ByVal VerticalStep&, Optional ByVal GridColor&,
Optional ByVal GridThickness&)
' pld Draw into image
' Do not display new image, because that is slow and there may be more calls
to other drawing routines
' Instead, caller must explicitly call the UpdateScreen routine
Dim i&, j&, gc&, gt&, lw&, lh&
Dim hNewPen&, hOldPen&
If IsMissing(GridColor) Then gc = m_ForeColor Else gc = GridColor
If IsMissing(GridThickness) Then gt = m_DrawWidth Else gt = GridThickness
hNewPen = apiCreatePen(PS_SOLID, gt, gc)
hOldPen = SelectObject(m_hDC, hNewPen)
lw = TwipsToPixels(m_ImageControl.Width, 0)
lh = TwipsToPixels(m_ImageControl.Height, 1)
'Debug.Print m_ImageControl.SizeMode, Choose(m_ImageControl.SizeMode + 1,
"Clip", "Stretch", "Unknown", "Zoom")
'Debug.Print m_ImageControl.Width, " Width"
'Debug.Print m_ImageControl.Height, " Height"
i = StartHorizontalOffset
j = TwipsToPixels(i, 0)
Do
Call apiMoveToEx(m_hDC, j, 0, ByVal 0&)
LineTo m_hDC, j, lh
i = i + HorizontalStep
j = TwipsToPixels(i, 0)
Loop Until j >= lw
i = StartVerticalOffset
If gt > 1 Then i = i + 20
j = TwipsToPixels(i, 1)
Do
Call apiMoveToEx(m_hDC, -1, j, ByVal 0&)
LineTo m_hDC, lw, j
i = i + VerticalStep
j = TwipsToPixels(i, 1)
Loop Until j >= lh
Call SelectObject(m_hDC, hOldPen)
Call DeleteObject(hNewPen)
GridVisible = True
End Sub
' ---------------This is a mod of the DrawCircle method and works perfectly,
no matter what the monitor's dpi setting.----------------------
Public Sub PaintBlot(ByVal LeftX&, ByVal TopY&, ByVal diameter&, ByVal
SpotColor&, Optional ByVal SpotCenter)
' pld Draw disks in image in specified color
' Do not display new image, because that is slow and there may be many calls
to this routine
' Instead, caller must explicitly call the UpdateScreen routine
Dim hNewPen&, hOldPen&
Dim hNewBrush&, hOldBrush&
' Draw spot using specified color. If no special color for center is
specified, make solid dot
hNewPen = apiCreatePen(PS_SOLID, m_DrawWidth + 1, SpotColor)
hNewBrush = apiCreateSolidBrush(IIf(IsMissing(SpotCenter), SpotColor,
SpotCenter))
hOldPen = SelectObject(m_hDC, hNewPen)
hOldBrush = SelectObject(m_hDC, hNewBrush)
apiEllipse m_hDC, LeftX, TopY, LeftX + diameter, TopY + diameter
Call SelectObject(m_hDC, hOldPen)
Call DeleteObject(hNewPen)
Call SelectObject(m_hDC, hOldBrush)
Call DeleteObject(hNewBrush)
DotsVisible = True
End Sub