-
Jan 15th, 2022, 02:01 AM
#1
Thread Starter
Frenzied Member
How Do I Draw Translucent Shapes ?
I'm working on duplicating a public domain indicator that is written in ThinkScript.
I have an old VB6 charting app and have come a long way in recreating this indicator in it.
The only thing left is the translucent shading within the channel.
Here is what it looks like in ThinkorSwing trading platform.
Here is what I've done so far in my VB6 charting app.
I have done translucent rectangles within my app for the purpose of creating 'zones'.
However, I'm not sure what to do about wavy shapes like the green/red channel you see in the images above.
Any suggestions?
TIA
-
Jan 15th, 2022, 04:31 AM
#2
Re: How Do I Draw Translucent Shapes ?
You could use raster operations (Merge) to simulate transparency:
Code:
Private Sub Form_Load()
Dim lX As Long
Dim fV As Single
Dim lC As Long
Dim lY As Long
ScaleMode = vbPixels
AutoRedraw = True
BackColor = 0
Randomize 7
lY = ScaleHeight / 2
DrawMode = vbMergePen
For lX = 0 To ScaleWidth - 1
fV = (fV * 10 + (Rnd * 2 - 1)) / 11
If fV >= 0 Then
lC = &HFF
Else
lC = &HFF00&
End If
lY = lY + fV * 10
If (lX Mod 10) = 0 Then
Line (lX - 3, lY - (Rnd * 100) / 2)-Step(6, Rnd(0) * 100), lC, BF
End If
Line (lX, lY - 50)-Step(0, 100), lC And &H4040&, BF
Next
End Sub
Last edited by The trick; Jan 15th, 2022 at 10:54 AM.
-
Jan 15th, 2022, 10:08 AM
#3
Re: How Do I Draw Translucent Shapes ?
Translucency is a tricky thing. Even in PhotoShop or PSP, there are many methods for merging two images/layers. You might use the alpha channel RGBA, but that's sort of a separate issue, as you can just make one whole image translucent over another (which it looks like what you want), and that doesn't require the alpha channel at all.
I'm not saying I know how to do it, but there are two things I can think of, one of which I do very often.
1) Excel does an excellent job of translucency.
That's how I do it ... by automating Excel and generating my translucencies in Excel. Here's another example where I start out with a template, and then generate these graphs, totally with VB6 automation:
(That gray band is over the red and blue traces.)
Using Excel even solves the printing problems, as it just does it. Now, if you want to print these things into a PDF, that's an entirely different problem. I've searched high-and-low and only found one PDF print driver that will correctly handle these things. Without even looking, and bet big odds that none of the PDF options written in VB6 would correctly do it. The one I've found that works is Power PDF from Nuance.
And now, the other way that comes to mind:
2) You could write something with the GdiPlus API that's available to us. The GdiPlus will certainly do it. However, before I started writing my own, I'd search these forums for LaVolpe's work. Before he left us for greener pastures, he did a tremendous amount of work on displaying images in VB6, often using the GdiPlus. I'd be a bit surprised if he didn't have something in the CodeBank that would do this. I've never personally done it this way though.
Good Luck.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Jan 15th, 2022, 10:22 AM
#4
Re: How Do I Draw Translucent Shapes ?
-
Jan 15th, 2022, 03:30 PM
#5
Thread Starter
Frenzied Member
Re: How Do I Draw Translucent Shapes ?
Originally Posted by The trick
You could use raster operations (Merge) to simulate transparency:
Code:
Private Sub Form_Load()
Dim lX As Long
Dim fV As Single
Dim lC As Long
Dim lY As Long
ScaleMode = vbPixels
AutoRedraw = True
BackColor = 0
Randomize 7
lY = ScaleHeight / 2
DrawMode = vbMergePen
For lX = 0 To ScaleWidth - 1
fV = (fV * 10 + (Rnd * 2 - 1)) / 11
If fV >= 0 Then
lC = &HFF
Else
lC = &HFF00&
End If
lY = lY + fV * 10
If (lX Mod 10) = 0 Then
Line (lX - 3, lY - (Rnd * 100) / 2)-Step(6, Rnd(0) * 100), lC, BF
End If
Line (lX, lY - 50)-Step(0, 100), lC And &H4040&, BF
Next
End Sub
Thanks for the example code. I ran it and it looks like it has potential. Of course I'll have to study it to understand what's going on. But thanks!
-
Jan 15th, 2022, 03:35 PM
#6
Thread Starter
Frenzied Member
Re: How Do I Draw Translucent Shapes ?
Thanks for your suggestions. :-)
-
Jan 15th, 2022, 03:37 PM
#7
Thread Starter
Frenzied Member
Re: How Do I Draw Translucent Shapes ?
Originally Posted by jpbro
Oh no, I'm not adverse to it. I embrace it with all my might! I use the RichClient5 for another application I have. I'll check out these links and hopefully will be able to glean enough to get this task done. Thanks!
-
Jan 15th, 2022, 11:51 PM
#8
Re: How Do I Draw Translucent Shapes ?
Originally Posted by webbiz
Oh no, I'm not adverse to it. I embrace it with all my might! I use the RichClient5 for another application I have. I'll check out these links and hopefully will be able to glean enough to get this task done. Thanks!
Cool If you are willing to share the VB6 code you have so far, I'd be happy to try it out with an RC6 transparent overlay.
-
Jan 16th, 2022, 12:00 AM
#9
Thread Starter
Frenzied Member
Re: How Do I Draw Translucent Shapes ?
Originally Posted by jpbro
Cool If you are willing to share the VB6 code you have so far, I'd be happy to try it out with an RC6 transparent overlay.
I won't be able to provide the code as there is just so much of it.
But it can be simply simulated.
Place a picturebox onto a form and draw a few lines using the .LINE routine.
Then add the RC6 stuff on top.
I'd be interested to see if they can coexist since I need to do the shading over a picturebox with lots of .LINE lines and boxes on it.
**The candlesticks on the chart you see on the images posted earlier are all drawn using .LINE()().
:-)
-
Jan 16th, 2022, 01:38 PM
#10
Re: How Do I Draw Translucent Shapes ?
Here's a highly simplified example (only draws one colour translucent for example):
Code:
Option Explicit
Private Type PointDbl
x As Double
y As Double
End Type
Private Sub Picture1_Click()
Dim ii As Long
Dim l_Index As Long
Dim la_Points() As PointDbl
Dim l_Y1 As Long
Dim l_Y2 As Long
' Setup the picturebox
Me.Picture1.BackColor = RGB(40, 40, 40)
Me.Picture1.ScaleMode = vbPixels ' Easier to work with pixels
Me.Picture1.ForeColor = vbRed
Me.Picture1.AutoRedraw = True
Me.Picture1.DrawWidth = 3
' Generate some random lines and transparent overlay points
ReDim la_Points((Me.Picture1.ScaleWidth - 30) / 15 * 2 + 4)
For ii = 15 To Me.Picture1.ScaleWidth - 10 Step 15
l_Y1 = Rnd * 120
l_Y2 = Rnd * 100
Me.Picture1.Line (ii, (Me.Picture1.ScaleHeight / 2) - l_Y1)-(ii, (Me.Picture1.ScaleHeight / 2) + l_Y2)
l_Index = l_Index + 1
If l_Index = 1 Then
la_Points(0).y = (Me.Picture1.ScaleHeight / 2) - (l_Y1 / 2)
la_Points(UBound(la_Points)).y = la_Points(0).y
la_Points(UBound(la_Points) - 1).y = (Me.Picture1.ScaleHeight / 2) + (l_Y2 / 2)
End If
With la_Points(l_Index)
.x = ii
.y = (Me.Picture1.ScaleHeight / 2) - (l_Y1 / 2)
End With
With la_Points(UBound(la_Points) - 1 - l_Index)
.x = ii
.y = (Me.Picture1.ScaleHeight / 2) + (l_Y2 / 2)
End With
Next ii
' Draw transparent overlay on PictureBox above lines
Dim lo_Surface As cCairoSurface
Set lo_Surface = Cairo.CreateSurface(Me.Picture1.ScaleWidth, Me.Picture1.ScaleHeight)
With lo_Surface.CreateContext
.PolygonPtr VarPtr(la_Points(0)), UBound(la_Points) + 1, , splNormal
.SetSourceColor RGB(20, 180, 20), 0.7
.Fill
End With
lo_Surface.DrawToDC Me.Picture1.hDC, , , , , , , , , vbSrcPaint ' vbSercPaint is our magic constant that draws the translucent overlay
End Sub
The above code draws the following on a PictureBox:
If you can, I'd recommend drawing everything with RC6/Cairo (including you lines/candles).
-
Jan 16th, 2022, 03:38 PM
#11
Thread Starter
Frenzied Member
Re: How Do I Draw Translucent Shapes ?
Originally Posted by jpbro
Here's a highly simplified example (only draws one colour translucent for example):
Code:
Option Explicit
Private Type PointDbl
x As Double
y As Double
End Type
Private Sub Picture1_Click()
Dim ii As Long
Dim l_Index As Long
Dim la_Points() As PointDbl
Dim l_Y1 As Long
Dim l_Y2 As Long
' Setup the picturebox
Me.Picture1.BackColor = RGB(40, 40, 40)
Me.Picture1.ScaleMode = vbPixels ' Easier to work with pixels
Me.Picture1.ForeColor = vbRed
Me.Picture1.AutoRedraw = True
Me.Picture1.DrawWidth = 3
' Generate some random lines and transparent overlay points
ReDim la_Points((Me.Picture1.ScaleWidth - 30) / 15 * 2 + 4)
For ii = 15 To Me.Picture1.ScaleWidth - 10 Step 15
l_Y1 = Rnd * 120
l_Y2 = Rnd * 100
Me.Picture1.Line (ii, (Me.Picture1.ScaleHeight / 2) - l_Y1)-(ii, (Me.Picture1.ScaleHeight / 2) + l_Y2)
l_Index = l_Index + 1
If l_Index = 1 Then
la_Points(0).y = (Me.Picture1.ScaleHeight / 2) - (l_Y1 / 2)
la_Points(UBound(la_Points)).y = la_Points(0).y
la_Points(UBound(la_Points) - 1).y = (Me.Picture1.ScaleHeight / 2) + (l_Y2 / 2)
End If
With la_Points(l_Index)
.x = ii
.y = (Me.Picture1.ScaleHeight / 2) - (l_Y1 / 2)
End With
With la_Points(UBound(la_Points) - 1 - l_Index)
.x = ii
.y = (Me.Picture1.ScaleHeight / 2) + (l_Y2 / 2)
End With
Next ii
' Draw transparent overlay on PictureBox above lines
Dim lo_Surface As cCairoSurface
Set lo_Surface = Cairo.CreateSurface(Me.Picture1.ScaleWidth, Me.Picture1.ScaleHeight)
With lo_Surface.CreateContext
.PolygonPtr VarPtr(la_Points(0)), UBound(la_Points) + 1, , splNormal
.SetSourceColor RGB(20, 180, 20), 0.7
.Fill
End With
lo_Surface.DrawToDC Me.Picture1.hDC, , , , , , , , , vbSrcPaint ' vbSercPaint is our magic constant that draws the translucent overlay
End Sub
The above code draws the following on a PictureBox:
If you can, I'd recommend drawing everything with RC6/Cairo (including you lines/candles).
Thank you so much for providing this.
This looks like it would do the trick assuming it is fast.
I suppose I could draw everything with RC6/Cairo once I learned it. I wish there was documentation that explained the process in simple terms as I have a simple mind and not a lot of time.
If I were to draw my price candles and lines using Cairo, what would be the benefit? Would it draw/refresh faster?
BTW, I added the RC6 in References. I've not read enough at the time of this reply to determine what I should do with the other .dll's such as cairo_sqlite.dll, etc.
Are you aware of anyone that may have put together a 'beginners' hold-by-hand tutorial on using RC6, Cairo, etc.?
Sorry if I come across basic, but I am not a vb6 pro. My application was created by only learning just enough to get a task done and then move to the next. And it has been many years since I wrote this thing so there is still much that is over my head.
THANK YOU for your assistance with this example. I'll be breaking it down carefully line-by-line to learn its application as it appears to be exactly what I need. :-)
-
Jan 16th, 2022, 10:21 PM
#12
Thread Starter
Frenzied Member
Re: How Do I Draw Translucent Shapes ?
Originally Posted by jpbro
Here's a highly simplified example (only draws one colour translucent for example):
Code:
Option Explicit
Private Type PointDbl
x As Double
y As Double
End Type
Private Sub Picture1_Click()
Dim ii As Long
Dim l_Index As Long
Dim la_Points() As PointDbl
Dim l_Y1 As Long
Dim l_Y2 As Long
' Setup the picturebox
Me.Picture1.BackColor = RGB(40, 40, 40)
Me.Picture1.ScaleMode = vbPixels ' Easier to work with pixels
Me.Picture1.ForeColor = vbRed
Me.Picture1.AutoRedraw = True
Me.Picture1.DrawWidth = 3
' Generate some random lines and transparent overlay points
ReDim la_Points((Me.Picture1.ScaleWidth - 30) / 15 * 2 + 4)
For ii = 15 To Me.Picture1.ScaleWidth - 10 Step 15
l_Y1 = Rnd * 120
l_Y2 = Rnd * 100
Me.Picture1.Line (ii, (Me.Picture1.ScaleHeight / 2) - l_Y1)-(ii, (Me.Picture1.ScaleHeight / 2) + l_Y2)
l_Index = l_Index + 1
If l_Index = 1 Then
la_Points(0).y = (Me.Picture1.ScaleHeight / 2) - (l_Y1 / 2)
la_Points(UBound(la_Points)).y = la_Points(0).y
la_Points(UBound(la_Points) - 1).y = (Me.Picture1.ScaleHeight / 2) + (l_Y2 / 2)
End If
With la_Points(l_Index)
.x = ii
.y = (Me.Picture1.ScaleHeight / 2) - (l_Y1 / 2)
End With
With la_Points(UBound(la_Points) - 1 - l_Index)
.x = ii
.y = (Me.Picture1.ScaleHeight / 2) + (l_Y2 / 2)
End With
Next ii
' Draw transparent overlay on PictureBox above lines
Dim lo_Surface As cCairoSurface
Set lo_Surface = Cairo.CreateSurface(Me.Picture1.ScaleWidth, Me.Picture1.ScaleHeight)
With lo_Surface.CreateContext
.PolygonPtr VarPtr(la_Points(0)), UBound(la_Points) + 1, , splNormal
.SetSourceColor RGB(20, 180, 20), 0.7
.Fill
End With
lo_Surface.DrawToDC Me.Picture1.hDC, , , , , , , , , vbSrcPaint ' vbSercPaint is our magic constant that draws the translucent overlay
End Sub
The above code draws the following on a PictureBox:
If you can, I'd recommend drawing everything with RC6/Cairo (including you lines/candles).
I'm scratching my head on this one.
Here is the SUB that plots the MomentumKeltner channel on my chart (frmChart.pctChart).
I assumed that in order to add the green translucent shading only within the channel I had to fill my Points array with the x,y going forward and back again.
The whole chart turns green. Not exactly what I hoped for.
Then I thought maybe I need to tie the last array index to the first array index, you know, as in closing the loop. So I had added sngPointsGrn(UBound(sngPointsGrn)) = sngPointsGrn(0) as a hail mary attempt and it didn't change anything. The problem is I just don't know what format of x/y .PolygonPtr wants from me.
This SUB draws the red and green wave channel onto the chart and works in doing this.
Unfortunately I'm stuck on trying to fill that wave channel with a translucent color.
In the code below, I was trying to just do green first to see if I could figure it out before moving to red. No go.
Code:
Public Sub PlotMomentumKeltner()
Dim i As Integer
Dim x1 As Long
Dim x2 As Long
Dim Y1Line1 As Long
Dim Y2Line1 As Long
Dim Y1Line2 As Long
Dim Y2Line2 As Long
Dim Y As Single
Dim oldDrawWidth As Long
Dim sLastArrow As String
Dim sngPointsGrn() As PointSingle
Dim sngPointsRed() As PointSingle
Dim iPointsIndexFwd As Integer
Dim iPointsIndexBack As Integer
oldDrawWidth = frmChart.pctChart.DrawWidth
frmChart.pctChart.DrawWidth = 1
iPointsIndexFwd = 0
iPointsIndexBack = (gLastBarRecNum - gFirstBarRecNum) * 4
ReDim sngPointsGrn(iPointsIndexBack)
'Plot Channel
sLastArrow = "None" 'initialize
For i = gFirstBarRecNum To gLastBarRecNum - 1
x1 = GetXFromRec(i)
Y1Line1 = GetYFromPrice(gMKLine1(i))
x2 = GetXFromRec(i + 1)
Y2Line1 = GetYFromPrice(gMKLine1(i + 1))
Y1Line2 = GetYFromPrice(gMKLine2(i))
Y2Line2 = GetYFromPrice(gMKLine2(i + 1))
'Draw lines green or red based on Hold value
If gMKHold(i + 1) = 1 Then
frmChart.pctChart.Line (x1, Y1Line1)-(x2, Y2Line1), vbGreen
frmChart.pctChart.Line (x1, Y1Line2)-(x2, Y2Line2), vbGreen
'Store x,y points for channel shading
If iPointsIndexFwd = 0 Then
sngPointsGrn(iPointsIndexFwd).X = x1
sngPointsGrn(iPointsIndexFwd).Y = Y1Line1
sngPointsGrn(iPointsIndexFwd + 1).X = x2
sngPointsGrn(iPointsIndexFwd + 1).Y = Y2Line1
iPointsIndexFwd = iPointsIndexFwd + 2
sngPointsGrn(iPointsIndexBack).X = x1
sngPointsGrn(iPointsIndexBack).Y = Y1Line2
sngPointsGrn(iPointsIndexBack - 1).X = x2
sngPointsGrn(iPointsIndexBack - 1).Y = Y2Line2
iPointsIndexBack = iPointsIndexBack - 2
Else
sngPointsGrn(iPointsIndexFwd).X = x2
sngPointsGrn(iPointsIndexFwd).Y = Y2Line1
iPointsIndexFwd = iPointsIndexFwd + 1
sngPointsGrn(iPointsIndexBack).X = x2
sngPointsGrn(iPointsIndexBack).Y = Y2Line2
iPointsIndexBack = iPointsIndexBack - 1
End If
Else
frmChart.pctChart.Line (x1, Y1Line1)-(x2, Y2Line1), vbRed
frmChart.pctChart.Line (x1, Y1Line2)-(x2, Y2Line2), vbRed
End If
If glDTF = DAILY Then
If AverageData(i).fClose > gMKLine2(i) And sLastArrow <> "UP" Then 'Price Up
If gMKLine1(i) < AverageData(i).fLow Then
Y = GetYFromPrice(gMKLine1(i))
Else
Y = GetYFromPrice(AverageData(i).fLow)
End If
DrawUpArrowMK frmChart.pctChart, GetXFromRec(i), Y + 50
sLastArrow = "UP"
ElseIf AverageData(i).fClose < gMKLine1(i) And sLastArrow <> "DOWN" Then 'Price Down
If gMKLine2(i) > AverageData(i).fHigh Then
Y = GetYFromPrice(gMKLine2(i))
Else
Y = GetYFromPrice(AverageData(i).fHigh)
End If
DrawDownArrowMK frmChart.pctChart, GetXFromRec(i), Y - 50
sLastArrow = "DOWN"
End If
Else
If MarketData(i).fClose > gMKLine2(i) Then 'Price Up
DrawUpArrowMK frmChart.pctChart, GetXFromRec(i), GetYFromPrice(gMKLine1(i))
ElseIf MarketData(i).fClose < gMKLine1(i) Then 'Price Down
DrawDownArrowMK frmChart.pctChart, GetXFromRec(i), GetYFromPrice(gMKLine2(i))
End If
End If
Next i
sngPointsGrn(UBound(sngPointsGrn)) = sngPointsGrn(0)
'Draw translucent channel overlay
Dim orig_ScaleMode As Integer
orig_ScaleMode = frmChart.pctChart.ScaleMode
frmChart.pctChart.ScaleMode = vbPixels
'First creating a surface based on the full size of the pctChart.
Dim cht_Surface As cCairoSurface
Set cht_Surface = Cairo.CreateSurface(frmChart.pctChart.ScaleWidth, frmChart.pctChart.ScaleHeight)
With cht_Surface.CreateContext
.PolygonPtr VarPtr(sngPointsGrn(0)), UBound(sngPointsGrn) + 1, , splNormal
.SetSourceColor vbGreen, 0.7
.Fill
End With
cht_Surface.DrawToDC frmChart.pctChart.hdc, , , , , , , , , vbSrcPaint
frmChart.pctChart.DrawWidth = oldDrawWidth 'restore
frmChart.pctChart.ScaleMode = orig_ScaleMode 'restore
End Sub
-
Jan 16th, 2022, 11:12 PM
#13
Re: How Do I Draw Translucent Shapes ?
I'm working on a better demo, but it won't be ready until tomorrow at the earliest.
In the meantime, I notice you are using Singles in your array, but you are calling .PolygonPtr which expects Doubles. Does it work if you use .PolygonSinglePtr instead?
-
Jan 17th, 2022, 01:16 AM
#14
Thread Starter
Frenzied Member
Re: How Do I Draw Translucent Shapes ?
Originally Posted by jpbro
I'm working on a better demo, but it won't be ready until tomorrow at the earliest.
In the meantime, I notice you are using Singles in your array, but you are calling .PolygonPtr which expects Doubles. Does it work if you use .PolygonSinglePtr instead?
It actually changed behavior.
Instead of shading the whole picturebox in green, it produced this:
Attachment 183621
I'll keep experimenting, but I think at this point the issue has to be the x/y I fill the sngPointGrn() array with.
:-)
-
Jan 18th, 2022, 11:46 AM
#15
Re: How Do I Draw Translucent Shapes ?
Unfortunately your image wasn't attached properly. There's a forum bug and images only get attached if you write the post in Advanced Mode.
I'm also attaching a sample project that produces the following output:
The project is by no means perfect, but I think it might be worth some study to get you pointed in the right direction. Unfortunately, I've been busier than expected the past couple of days, so I haven't had a chance to perfect it (but I might have a chance to give it a second pass later this week).
Anyway, take a look and hopefully there's enough there to help.
Candles.zip
-
Jan 18th, 2022, 02:37 PM
#16
Thread Starter
Frenzied Member
Re: How Do I Draw Translucent Shapes ?
Originally Posted by jpbro
Unfortunately your image wasn't attached properly. There's a forum bug and images only get attached if you write the post in Advanced Mode.
I'm also attaching a sample project that produces the following output:
The project is by no means perfect, but I think it might be worth some study to get you pointed in the right direction. Unfortunately, I've been busier than expected the past couple of days, so I haven't had a chance to perfect it (but I might have a chance to give it a second pass later this week).
Anyway, take a look and hopefully there's enough there to help.
Candles.zip
Thanks for the code example. I didn't know there was an advanced mode. Found it. :-)
I was having trouble getting the coordinates right but have figured out where I was messing up. It helps sometimes to pencil it out first before punching in x's and y's.
Here is what I'm struggling with now that I know the cairo code will work.
This is a section of the daily chart of Microsoft with the channel drawn in green and red sections using my Thinkorswim trading platform.
On my VB6 application, I have successfully recreated the channel as shown here.
Now all I need to do is figure out how to shade the channel green and red in alpha translucent next.
Clearly .PolygonPtr or one of the 'single' or 'double' .Polygon.. methods will do the trick. But I have to figure out how to fill the points array and that's making my head hurt.
Currently the channel is being drawn using the .Line() routine (that I will be replacing with the Cairo Line shortly).
Each price bar on the chart has a BAR number ranging from "gFirstBarRecNum" to "gLastBarRecNum".
I have functions that I wrote that makes it easy to get the X and Y values.
GetXFromRec(<record number>) ' returns X coordinate based on price bar's record number
GetYFromPrice(<price float value>) 'returns Y coordinate based on the price provided
So what I did was loop from gFirstBarRecNum to gLastBarRecNum - 1 getting the X/Y coordinate and drawing a line from 'current record' to 'current record + 1'.
So for EACH RECORD there are two X/Y coordinates. One for the top channel line and the other for the bottom channel line.
So I'm wondering, should I draw a translucent vertical triangle for EACH RECORD from top_channel-line x/y to bottom_channel-line (vertical triangle rather than vertical line because each record takes up a few pixels in width) or use the PolygonPtr? With the PolygonPtr, wouldn't I need to provide x/y coordinates in a CIRCULAR (return to first x/y) manner, requiring a means of reversing direction within the array? Trying to figure out how to do this and include the change in color from red to green to red along the way is taunting.
Your thoughts?
-
Jan 18th, 2022, 02:51 PM
#17
Re: How Do I Draw Translucent Shapes ?
Olaf will probably have a better idea, but here's what I would try:
Right now you have all the points you need drawing lines, but if you switch to PolygonPtr using an array of the same points (as PointerDbl structures), then you will be able to use the Fill method to fill in the translucent middle bit. The "trick" is:
1) Your array should be twice the number of chart X axis ticks that you are drawing, to have enough room to hold the "high" points and the "low" points of the translucent blob.
2) You will store the "high" points in the array from left to right (e.g. left most high point at index 0, right most high point at index Ubound()/2-1) The "low" points will be stored from right to left, so the right-most low point is stored at index Ubound()-1 and the left-most low point is stored at index UBound()/2
That will force the polygon to be drawn in a "loop" much like you might do with pen and paper without lifting the pen from the page. When that's done, you will have a closed shaped that you can fill with any colour. You will then draw one polygon for each change of colour (red/green). At the end, if you want to add the non-translucent outline across the top and bottom, you can do a second pass with your current line drawing routine to place the lines on top of the translucent run of polygons.
-
Jan 18th, 2022, 03:25 PM
#18
Thread Starter
Frenzied Member
Re: How Do I Draw Translucent Shapes ?
Originally Posted by jpbro
Olaf will probably have a better idea, but here's what I would try:
Right now you have all the points you need drawing lines, but if you switch to PolygonPtr using an array of the same points (as PointerDbl structures), then you will be able to use the Fill method to fill in the translucent middle bit. The "trick" is:
1) Your array should be twice the number of chart X axis ticks that you are drawing, to have enough room to hold the "high" points and the "low" points of the translucent blob.
2) You will store the "high" points in the array from left to right (e.g. left most high point at index 0, right most high point at index Ubound()/2-1) The "low" points will be stored from right to left, so the right-most low point is stored at index Ubound()-1 and the left-most low point is stored at index UBound()/2
That will force the polygon to be drawn in a "loop" much like you might do with pen and paper without lifting the pen from the page. When that's done, you will have a closed shaped that you can fill with any colour. You will then draw one polygon for each change of colour (red/green). At the end, if you want to add the non-translucent outline across the top and bottom, you can do a second pass with your current line drawing routine to place the lines on top of the translucent run of polygons.
That's what I was thinking, but it is the array of x/y that's going to be difficult (at least in my mind).
My current loop goes from the first record to the last record.
But along the way, I have to change colors. So I would have to dimension the array before entering the loop, although right now it is the loop that eventually arrives at the transition color record. So this would likely mean I would have to loop through the Hold() first to count how many records for green, then red, then green, etc.
From there, I would likely have to divide up the loop into a green loop and a red loop, as I would have to redim the points array for each loop based on the green and red record counts.
If I'm not mistaken, wouldn't I need to have my last array element equal to the first element to 'close' the polygon loop? If so, I would have to double the elements and ADD ONE for the final connect. Right?
This seems so messy when I write it out.
-
Jan 18th, 2022, 03:37 PM
#19
Re: How Do I Draw Translucent Shapes ?
Whenever you have to change colours, that's when you stop moving through the full array of values and start processing the bottom line values (adding them to your polygon array backwards. You don't need the extra points to close the shape yourself, RC6 will close it for you.
Here's my code that only deals with one colour (from the sample project that I sent):
Code:
' Generate the points for the top of our translucent trend blob
For ii = 0 To mo_Candles.Count - 1
Set lo_Candle = mo_Candles(ii)
With la_PointsHigh(ii)
.X = m_CandleSpacePx + (m_CandleSpacePx + m_CandleWidthPx) * ii
.Y = l_Height - (lo_Candle.High - (ii Mod 5) - l_ChartLow) * l_DollarsPerPixel
End With
Next ii
' Generate the points for the bottom of our translucent trend blob
For ii = mo_Candles.Count - 1 To 0 Step -1
Set lo_Candle = mo_Candles(ii)
With la_PointsHigh(mo_Candles.Count + mo_Candles.Count - 1 - ii)
.X = m_CandleSpacePx + (m_CandleSpacePx + m_CandleWidthPx) * ii
.Y = l_Height - (lo_Candle.Low + (ii Mod 8) - l_ChartLow) * l_DollarsPerPixel
End With
Next ii
It's a bit messy with the recalculations of the same values and stuff (I should move that out to a function or at least store the duped values in a variable), but it should illustrate the point. You would have to break the above up into chunks to perform each time the colour changes.
I'll see if I can tweak the example code to switch colours.
-
Jan 18th, 2022, 05:27 PM
#20
Thread Starter
Frenzied Member
Re: How Do I Draw Translucent Shapes ?
Originally Posted by jpbro
Unfortunately your image wasn't attached properly. There's a forum bug and images only get attached if you write the post in Advanced Mode.
I'm also attaching a sample project that produces the following output:
The project is by no means perfect, but I think it might be worth some study to get you pointed in the right direction. Unfortunately, I've been busier than expected the past couple of days, so I haven't had a chance to perfect it (but I might have a chance to give it a second pass later this week).
Anyway, take a look and hopefully there's enough there to help.
Candles.zip
You put a lot of effort into drawing candlesticks in the code you posted. I'm wondering why? All those .AddCandles and temp prices (interesting looking candles btw
The original suggestion of adding a few lines was to test that the 'blob' as you put it won't over-write them. I could not determine where the 'blob' code kicked in.
Anyway, Olaf posted some code under my other thread
https://www.vbforums.com/showthread....rguments-error
I was trying to use it on my chart but nothing shows up. Haven't yet figured out why.
In his example he paints the picturebox white. I want to draw on top of my existing picturebox without whitewashing it clean so I left that part off.
Code:
Public Sub PlotMomentumKeltner()
Dim i As Integer
Dim x1 As Long
Dim x2 As Long
Dim Y1Line1 As Long
Dim Y2Line1 As Long
Dim Y1Line2 As Long
Dim Y2Line2 As Long
Dim Y As Single
Dim oldDrawWidth As Long
Dim sLastArrow As String
Dim sngPointsGrn() As PointDouble
Dim sngPointsRed() As PointSingle
Dim iPointsIndexFwd As Integer
Dim iPointsIndexBack As Integer
Dim lPixelWidth As Long
Dim Coord(0 To 1) As POINTAPI
oldDrawWidth = frmChart.pctChart.DrawWidth
frmChart.pctChart.DrawWidth = 1
iPointsIndexFwd = 0
iPointsIndexBack = (gLastBarRecNum - gFirstBarRecNum) * 4
ReDim sngPointsGrn(5)
'Plot Channel
sLastArrow = "None" 'initialize
For i = gFirstBarRecNum To gLastBarRecNum - 1
x1 = GetXFromRec(i)
Y1Line1 = GetYFromPrice(gMKLine1(i))
x2 = GetXFromRec(i + 1)
Y2Line1 = GetYFromPrice(gMKLine1(i + 1))
Y1Line2 = GetYFromPrice(gMKLine2(i))
Y2Line2 = GetYFromPrice(gMKLine2(i + 1))
'Draw lines green or red based on Hold value
If gMKHold(i + 1) = 1 Then
frmChart.pctChart.Line (x1, Y1Line1)-(x2, Y2Line1), vbGreen
frmChart.pctChart.Line (x1, Y1Line2)-(x2, Y2Line2), vbGreen
Else
frmChart.pctChart.Line (x1, Y1Line1)-(x2, Y2Line1), vbRed
frmChart.pctChart.Line (x1, Y1Line2)-(x2, Y2Line2), vbRed
End If
If glDTF = DAILY Then
If AverageData(i).fClose > gMKLine2(i) And sLastArrow <> "UP" Then 'Price Up
If gMKLine1(i) < AverageData(i).fLow Then
Y = GetYFromPrice(gMKLine1(i))
Else
Y = GetYFromPrice(AverageData(i).fLow)
End If
DrawUpArrowMK frmChart.pctChart, GetXFromRec(i), Y + 50
sLastArrow = "UP"
ElseIf AverageData(i).fClose < gMKLine1(i) And sLastArrow <> "DOWN" Then 'Price Down
If gMKLine2(i) > AverageData(i).fHigh Then
Y = GetYFromPrice(gMKLine2(i))
Else
Y = GetYFromPrice(AverageData(i).fHigh)
End If
DrawDownArrowMK frmChart.pctChart, GetXFromRec(i), Y - 50
sLastArrow = "DOWN"
End If
Else
If MarketData(i).fClose > gMKLine2(i) Then 'Price Up
DrawUpArrowMK frmChart.pctChart, GetXFromRec(i), GetYFromPrice(gMKLine1(i))
ElseIf MarketData(i).fClose < gMKLine1(i) Then 'Price Down
DrawDownArrowMK frmChart.pctChart, GetXFromRec(i), GetYFromPrice(gMKLine2(i))
End If
End If
Next i
'BELOW IS WHERE I AM ATTEMPTING TO DRAW VERTICAL LINES USING CAIRO
Dim orig_ScaleMode As Integer
orig_ScaleMode = frmChart.pctChart.ScaleMode
frmChart.pctChart.ScaleMode = vbPixels
Set pctChartCC = Cairo.CreateSurface(frmChart.pctChart.ScaleWidth, frmChart.pctChart.ScaleHeight).CreateContext
For i = gFirstBarRecNum To gLastBarRecNum
Coord(0).X = ConvertTwipsToPixels(GetXFromRec(i), 0)
Coord(1).X = Coord(0).X
Coord(0).Y = ConvertTwipsToPixels(GetYFromPrice(gMKLine1(i)), 0)
Coord(1).Y = ConvertTwipsToPixels(GetYFromPrice(gMKLine2(i)), 0)
'Draw lines green or red based on Hold value
If gMKHold(i + 1) = 1 Then 'Green
pctChartCC.DrawLine Coord(0).X, Coord(0).Y, Coord(1).X, Coord(1).Y, True, 2, vbGreen
Else 'Red
pctChartCC.DrawLine Coord(0).X, Coord(0).Y, Coord(1).X, Coord(1).Y, True, 2, vbRed
End If
Next i
BackBufferToPicBox
frmChart.pctChart.DrawWidth = oldDrawWidth 'restore
frmChart.pctChart.ScaleMode = orig_ScaleMode 'restore
End Sub
This code draws my channel but the .DrawLine isn't showing up. Not sure where I'm going wrong. Hmmm
-
Jan 18th, 2022, 06:09 PM
#21
Re: How Do I Draw Translucent Shapes ?
Originally Posted by webbiz
You put a lot of effort into drawing candlesticks in the code you posted. I'm wondering why?
It wasn't too much trouble. Main reasons I did it are
1) I wasn't sure my written ideas were getting across clearly, and I thought code might be clearer.
2) I'm trying to get more proficient at the RC6 Cairo stuff myself, and I prefer working with a "real" project when I'm learning.
3) Why not, sometimes it's fun to try something new
Originally Posted by webbiz
All those .AddCandles and temp prices (interesting looking candles btw
For the data, I just Googled for candlestick chart data and found a CSV of Netflix stock data from 2016 or something like that ;(
Code:
Anyway, Olaf posted some code under my other thread
Olaf is suggesting that you draw everything in Cairo and then dump the full rendered Cairo image to your PB. Your code is trying to draw part with PB methods and part with Cairo methods. In that case you will need to draw the Cairo surface over the PB with the following code (instead of calling BackBufferToPicBox):
Code:
pctChartCC.DrawToDC frmChart.pctChart.hDC, , , , , , , , , vbSrcPaint ' vbSrcPaint is our magic constant that draws the translucent overlay
Does that draw your blob?
If that doesn't work, one thing I like to do is make sure my Cairo drawing is working as expected. I do this by saving a JPG or PNG of the surface (using the .WriteContentToJpgFile or .WriteContentToPngFile methods) and then view the saved image to see if it appears as I think it should.
-
Jan 18th, 2022, 08:55 PM
#22
Thread Starter
Frenzied Member
Re: How Do I Draw Translucent Shapes ?
Originally Posted by jpbro
Code:
pctChartCC.DrawToDC frmChart.pctChart.hDC, , , , , , , , , vbSrcPaint ' vbSrcPaint is our magic constant that draws the translucent overlay
Does that draw your blob?
If that doesn't work, one thing I like to do is make sure my Cairo drawing is working as expected. I do this by saving a JPG or PNG of the surface (using the .WriteContentToJpgFile or .WriteContentToPngFile methods) and then view the saved image to see if it appears as I think it should.
Hey, as long as you are having fun I say 'go for it'! :-)
Well, it turns out that .DrawLine is not available to me unless I "Set = pctChartCC = Cairo.CreateSurface()".
But then I don't have access to .DrawToDC.
Olaf mentioned that it would be easy to replace my existing Line() code with the DrawLine() cairo code. You believe he is suggesting I revamp the whole thing? Are we talking about converting all my TWIPS code over to Pixels? That would be a killer project as I have so much code that references based on Twips. If only I knew then what I know now and started using Pixels from the beginning. Not sure it would be feasible at this point. I'll make a copy of my code to test the waters once I feel comfortable using this Cairo code to see what it would take for a full-blown revamp.
-
Jan 18th, 2022, 09:40 PM
#23
Re: How Do I Draw Translucent Shapes ?
Originally Posted by webbiz
Hey, as long as you are having fun I say 'go for it'! :-)
Originally Posted by webbiz
Well, it turns out that .DrawLine is not available to me unless I "Set = pctChartCC = Cairo.CreateSurface()".
But then I don't have access to .DrawToDC.
Sorry, that was my mistake, I didn't scroll far enough right to see that you were calling CreateContext at the end of the line (and CC should have been my clue that the variable held a Context and not a Surface).
What if you try this instead:
Code:
Dim pctChartSrf As cCairoSurface
Set pctChartSrf = Cairo.CreateSurface(frmChart.pctChart.ScaleWidth, frmChart.pctChart.ScaleHeight)
Set pctChartCC = pctChartSrf.CreateContext
Then at the bottom instead of calling BackBufferToPicBox, try the following:
Code:
pctChartSrf.DrawToDC frmChart.pctChart.hDC, , , , , , , , , vbSrcPaint ' vbSrcPaint is our magic constant that draws the translucent overlay
Does that work?
Originally Posted by webbiz
Olaf mentioned that it would be easy to replace my existing Line() code with the DrawLine() cairo code. You believe he is suggesting I revamp the whole thing? Are we talking about converting all my TWIPS code over to Pixels? That would be a killer project as I have so much code that references based on Twips. If only I knew then what I know now and started using Pixels from the beginning. Not sure it would be feasible at this point. I'll make a copy of my code to test the waters once I feel comfortable using this Cairo code to see what it would take for a full-blown revamp.
I won't put words in Olaf's mouth, but I personally recommended using Cairo (and pixels) all the way down if possible, and that was how I understood Olaf's post. That said, I didn't know how far along you were in the project already, so perhaps it's too big a job. It might not be as big as you think though - you can easily convert Twips to Pixels (and back) using the RC6 New_C.Displays.Primary.TwipsPerPixelX and .TwipsPerPixelY properties.
-
Jan 18th, 2022, 09:49 PM
#24
Thread Starter
Frenzied Member
Re: How Do I Draw Translucent Shapes ?
Originally Posted by jpbro
I won't put words in Olaf's mouth, but I personally recommended using Cairo (and pixels) all the way down if possible, and that was how I understood Olaf's post. That said, I didn't know how far along you were in the project already, so perhaps it's too big a job. It might not be as big as you think though - you can easily convert Twips to Pixels (and back) using the RC6 New_C.Displays.Primary.TwipsPerPixelX and .TwipsPerPixelY properties.
My old VB6 app has this function:
Code:
Public Function ConvertTwipsToPixels(lngTwips As Long, _
lngDirection As Long) As Long
'Handle to device
Dim lngDC As Long
Dim lngPixelsPerInch As Long
Const nTwipsPerInch = 1440
On Error GoTo ConvertTwipsToPixels_Error
lngDC = GetDC(0)
If (lngDirection = 0) Then 'Horizontal
lngPixelsPerInch = GetDeviceCaps(lngDC, WU_LOGPIXELSX)
Else 'Vertical
lngPixelsPerInch = GetDeviceCaps(lngDC, WU_LOGPIXELSY)
End If
lngDC = ReleaseDC(0, lngDC)
ConvertTwipsToPixels = (lngTwips / nTwipsPerInch) * lngPixelsPerInch
On Error GoTo 0
Exit Function
ConvertTwipsToPixels_Error:
Call LogError("modGlobals", Err.number, Err.description, "ConvertTwipsToPixels", Erl)
End Function
I used this earlier today for the reason you mentioned, but can't verify whether it worked or not because nothing was drawn on my chart.
Don't recall where I got this as I know I didn't write it. Good ole copy-n-paste.
Nothing yet to report on the code lines you just provided. Thanks.
-
Jan 18th, 2022, 09:58 PM
#25
Thread Starter
Frenzied Member
Re: How Do I Draw Translucent Shapes ?
Originally Posted by jpbro
What if you try this instead:
Code:
Dim pctChartSrf As cCairoSurface
Set pctChartSrf = Cairo.CreateSurface(frmChart.pctChart.ScaleWidth, frmChart.pctChart.ScaleHeight)
Set pctChartCC = pctChartSrf.CreateContext
Then at the bottom instead of calling BackBufferToPicBox, try the following:
Code:
pctChartSrf.DrawToDC frmChart.pctChart.hDC, , , , , , , , , vbSrcPaint ' vbSrcPaint is our magic constant that draws the translucent overlay
Does that work?
After candlesticks are drawn and after the channel is drawn, this code starts.
Note I hard coded in the x/y values.
Still nothing.
Code:
Dim orig_ScaleMode As Integer
orig_ScaleMode = frmChart.pctChart.ScaleMode
frmChart.pctChart.ScaleMode = vbPixels
Dim pctChartSrf As cCairoSurface
Set pctChartSrf = Cairo.CreateSurface(frmChart.pctChart.ScaleWidth, frmChart.pctChart.ScaleHeight)
pctChartCc.DrawLine 100, 100, 500, 500, True, 3, vbGreen, 0.3
pctChartSrf.DrawToDC frmChart.pctChart.hdc, , , , , , , , , vbSrcPaint ' vbSrcPaint is our magic constant that draws the translucent overlay
-
Jan 18th, 2022, 10:03 PM
#26
Re: How Do I Draw Translucent Shapes ?
I think your ConvertTwipsToPixels function looks OK, except it should return Single instead of Long. At some DPIs the math won't result in an integer, and your calculations will end up being off by a bit.
-
Jan 18th, 2022, 10:06 PM
#27
Re: How Do I Draw Translucent Shapes ?
Do you have:
Code:
Set pctChartCC = pctChartSrf.CreateContext
Immediately after
Code:
Set pctChartSrf = Cairo.CreateSurface(frmChart.pctChart.ScaleWidth, frmChart.pctChart.ScaleHeight)
? It's not in your snippet.
-
Jan 18th, 2022, 11:02 PM
#28
Thread Starter
Frenzied Member
Re: How Do I Draw Translucent Shapes ?
Originally Posted by jpbro
Do you have:
Code:
Set pctChartCC = pctChartSrf.CreateContext
Immediately after
Code:
Set pctChartSrf = Cairo.CreateSurface(frmChart.pctChart.ScaleWidth, frmChart.pctChart.ScaleHeight)
? It's not in your snippet.
No. I have that in the Declarations section of the Module.
-
Jan 23rd, 2022, 12:09 AM
#29
Re: How Do I Draw Translucent Shapes ?
Sorry for not getting back to you sooner, I got busy with work.
Originally Posted by webbiz
No. I have that in the Declarations section of the Module.
You can't have "Set pctChartCC = pctChartSrf.CreateContext" in the declarations, so I'm a bit confused. Can you post a small sample that will run if I copy & paste it into a new project?
-
Sep 1st, 2022, 01:09 PM
#30
Thread Starter
Frenzied Member
Re: How Do I Draw Translucent Shapes ?
After a bit of absence from my app (life throws curve balls that at times I cannot duck) but now I have some time to get back to this subject again.
As I am pouring through my old vb6 books (like Visual Basic Graphics Programming and Visual Basic Programmer's Guide to the Win32 API) I am left wondering if this question has ever been asked?
"What is the advantage or disadvantage of using Cairo (via vbRichClient6) over using the Win32 API?"
I know that the answer is scattered all over the place in these forums, but haven't been able to find it nailed down in any particular post.
I did search on Cairo, vbRichClient, etc. and get zillions of posts. But it is difficult to learn this way for me. It's like being dropped into the MIDDLE of a conversation and hunting for the very beginning with consecutive logical increments from there is like a needle in a haystack.
I'm also going through the DEMO files again but find it hard to learn Cairo this way. And unfortunately, the DOCUMENTATION part of the vbRichClient site is still empty.
I'll keep plugging along and hopefully some concepts will start to sink in.
Meanwhile, I thought I'd post this in my old thread since it is still 'unresolved' and I'm still trying to figure out the 'transparent' issue, this time also to draw rectangles. LOL!!
-
Sep 1st, 2022, 01:11 PM
#31
Thread Starter
Frenzied Member
Re: How Do I Draw Translucent Shapes ?
Originally Posted by webbiz
After a bit of absence from my app (life throws curve balls that at times I cannot duck) but now I have some time to get back to this subject again.
As I am pouring through my old vb6 books (like Visual Basic Graphics Programming and Visual Basic Programmer's Guide to the Win32 API) I am left wondering if this question has ever been asked?
"What is the advantage or disadvantage of using Cairo (via vbRichClient6) over using the Win32 API?"
I know that the answer is scattered all over the place in these forums, but haven't been able to find it nailed down in any particular post.
I did search on Cairo, vbRichClient, etc. and get zillions of posts. But it is difficult to learn this way for me. It's like being dropped into the MIDDLE of a conversation and hunting for the very beginning with consecutive logical increments from there is like a needle in a haystack.
I'm also going through the DEMO files again but find it hard to learn Cairo this way. And unfortunately, the DOCUMENTATION part of the vbRichClient site is still empty.
I'll keep plugging along and hopefully some concepts will start to sink in.
Meanwhile, I thought I'd post this in my old thread since it is still 'unresolved' and I'm still trying to figure out the 'transparent' issue, this time also to draw rectangles. LOL!!
Oh, and one quick question.
Is it necessary to create a 'surface' to draw with Cairo or can you just draw directly on a vb6 Object like form or picturebox? (I know, probably a dumb question.)
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|