My question is very straightforward.
Is there any way to make the background of Richtextbox control transparent. Or is it possible at all?
Printable View
My question is very straightforward.
Is there any way to make the background of Richtextbox control transparent. Or is it possible at all?
Try setting its borderstyle to rtfNoBorder, and its backcolor to the same back color as your form.
You could subclass the RTFBox window and whenever you recieve a message WM_ERASEBKND you could send a WM_PRINTCLIENT message to the window below the rich text box to make it draw itself onto the rich text box's background.
There are probably other ways - what, exactly, do you want to show through the rich text box?
Hope this helps,
Duncan
That sounds like an interesting solution MerrionComputin. How would you code that?
Bother - doesn't work...when you scroll the rich text box, the see through bit scrolls away which looks might weird.
I have a picture on my form. I want that this picture to be seen through the RichTextBox.
MerrionComputin - I have no idea about subclassing. Could you please post a code snippet of the logic you have mentioned. Thanks for your response.
Subclassing 101
(Note: some of the detail has been reduced for clarity)
1. What is subclassing?
Each and every window has a message queue and a message processing loop. During the normal course of operation the window takes one message off the queue, decides whether to process it or not, acts on the message and then moves on to the next message.
For example, when you press a key while the focus is on the rich text box the operating system queues a WM_KEYDOWN a WM_KEYUP and a WM_CHAR message to the rich text box's message queue. The rich text box reads these off and decides whether the keypress causes it to change it's content (i.e. if it is a printable character). If so it adds the character to it's internal buffer, calculates where the character needs to be printed and sets that part of the window to be invalidated. This causes a WM_ERASEBKND and then a WM_PAINT message to be added to it's queue. In response to these it paints the update region with the defined background colour and then draws the character on top of it.
Subclassing is writing your own procedure to handle these messages and instructing the window to use this. You can then alter the default behaviour that happens when a message occurs - in our example you can prevent the rich text box using the default colour to redraw the background and get it to use a copy of the underlying window instead. Those messages whose default behaviour is OK to you are simply passed on to the existing message handler to deal with.
2. How is it done?
What you have to do is write your window message handling proc to a predefined format and then get the address of this procedure and call the SetWindowLong API to set this to be the window's message handler. The defined format is:
VB Code:
Public gOldWndProc As Long '\\ --[VB_WindowProc]-------------------------------------------------------- '\\ 'typedef LRESULT (CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM); '\\ Parameters: '\\ hwnd - window handle receiving message '\\ wMsg - The window message (WM_..etc.) '\\ wParam - First message parameter '\\ lParam - Second message parameter '\\ -------------------------------------------------------------------------------- '\\ (c) 2001 - Merrion Computing. '\\ Please check [url]http://www.merrioncomputing.com[/url] for updates. '\\ -------------------------------------------------------------------------------- Public Function VB_WindowProc(ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long '\\ Process the messages here End Function [/code] Note that this proc must be defined as public and be in a [b].bas[/b] module. And the call (in the form load, usually) to set this to be your rich text box's message handker to it is: [code] Private Declare Function SetWindowLongApi Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long Private Const GWL_WNDPROC = (-4) Private Sub Form_Load() gOldWndProc = SetWindowLongApi(RichText1.hwnd, GWL_WNDPROC, AddressOf VB_WindowProc) End Sub
...to be continued...
3. Decoding the windows message
There are a very large number of predefined window messages. The one we are interested in is WM_ERASEBKGND = &H14. However they each have very different parameter requirements - for example if you want to erase a background you only need to know the Device context that needs to be erased, whereas for a WM_CHAR message you need to know which character was pressed, the repetitions, the scan code etc. However there are only two parameters available for all this information to be passed - wParam and lParam. This means that the content of these two parameters depends on the type of message being sent....for WM_ERASEBKND the wParam member is zero always and the lParam member is a handle to the device context that needs to be erased.
4. Passing the other messages on
Since you don't really want to have to write the code for every single window message you need to delegate (pass on) those that you aren't interested in to the existing window procedure. You do this with the CallWindowProc API call...
Code:Public gOldWndProc As Long
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
private Declare Function DefWindowProc Lib "user32" Alias "DefWindowProcA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
'\\ --[VB_WindowProc]--------------------------------------------------------
'\\ 'typedef LRESULT (CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM);
'\\ Parameters:
'\\ hwnd - window handle receiving message
'\\ wMsg - The window message (WM_..etc.)
'\\ wParam - First message parameter
'\\ lParam - Second message parameter
'\\ --------------------------------------------------------------------------------
'\\ (c) 2001 - Merrion Computing.
'\\ Please check http://www.merrioncomputing.com for updates.
'\\ --------------------------------------------------------------------------------
Public Function VB_WindowProc(ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
'\\ Process the messages here
If msg = WM_ERASEBKND Then
'\\ hDC is in lParam
Else
If gOldWndProc = 0 Then
VB_Windowproc = DefWindowProc(hWnd, uMsg, wParam, lParam)
Else
VB_Windowproc = CallWindowproc(gOldWndProc, hWnd, uMsg, wParam, lParam)
End If
End If
End Function
5. Drawbacks
The most obvious drawback in using subclassing is that any runtime error that occurs in a subclassing routine will crash the entire application. If you are in debug mode it will crash the debugger as well.
Also in order to decode the wParam and lParam values you will need to know about things like memory addresses and bitwise comparisons and cutting long values into 4 bytes etc. that Visual basic doesn't usually involve.
Thirdly the overhead of writing a new VB_Windowproc for each different subclassing operation you want to perform soon becomes mightily tedius.
6. Shortcut to subclassing
Fortunately a number of controls (including EventVB) exist that make this easier. To subclass the rich text box with the EventVB.dll :
HTH,Code:'\\ In form
Dim WithEvents vbLink As EventVB.ApiFunctions
Dim WithEvents vbRTFWnd As EventVB.ApiWindow
Private Sub Form_Load()
Set vbLink = New EventVB.ApiFunctions
Set vbRTFWnd = New EventVB.ApiWindow
vbRtfWnd.hwnd = Me.RichTextbox1.hwnd
'\\ Subclass the window
vbLink.SubclassedWindows.Add vbRTFWnd
End Sub
Private Sub vbRTFWnd_WindowMessageFired(ByVal msg As WindowMessages,ByVal wParam As Long ,ByVal lParam As Long, Cancel As Boolean, ProcRet As Long)
If msg = WM_ERASEBKND Then
'\\ Prevent default processing
Cancel = True
ProcRet = 1
End If
End Sub
Duncan
ROFL
Right - it turns out all that subclassing stuff isn't needed at all.
The following (with EventVB) works:
VB Code:
Dim vbLink As EventVB.ApiFunctions Dim vbWndRtf As EventVB.ApiWindow Private Sub Form_Load() Set vbLink = New EventVB.ApiFunctions Set vbWndRtf = New EventVB.ApiWindow With vbWndRtf .hwnd = RichText1.hwnd .DeviceContext.Backstyle = TRANSPARENT .SetWindowStyle WS_EX_TRANSPARENT, True End With End Sub
And it looks pretty smart - I think I'm gonna use this in some of my apps...
HTH,
Duncan
Wow!!! That is one hell of a OCX!!! Very coool.
I will take a look at it.
Hi MerrionComputin,
Yo have really given me a fantastic start on whole stuff. thanks a heap. Franky I dont really like the idea of subclassing. It simple crashes your system for no reason. Do you have any idea why does it crash so often. Anyway keep posting your suggestions. I am really learning!!!
Subclassing doesn't crash all that often if you take care with it. The main thing is to make sure no run time errors occur in the subclassed part of the code as this will cause VB to exit. To do this, you absolutely must have Option Explicit specified everywhere and haveQuote:
Do you have any idea why does it crash so often.
in your VB WndProc.VB Code:
On Error Resume Next
If you are careful then the amazing capabilities exposed by subclassing are worth the risk. With EventVB this risk should be reduced anyway as there are many people using it so more sets of eyes catching any bugs...
HTH,
Duncan