|
code
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
PictureBox Scale Confusion1) Why do I need to rescale the picturebox to its actual pixel values in order for API MoveTo, LIneTo to show the line on the picturebox? 2) How do I rescale the picturebox such that I'm able to obtain the actual array values for the X axis "i" value such that their is a 1 to 1 relationship between the X value obtained from "i" and the points actually plotted in #1 below? ======= info follows =============== !) I'm setting the scale to draw a line in a PictureBox as follows picGraph.Scale (0, .089000)-(530, .047376) and then drawing a line using picGraph.Line (i, dblYData1(i))-(i + 1, dblYData1(i + 1)) The line appears to be drawn and scaled correctly. 2) I then wanted to drag a vertical line across the picturebox with the MouseMove event. In order for the API: MoveTo, LineTo functions to show the line I had to rescale the picture box to its actual pixel dimensions other wise the vertical line did Not show. frmBestFit.picGraph.Scale (0, 0)-(580, 799) After rescaling to the above the vertical line shows and drags across the picturebox. 3) Lastly I wanted to obtain the values for "i" as the the vertical line is being dragged across the picturebox. Using the same Scale values of frmBestFit.picGraph.Scale (0, 0)-(580, 799) I error with "No Subscript" about 1/3 across the picturebox from .ScaleLeft. Obviously the pixel points are closer together than the line points plotted in #1. "David" <dw85745***@earthlink.net> wrote in message The various Scale settings of a PictureBox determine how VB interprets the news:%23M0Sq7k4JHA.1712@TK2MSFTNGP03.phx.gbl... > I'm confused. > I'm setting the scale to draw a line in a PictureBox as follows > picGraph.Scale (0, .089000)-(530, .047376) > 1) Why do I need to rescale the picturebox to its actual pixel > values in order for API MoveTo, LIneTo to show the line on > the picturebox? coordinates when you use native VB drawing methods. The API (GDI) drawing functions on the other hand continue to use their default units of pixels. So, if you want to draw a line using the native VB Line method then you should use your VB Scale coordinates and if you want to draw a Line using the GDI methods (MoveTo and LineTo) and you are using something other than the standard vbPixels ScaleMode then you need to perform the conversion from Scale units to pixels in your code, passing the converted values (the pixel values) to the GDI functions. In fact this is pretty much what VB itself does "under the hood" when you use a native VB drawing method. VB always leaves the underlying DC of the PictureBox set to its default map mode of pixels regardless of the VB ScaleMode and the VB Line method (or other VB drawing method) performs the conversion from Scale Units to pixels "under the hood" before itself using the GDI function to draw the line, passing it the calculated pixel values. When you use the GDI LineTo function directly yourself (instead if using the native VB Line method) then your code needs to perfom this otherwise "under the hood" conversion itself. For example, in your own code you have set the various Scale properties of the PictureBox using the line: picGraph.Scale (0, 0.089)-(530, 0.047376) In order to draw a pixel at the centre of such a PictureBox using the native VB Pset you might use something like: x = 265 y = 0.06818 picGraph.PSet (x, y), vbBlue If you want to draw a pixel at the centre of the same PictureBox using the API (GDI) SetPixel method then you need to perform in code the conversion that VB itself would otherwise perform "under the hood" to convert the scale units to pixels. The VB ScaleX and ScaleY functions can help you to perform such a conversion. For example, using the same values of x and y as shown above the code would be: x = 265 y = 0.06818 j = picGraph.ScaleX(x - picGraph.ScaleLeft, picGraph.ScaleMode, vbPixels) k = picGraph.ScaleY(y - picGraph.ScaleTop, picGraph.ScaleMode, vbPixels) SetPixel picGraph.hdc, j, k, vbRed [Watch for any "newsgroup wrapping" on the above lines]. Note that the conversion code (as shown above) should include the ScaleLeft and ScaleTop properties respectively. You can often get away without using them, depending on the specific scale settings of your PictureBox, but it is always best to use them otherwise the code will "fall down" in many cases, as indeed it would in your specific case where you have altered one of the origins to something other than zero. The code as shown above will work in cases. There may of course be the occasional "single pixel" difference in the output in certain circumstances on the grounds that the two methods may round their various conversions slightly differently, but in general everything should work as expected. Otherwise, as you have discovered, if you are responding the the X and Y coordinates reported by the various PictureBox events (MouseMove etc) and if you prefer not to perform such a conversion in code then you can temporarily set the ScaleMode back to pixels just while you are peforming that task. Personally though I don't like swapping from one ScaleMode to another "on the fly" as a general rule because it is easy to get things wrong. As I have said, VB always leaves the underlying DC of the PictureBox set to its default mapmode value of pixels regardless of the various VB ScaleModes you are using, and VB performs the necessary conversions "on the fly" from VB Scale units to pixels when performing any native VB drawing functions so that it can pass pixel values to the various API routines that the native VB drawing methods themselves use "under the hood". This means that, as explained above, you must pass pixel values to the API functions (SetPixel, LineTo, etc) if you are using them directly. I would suggest that you leave it that way and perform any required conversions in your code as explained above. However, it is actually possible to change the units that the API routines themselves use, although I wouldn't recommend doing that for general purpose work on the grounds that VB itself always expects the mapmode of the DC to be set to pixel units and if it finds it set to some other units when it performs its various operations on the PictureBox then it all goes wrong. So, if you do decide to set the underlying "API scale units" to something other than pixels you need to be very careful to change them back again before VB itself performs any drawing operations (Paint events or whatever) in the PictureBox. If you want to look into changing the "API scale units" of a DC (a PictureBox for example) then check out the SetMapMode and SetViewportExtEx and various other associated API functions. These will enable you to change from pixels (MM_TEXT) to twips or to various English and Metric units (MM_HIMETRIC, MM_HIENGLISH etc) and also to the API equivalent of a user scale mode and different ScaleLeft and ScaleTop properties (MM_ANISOTROPIC) although it is not quite as simple as it at first sounds and in the case of the "GDI user scale mode" (MM_ANISOTROPIC) you need to bear in mind the fact that all API (GDI) drawing functions use Longs and you cannot therefore pass floating point values to them. This means that you cannot effectively set the DC so that it has a vertical size extending from 0.089 to 0.047376 units as you have done in your VB Scale setting. You would need to instead use values such as 89000 to 47376 (although since, no matter what you do, you cannot actually plot a pixel at anything other than a whole pixel value anyway the values 8900 to 4738 would be more than enough on any display). That is one of the ways in which VB ScaleModes make things very easy, because VB allows you to use floating point values for such things on the grounds that it converts them to the equivalent pixel values "under the hood" and passes the pixel values onto the underlying API (GDI) functions that the VB drawing functions use. Mike Thanks for excellent response Mr. Williams.
Didn't know about ScaleX and ScaleY so learned something new today. Interestingly after using ScaleX and ScaleY the GDI vertical line showed and appeared to be scaled correctly. Also, I was able to drag the GDI vertical line with MouseMove when NO underlying graphics were plotted. However, when underlying graphics are plotted, and the MouseMove event is used -- multiple vertical lines are being placed instead of just one line which can be dragged across the PBox (I use vbInvert). Consequently, it appears ScaleX and ScaleY are somehow conflicting with GDI (MoveTo, LineTo) since the GDI (MoveTo, LineTo) worked previously when rescaling to actual PBox pixel dimensions. FWIW heres my new code: [code] 'NOTE: Scale in set in routine which plots the underlying graphics. 'Altered GDI Code in MouseMove Event: With objPBox iY1 = objPBox.ScaleY(.ScaleTop - .ScaleTop, .ScaleMode, vbPixels) iY2 = .ScaleTop + .ScaleHeight iY2 = objPBox.ScaleY(iY2 - .ScaleTop, .ScaleMode, vbPixels) 'Erase Old miOldX = objPBox.ScaleX(miOldX - .ScaleLeft, .ScaleMode, vbPixels) lngDummy = MoveToEx(.hDC, miOldX, iY1, pt) lngDummy = LineTo(.hDC, miOldX, iY2) 'New iX1 = CLng(x) iX1 = objPBox.ScaleX(iX1 - .ScaleLeft, .ScaleMode, vbPixels) lngDummy = MoveToEx(.hDC, iX1, iY1, pt) lngDummy = LineTo(.hDC, iX1, iY2) End With miOldX = iX1 [/code] Know of any place that the conversion functions or calculations are available for ScaleX and ScaleY so I can manually implement and see what's going on? David Show quoteHide quote "Michael Williams" <M***@WhiskeyAndCoke.com> wrote in message news:Ou98Naq4JHA.2656@TK2MSFTNGP05.phx.gbl... > > "David" <dw85745***@earthlink.net> wrote in message > news:%23M0Sq7k4JHA.1712@TK2MSFTNGP03.phx.gbl... > >> I'm confused. >> I'm setting the scale to draw a line in a PictureBox as follows >> picGraph.Scale (0, .089000)-(530, .047376) >> 1) Why do I need to rescale the picturebox to its actual pixel >> values in order for API MoveTo, LIneTo to show the line on >> the picturebox? > > The various Scale settings of a PictureBox determine how VB interprets the > coordinates when you use native VB drawing methods. The API (GDI) drawing > functions on the other hand continue to use their default units of pixels. > So, if you want to draw a line using the native VB Line method then you > should use your VB Scale coordinates and if you want to draw a Line using > the GDI methods (MoveTo and LineTo) and you are using something other than > the standard vbPixels ScaleMode then you need to perform the conversion > from Scale units to pixels in your code, passing the converted values (the > pixel values) to the GDI functions. > > In fact this is pretty much what VB itself does "under the hood" when you > use a native VB drawing method. VB always leaves the underlying DC of the > PictureBox set to its default map mode of pixels regardless of the VB > ScaleMode and the VB Line method (or other VB drawing method) performs the > conversion from Scale Units to pixels "under the hood" before itself using > the GDI function to draw the line, passing it the calculated pixel values. > When you use the GDI LineTo function directly yourself (instead if using > the native VB Line method) then your code needs to perfom this otherwise > "under the hood" conversion itself. For example, in your own code you have > set the various Scale properties of the PictureBox using the line: > > picGraph.Scale (0, 0.089)-(530, 0.047376) > > In order to draw a pixel at the centre of such a PictureBox using the > native VB Pset you might use something like: > > x = 265 > y = 0.06818 > picGraph.PSet (x, y), vbBlue > > If you want to draw a pixel at the centre of the same PictureBox using the > API (GDI) SetPixel method then you need to perform in code the conversion > that VB itself would otherwise perform "under the hood" to convert the > scale units to pixels. The VB ScaleX and ScaleY functions can help you to > perform such a conversion. For example, using the same values of x and y > as shown above the code would be: > > x = 265 > y = 0.06818 > j = picGraph.ScaleX(x - picGraph.ScaleLeft, picGraph.ScaleMode, > vbPixels) > k = picGraph.ScaleY(y - picGraph.ScaleTop, picGraph.ScaleMode, > vbPixels) > SetPixel picGraph.hdc, j, k, vbRed > > [Watch for any "newsgroup wrapping" on the above lines]. Note that the > conversion code (as shown above) should include the ScaleLeft and ScaleTop > properties respectively. You can often get away without using them, > depending on the specific scale settings of your PictureBox, but it is > always best to use them otherwise the code will "fall down" in many cases, > as indeed it would in your specific case where you have altered one of the > origins to something other than zero. The code as shown above will work in > cases. There may of course be the occasional "single pixel" difference in > the output in certain circumstances on the grounds that the two methods > may round their various conversions slightly differently, but in general > everything should work as expected. > > Otherwise, as you have discovered, if you are responding the the X and Y > coordinates reported by the various PictureBox events (MouseMove etc) and > if you prefer not to perform such a conversion in code then you can > temporarily set the ScaleMode back to pixels just while you are peforming > that task. Personally though I don't like swapping from one ScaleMode to > another "on the fly" as a general rule because it is easy to get things > wrong. > > As I have said, VB always leaves the underlying DC of the PictureBox set > to its default mapmode value of pixels regardless of the various VB > ScaleModes you are using, and VB performs the necessary conversions "on > the fly" from VB Scale units to pixels when performing any native VB > drawing functions so that it can pass pixel values to the various API > routines that the native VB drawing methods themselves use "under the > hood". This means that, as explained above, you must pass pixel values to > the API functions (SetPixel, LineTo, etc) if you are using them directly. > > I would suggest that you leave it that way and perform any required > conversions in your code as explained above. However, it is actually > possible to change the units that the API routines themselves use, > although I wouldn't recommend doing that for general purpose work on the > grounds that VB itself always expects the mapmode of the DC to be set to > pixel units and if it finds it set to some other units when it performs > its various operations on the PictureBox then it all goes wrong. So, if > you do decide to set the underlying "API scale units" to something other > than pixels you need to be very careful to change them back again before > VB itself performs any drawing operations (Paint events or whatever) in > the PictureBox. > > If you want to look into changing the "API scale units" of a DC (a > PictureBox for example) then check out the SetMapMode and SetViewportExtEx > and various other associated API functions. These will enable you to > change from pixels (MM_TEXT) to twips or to various English and Metric > units (MM_HIMETRIC, MM_HIENGLISH etc) and also to the API equivalent of a > user scale mode and different ScaleLeft and ScaleTop properties > (MM_ANISOTROPIC) although it is not quite as simple as it at first sounds > and in the case of the "GDI user scale mode" (MM_ANISOTROPIC) you need to > bear in mind the fact that all API (GDI) drawing functions use Longs and > you cannot therefore pass floating point values to them. This means that > you cannot effectively set the DC so that it has a vertical size extending > from 0.089 to 0.047376 units as you have done in your VB Scale setting. > You would need to instead use values such as 89000 to 47376 (although > since, no matter what you do, you cannot actually plot a pixel at anything > other than a whole pixel value anyway the values 8900 to 4738 would be > more than enough on any display). That is one of the ways in which VB > ScaleModes make things very easy, because VB allows you to use floating > point values for such things on the grounds that it converts them to the > equivalent pixel values "under the hood" and passes the pixel values onto > the underlying API (GDI) functions that the VB drawing functions use. > > Mike > > > "David" <dw85745***@earthlink.net> wrote in message Mike will be fine ;-)news:eg2zplr4JHA.4184@TK2MSFTNGP02.phx.gbl... > Thanks for excellent response Mr. Williams. > Didn't know about ScaleX and ScaleY so learned something new Yes. That's what I was saying in my previous response. If you use ScaleX and > today. Interestingly after using ScaleX and ScaleY the GDI vertical > line showed and appeared to be scaled correctly. ScaleY in the correct way to convert the coordinates from the VB Scale units to pixels then you will be able to pass the calculated pixel values to the various API (GDI) drawing functions which by default use pixels regardless of the VB Scale units you are using. > Also, I was able to drag the GDI vertical line with MouseMove Actually the problem is highly unlikely to be caused by your use of ScaleX > when NO underlying graphics were plotted. However, when > underlying graphics are plotted, and the MouseMove event is used -- > multiple vertical lines are being placed instead of just > one line which can be dragged across the PBox (I use vbInvert). > Consequently, it appears ScaleX and ScaleY are somehow > conflicting with GDI (MoveTo, LineTo) since the GDI (MoveTo, > LineTo) worked previously when rescaling to actual PBox pixel > dimensions. and ScaleY unless you are using them incorrectly or your code is failing in some other way. With these sort of things it is very easy to have problems caused by a specific part of your code and to erroneously connect those problems with some other part of your code which is not in itself causing the problem, especially when you are trying new things. > FWIW heres my new code: I've looked at that but to be honest I always have problems following code unless I can see all the variable declarations and other relevant things so that I know both their type and their scope and also so that I know things like whether or not you are using or manipulating the Autredraw property anywhere in your code. So, rather than ask lots of questions about the code you have posted here is an example that I've just written using a PictureBox with its Scale properties set up exactly the same as your own and which uses the ScaleX and ScaleY functions to calculate the appropriate pixel values from the PicBox MouseMove VB Scale coordinates so that it can draw the line using the MoveToEx and LineTo GDI methods that you are using yourself. To check it out paste the code into a VB Form containing a PictureBox and change the hard coded path "c:\temp1jan1.jpg" to a picture that exists on your own system. Then run the code and click the left Mouse Button on the Picture Box. It should draw a line and then move that line in response to horizontal movement of the mouse whilst you are still holding down the button. When you release the button the line will be left at the last position at which it was drawn and you will then be able to click the mouse button elsewhere on the PictureBox to start and drag another line. It all works fine on my own system. Check it out and let mw know how it behaves on your own. Mike Option Explicit Private Declare Function MoveToEx Lib "gdi32" _ (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, _ lpPoint As POINTAPI) As Long Private Declare Function LineTo Lib "gdi32" _ (ByVal hdc As Long, ByVal x As Long, ByVal y As Long) _ As Long Private Type POINTAPI x As Long y As Long End Type Private oldX As Long Private pt1 As POINTAPI Private picTop As Long, picBottom As Long Private Sub Form_Load() Me.Move 0, 0 Me.Show: Me.Refresh With picGraph picGraph.Scale (0, 0.089)-(530, 0.047376) picGraph.DrawMode = vbCopyPen picGraph.PaintPicture LoadPicture("c:\temp\jan1.jpg"), _ .ScaleLeft, .ScaleTop, _ .ScaleWidth, .ScaleHeight .DrawMode = vbInvert ' store the top and bottom pixel coordinates, which ' will remain the same unless we resize the PicBox picTop = .ScaleY(0, .ScaleMode, vbPixels) picBottom = .ScaleY(.ScaleHeight, .ScaleMode, vbPixels) End With End Sub Private Sub picGraph_MouseDown(Button As Integer, _ Shift As Integer, x As Single, y As Single) If (Button And 1) = 1 Then With picGraph ' set oldX to initial position of line oldX = .ScaleX(x - .ScaleLeft, .ScaleMode, vbPixels) ' draw the initial line MoveToEx .hdc, oldX, picTop, pt1 LineTo .hdc, oldX, picBottom End With End If End Sub Private Sub picGraph_MouseMove(Button As Integer, _ Shift As Integer, x As Single, y As Single) If (Button And 1) = 1 Then With picGraph ' redraw the line at its previous position ' in order to erase it (vbInvert drawing) MoveToEx .hdc, oldX, picTop, pt1 LineTo .hdc, oldX, picBottom ' set oldX to the pixel value of the new position oldX = .ScaleX(x - .ScaleLeft, .ScaleMode, vbPixels) ' draw the line at its new position MoveToEx .hdc, oldX, picTop, pt1 LineTo .hdc, oldX, picBottom End With End If End Sub Thanks Mike.
Got mine working using your example. My code reset OldX at end of MouseMove which was re-setting the original X value rather than reusing the scaled X. I now need to do a takeoff of the X values using the scale used to plot one of the lines. Hopefully no problems. ================================= I do have one more question if you don't mind.. In MSChart you can click on the plotted line and it will be identified by squares. Only thing I can think of how this may be done is: 1) Enum all plotted data sets, or 2) Have a table of plotted dataset colors and use API: GetPixel to find which dataset then reloop the dataset at a larger step increment to ID the line. This will work unless there are multiple lines of the same color. Any ideas how this is done? Show quoteHide quote "Michael Williams" <M***@WhiskeyAndCoke.com> wrote in message news:u9rfsrt4JHA.4632@TK2MSFTNGP02.phx.gbl... > "David" <dw85745***@earthlink.net> wrote in message > news:eg2zplr4JHA.4184@TK2MSFTNGP02.phx.gbl... > >> Thanks for excellent response Mr. Williams. > > Mike will be fine ;-) > >> Didn't know about ScaleX and ScaleY so learned something new >> today. Interestingly after using ScaleX and ScaleY the GDI vertical >> line showed and appeared to be scaled correctly. > > Yes. That's what I was saying in my previous response. If you use ScaleX > and ScaleY in the correct way to convert the coordinates from the VB Scale > units to pixels then you will be able to pass the calculated pixel values > to the various API (GDI) drawing functions which by default use pixels > regardless of the VB Scale units you are using. > >> Also, I was able to drag the GDI vertical line with MouseMove >> when NO underlying graphics were plotted. However, when >> underlying graphics are plotted, and the MouseMove event is used -- >> multiple vertical lines are being placed instead of just >> one line which can be dragged across the PBox (I use vbInvert). >> Consequently, it appears ScaleX and ScaleY are somehow >> conflicting with GDI (MoveTo, LineTo) since the GDI (MoveTo, >> LineTo) worked previously when rescaling to actual PBox pixel >> dimensions. > > Actually the problem is highly unlikely to be caused by your use of ScaleX > and ScaleY unless you are using them incorrectly or your code is failing > in some other way. With these sort of things it is very easy to have > problems caused by a specific part of your code and to erroneously connect > those problems with some other part of your code which is not in itself > causing the problem, especially when you are trying new things. > >> FWIW heres my new code: > > I've looked at that but to be honest I always have problems following code > unless I can see all the variable declarations and other relevant things > so that I know both their type and their scope and also so that I know > things like whether or not you are using or manipulating the Autredraw > property anywhere in your code. So, rather than ask lots of questions > about the code you have posted here is an example that I've just written > using a PictureBox with its Scale properties set up exactly the same as > your own and which uses the ScaleX and ScaleY functions to calculate the > appropriate pixel values from the PicBox MouseMove VB Scale coordinates so > that it can draw the line using the MoveToEx and LineTo GDI methods that > you are using yourself. To check it out paste the code into a VB Form > containing a PictureBox and change the hard coded path "c:\temp1jan1.jpg" > to a picture that exists on your own system. Then run the code and click > the left Mouse Button on the Picture Box. It should draw a line and then > move that line in response to horizontal movement of the mouse whilst you > are still holding down the button. When you release the button the line > will be left at the last position at which it was drawn and you will then > be able to click the mouse button elsewhere on the PictureBox to start and > drag another line. It all works fine on my own system. Check it out and > let mw know how it behaves on your own. > > Mike > > Option Explicit > Private Declare Function MoveToEx Lib "gdi32" _ > (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, _ > lpPoint As POINTAPI) As Long > Private Declare Function LineTo Lib "gdi32" _ > (ByVal hdc As Long, ByVal x As Long, ByVal y As Long) _ > As Long > Private Type POINTAPI > x As Long > y As Long > End Type > Private oldX As Long > Private pt1 As POINTAPI > Private picTop As Long, picBottom As Long > > Private Sub Form_Load() > Me.Move 0, 0 > Me.Show: Me.Refresh > With picGraph > picGraph.Scale (0, 0.089)-(530, 0.047376) > picGraph.DrawMode = vbCopyPen > picGraph.PaintPicture LoadPicture("c:\temp\jan1.jpg"), _ > .ScaleLeft, .ScaleTop, _ > .ScaleWidth, .ScaleHeight > .DrawMode = vbInvert > ' store the top and bottom pixel coordinates, which > ' will remain the same unless we resize the PicBox > picTop = .ScaleY(0, .ScaleMode, vbPixels) > picBottom = .ScaleY(.ScaleHeight, .ScaleMode, vbPixels) > End With > End Sub > > Private Sub picGraph_MouseDown(Button As Integer, _ > Shift As Integer, x As Single, y As Single) > If (Button And 1) = 1 Then > With picGraph > ' set oldX to initial position of line > oldX = .ScaleX(x - .ScaleLeft, .ScaleMode, vbPixels) > ' draw the initial line > MoveToEx .hdc, oldX, picTop, pt1 > LineTo .hdc, oldX, picBottom > End With > End If > End Sub > > Private Sub picGraph_MouseMove(Button As Integer, _ > Shift As Integer, x As Single, y As Single) > If (Button And 1) = 1 Then > With picGraph > ' redraw the line at its previous position > ' in order to erase it (vbInvert drawing) > MoveToEx .hdc, oldX, picTop, pt1 > LineTo .hdc, oldX, picBottom > ' set oldX to the pixel value of the new position > oldX = .ScaleX(x - .ScaleLeft, .ScaleMode, vbPixels) > ' draw the line at its new position > MoveToEx .hdc, oldX, picTop, pt1 > LineTo .hdc, oldX, picBottom > End With > End If > End Sub > > > "David" <dw85745***@earthlink.net> wrote in message Whatever you do you need to maintain the actual data that each plotted line news:ezdj5jw4JHA.1380@TK2MSFTNGP05.phx.gbl... > Thanks Mike. I do have one more question if you > don't mind. In MSChart you can click on the plotted > line and it will be identified by squares. Only thing I > can think of how this may be done is: > 1) Enum all plotted data sets, or > 2) Have a table of plotted dataset colors and use > API: GetPixel to find which dataset then reloop the > dataset at a larger step increment to ID the line. > This will work unless there are multiple lines of the > same color. Any ideas how this is done? or other drawn chart element represents because the lines themselves are only an approximation of the data due to the "whole pixel" limitation of anything you draw on the screen and you cannot therefore accurately extrapolate the actual data merely by examining the drawn line. But I'm sure you are doing that anyway and that your current problem is actually identifying which data set the user intended to select by examining the point that he clicked on the displayed chart. There are all sorts of different ways of doing this depending on the type of graph or chart you are drawing. In some cases you can create enclosed regions and use the PtInRegion API to determine whether the user has clicked in a particular region and in other cases doing it that way causes more problems than it solves. There are of course all sorts of other ways. To be perfectly honest I don't often get involved in drawing or maintaining graphs of data and so I'm not really the best person to ask. There are others here who know much more about it than I do and who will probably respond soon. There is one simple method that I would suggest which can be easily applied to all sorts of drawn graphs and charts and that is to maintain a second copy of the chart in memory and to draw your graph or chart both into the copy that gets displayed to the screen and into the second copy in memory. I don't mean a "second copy" as in a backbuffer or Autoredraw buffer of the displayed copy, I mean a completely separate copy in memory which never gets displayed. Any background stuff (background grids or pictures or whatever) and any foreground grids (if there are any) that might overlay the actual chart data are drawn only into the "display" copy of the chart. The actual chart data itself (your drawn lines or whatever) is drawn into both the "display" (in whatever colour you wish to display) copy and into the "second copy in memory" (in a colour that is unique for each element). In that way the displayed chart shows the background and grids and the chart data and any foreground grids etc whereas the hidden "second copy in memory" contains /only/ the actual drawn chart data. You should use a DIBSection instead of a Screen Compatible bitmap for the "second copy in memory" because a DIBSection can contain the full range of 24 bit colour values (16 million RGB values) regardless of the colour depth of the display on which your code is running, whereas a Screen Compatible bitmap (such as the Screen or a VB Form or a VB PictureBox) is limited in its range of available colours by the colour depth of the machine on which it is running. For each element of your drawing (for each drawn data line or whatever) you select a unique colour value (a Long in the range 1 to 16777216, reserving zero (black) for the background) and you associate that specific colour value with that specific data element in your main data. You then drawn your data line (or whatever) into the hidden "second copy in memory" using the selected unique colour. You also draw the same data line (or whatever) into the display copy of the chart using whatever colour you wish (whatever colour suits your purposes and looks nice on the display). In that way you can draw the individual data lines or whatever in the displayed chart using any colour you wish. You can even draw them all in the same colour if you wish (although that of course is an unlikely requirement) and your code will in all cases still be able to tell them apart because each data element is drawn in a unique colour in the hidden DIBSection. Then when the user clicks the chart on the display you determine the pixel x,y coordinates of the point he has clicked in the way you are currently doing but instead of examining the displayed chart image at that point you instead examine the colour at that point in the hidden "second copy" in memory (the DIBSection). Since the DBSection contains /only/ the drawn data elements and /none/ of the background image or grids or anything else, and since each individual data element is associated with its own unique colour, you can determine the data element that the user intended to select simply by the colour of the clicked point in the DIBSection. This method also automatically takes into account the "ZOrder" of the drawn elements, just as is the case in the MS Chart control. This method is useful in all sorts of circumstances, although as I have said I don't usually get involved in drawing graphs of data and there are probably half a dozen or more different ways of doing it that I don't know about and I'm sure that others here will post their own suggested methods if you would prefer not to use the method I have suggested. Mike Again -- Thank you for your time and effort on my behalf.
Interesting idea using a hidden DC with lines of different colors but IMHO seems a long way around the block to ID a line as well as memory intensive -- that's my first impression -- and I don't have a better solution at this time. David Show quoteHide quote "Michael Williams" <M***@WhiskeyAndCoke.com> wrote in message news:uG7EjM34JHA.1092@TK2MSFTNGP06.phx.gbl... > "David" <dw85745***@earthlink.net> wrote in message > news:ezdj5jw4JHA.1380@TK2MSFTNGP05.phx.gbl... > >> Thanks Mike. I do have one more question if you >> don't mind. In MSChart you can click on the plotted >> line and it will be identified by squares. Only thing I >> can think of how this may be done is: >> 1) Enum all plotted data sets, or >> 2) Have a table of plotted dataset colors and use >> API: GetPixel to find which dataset then reloop the >> dataset at a larger step increment to ID the line. >> This will work unless there are multiple lines of the >> same color. Any ideas how this is done? > > Whatever you do you need to maintain the actual data that each plotted > line or other drawn chart element represents because the lines themselves > are only an approximation of the data due to the "whole pixel" limitation > of anything you draw on the screen and you cannot therefore accurately > extrapolate the actual data merely by examining the drawn line. But I'm > sure you are doing that anyway and that your current problem is actually > identifying which data set the user intended to select by examining the > point that he clicked on the displayed chart. There are all sorts of > different ways of doing this depending on the type of graph or chart you > are drawing. In some cases you can create enclosed regions and use the > PtInRegion API to determine whether the user has clicked in a particular > region and in other cases doing it that way causes more problems than it > solves. There are of course all sorts of other ways. > > To be perfectly honest I don't often get involved in drawing or > maintaining graphs of data and so I'm not really the best person to ask. > There are others here who know much more about it than I do and who will > probably respond soon. There is one simple method that I would suggest > which can be easily applied to all sorts of drawn graphs and charts and > that is to maintain a second copy of the chart in memory and to draw your > graph or chart both into the copy that gets displayed to the screen and > into the second copy in memory. I don't mean a "second copy" as in a > backbuffer or Autoredraw buffer of the displayed copy, I mean a completely > separate copy in memory which never gets displayed. > > Any background stuff (background grids or pictures or whatever) and any > foreground grids (if there are any) that might overlay the actual chart > data are drawn only into the "display" copy of the chart. The actual chart > data itself (your drawn lines or whatever) is drawn into both the > "display" (in whatever colour you wish to display) copy and into the > "second copy in memory" (in a colour that is unique for each element). In > that way the displayed chart shows the background and grids and the chart > data and any foreground grids etc whereas the hidden "second copy in > memory" contains /only/ the actual drawn chart data. You should use a > DIBSection instead of a Screen Compatible bitmap for the "second copy in > memory" because a DIBSection can contain the full range of 24 bit colour > values (16 million RGB values) regardless of the colour depth of the > display on which your code is running, whereas a Screen Compatible bitmap > (such as the Screen or a VB Form or a VB PictureBox) is limited in its > range of available colours by the colour depth of the machine on which it > is running. > > For each element of your drawing (for each drawn data line or whatever) > you select a unique colour value (a Long in the range 1 to 16777216, > reserving zero (black) for the background) and you associate that specific > colour value with that specific data element in your main data. You then > drawn your data line (or whatever) into the hidden "second copy in memory" > using the selected unique colour. You also draw the same data line (or > whatever) into the display copy of the chart using whatever colour you > wish (whatever colour suits your purposes and looks nice on the display). > In that way you can draw the individual data lines or whatever in the > displayed chart using any colour you wish. You can even draw them all in > the same colour if you wish (although that of course is an unlikely > requirement) and your code will in all cases still be able to tell them > apart because each data element is drawn in a unique colour in the hidden > DIBSection. > > Then when the user clicks the chart on the display you determine the pixel > x,y coordinates of the point he has clicked in the way you are currently > doing but instead of examining the displayed chart image at that point you > instead examine the colour at that point in the hidden "second copy" in > memory (the DIBSection). Since the DBSection contains /only/ the drawn > data elements and /none/ of the background image or grids or anything > else, and since each individual data element is associated with its own > unique colour, you can determine the data element that the user intended > to select simply by the colour of the clicked point in the DIBSection. > This method also automatically takes into account the "ZOrder" of the > drawn elements, just as is the case in the MS Chart control. This method > is useful in all sorts of circumstances, although as I have said I don't > usually get involved in drawing graphs of data and there are probably half > a dozen or more different ways of doing it that I don't know about and I'm > sure that others here will post their own suggested methods if you would > prefer not to use the method I have suggested. > > Mike > > > > "David" <dw85745***@earthlink.net> wrote in message It certainly is overkill just to ID some lines, but I have no real idea of news:OK7zw194JHA.4272@TK2MSFTNGP04.phx.gbl... > Again -- Thank you for your time and effort on my behalf. > Interesting idea using a hidden DC with lines of different > colors but IMHO seems a long way around the block to > ID a line as well as memory intensive -- that's my first > impression -- and I don't have a better solution at this time. what sort of charts or graphs you are drawing and so I offered it as a solution because of its flexibility. Mike
Show quote
Hide quote
"David" <dw85745***@earthlink.net> wrote in message There's a good description of how to create a line selecting routine here:news:ezdj5jw4JHA.1380@TK2MSFTNGP05.phx.gbl... > snip I do have one more question if you don't mind.. > > In MSChart you can click on the plotted line and it will be identified by > squares. > > Only thing I can think of how this may be done is: > > 1) Enum all plotted data sets, or > 2) Have a table of plotted dataset colors and use API: GetPixel to find > which dataset then reloop the dataset at a larger step increment to ID the > line. This will work unless there are multiple lines of the same color. > > Any ideas how this is done? http://msdn.microsoft.com/en-us/library/ms969920.aspx Thanks Mr. Hahn will review.
David Show quoteHide quote "James Hahn" <jh***@yahoo.com> wrote in message news:OyJuOdb5JHA.4404@TK2MSFTNGP04.phx.gbl... > "David" <dw85745***@earthlink.net> wrote in message > news:ezdj5jw4JHA.1380@TK2MSFTNGP05.phx.gbl... >> snip I do have one more question if you don't mind.. >> >> In MSChart you can click on the plotted line and it will be identified by >> squares. >> >> Only thing I can think of how this may be done is: >> >> 1) Enum all plotted data sets, or >> 2) Have a table of plotted dataset colors and use API: GetPixel to find >> which dataset then reloop the dataset at a larger step increment to ID >> the line. This will work unless there are multiple lines of the same >> color. >> >> Any ideas how this is done? > > There's a good description of how to create a line selecting routine here: > http://msdn.microsoft.com/en-us/library/ms969920.aspx
What files should I distribute (SAPI 5.3)?
How to test for array? DLL in Visual BASIC 6 Mayayana and others: Know The Notes now for 98SE using MM's new 'Never Replace' scheme regfree-loading Format function question..... Finding the biggest number out of 8 variables WMI and WIN2003 100% quandry Adding Text- to -Speech functionality (SAPI 5) to my app |
|||||||||||||||||||||||