|
Hi , I have a situation where in my text box are different size and font size is different but the content is same , how to syncc up this .
REgards
ARun a
|
|
|
|
|
Thank You,
I completed my program with your sample code very well. I wanted to synchr. several text boxes where only one (as master) has a vertical scroll bar and the others shall follow them.
I think there is one mistake in your initial design. Since all bars fire to all others when moved, the manual control of the program is blocked in an endless loop. Then terminating in Form1 is not possible.
Regards,
Rolfo1
|
|
|
|
|
Your Welcome. Yes, the original code was done for VS 7.1, but if you look in the messages for "Scrolling Test Code for VB2005" you will find the test code I posted in vb for VS 2005. It will work in VS2008 also. Thank you.
|
|
|
|
|
Found a post here:
http://www.techtalkz.com/c-c-sharp/68735-richtextbox-scroll-position.html[^]
That code fixes the scrolling issues I was seeing. Here is a full code sample. Note that this does not address keyboard input that moves the cursor around, only mouse dragging of the scroll bars.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace ScrollSynching
{
public partial class RichTextBoxSynchScroll : RichTextBox
{
#region ScrollMessages
private enum ScrollMessages : uint
{
WM_HSCROLL = 0x0114,
WM_VSCROLL = 0x0115
}
#endregion
#region richedit.h Flags
private enum RichEditFlags : int
{
EM_GETSCROLLPOS = 0x400 + 221,
EM_SETSCROLLPOS = 0x400 + 222
}
#endregion
private double _Yfactor = 1.0d;
[System.Runtime.InteropServices.DllImport("User32", EntryPoint = "SendMessageA", ExactSpelling = false, CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, ref Point lParam);
public RichTextBoxSynchScroll()
{
InitializeComponent();
}
public Point ScrollPos
{
get
{
Point scrollPoint = new Point();
SendMessage(this.Handle, (int)RichEditFlags.EM_GETSCROLLPOS, IntPtr.Zero, ref scrollPoint);
return scrollPoint;
}
set
{
Point original = value;
if (original.Y < 0)
original.Y = 0;
if (original.X < 0)
original.X = 0;
Point factored = value;
factored.Y = (int)((double)original.Y * _Yfactor);
Point result = value;
SendMessage(this.Handle, (int)RichEditFlags.EM_SETSCROLLPOS, IntPtr.Zero, ref factored);
SendMessage(this.Handle, (int)RichEditFlags.EM_GETSCROLLPOS, IntPtr.Zero, ref result);
int loopcount = 0;
int maxloop = 100;
while (result.Y != original.Y)
{
if (result.Y > original.Y)
factored.Y -= (result.Y - original.Y) / 2 - 1;
else if (result.Y < original.Y)
factored.Y += (original.Y - result.Y) / 2 + 1;
SendMessage(this.Handle, (int)RichEditFlags.EM_SETSCROLLPOS, IntPtr.Zero, ref factored);
SendMessage(this.Handle, (int)RichEditFlags.EM_GETSCROLLPOS, IntPtr.Zero, ref result);
loopcount++;
if (loopcount >= maxloop || result.Y == original.Y)
{
_Yfactor = (double)factored.Y / (double)original.Y;
break;
}
}
}
}
static List<RichTextBoxSynchScroll> synchedScrollBarsList = null;
static public void AddToSynch(RichTextBoxSynchScroll ctrl)
{
if((ctrl == null) || (ctrl.Handle == IntPtr.Zero))
{
throw new ArgumentNullException("ctrl is null");
}
if (synchedScrollBarsList == null)
{
synchedScrollBarsList = new List<RichTextBoxSynchScroll>(2);
}
synchedScrollBarsList.Add(ctrl);
}
static public void RemoveFromSynch(RichTextBoxSynchScroll ctrl)
{
if ((ctrl == null) || (ctrl.Handle == IntPtr.Zero))
{
throw new ArgumentNullException("ctrl is null");
}
if (synchedScrollBarsList != null)
{
if (synchedScrollBarsList.Contains(ctrl))
{
synchedScrollBarsList.Remove(ctrl);
}
else
{
throw new ArgumentOutOfRangeException("ctrl not currently synched");
}
}
}
protected override void WndProc(ref Message m)
{
if (m.Msg == (int)ScrollMessages.WM_VSCROLL)
{
foreach (RichTextBoxSynchScroll scrollBar in synchedScrollBarsList)
{
if (scrollBar != this)
{
scrollBar.ScrollPos = this.ScrollPos;
}
}
}
if (m.Msg == (int)ScrollMessages.WM_HSCROLL)
{
foreach (RichTextBoxSynchScroll scrollBar in synchedScrollBarsList)
{
if (scrollBar != this)
{
scrollBar.ScrollPos = this.ScrollPos;
}
}
}
base.WndProc(ref m);
}
}
}
|
|
|
|
|
I am using the Visual C++ 2005 Express Edition (Whidbey) and I have tried to convert the old C++ syntax but I was stucked in this part:
// ===================================================================
// NativeWindow Subclassing
// ===================================================================
__gc class Subclass : public System::Windows::Forms::NativeWindow
{
public:
__delegate void WindowsEventHandler(Object * sender, Message * uMsg);
__event WindowsEventHandler * NativeWindowsEvent;
Subclass(IntPtr pWindowHandle)
{
this->AssignHandle(pWindowHandle);
}
void SendWndProc( System::Windows::Forms::Message * uMsg)
{
__super::WndProc(uMsg);
}
protected: void WndProc( System::Windows::Forms::Message * uMsg)
{
__super::WndProc(uMsg);
if (NativeWindowsEvent != 0)
NativeWindowsEvent(this, uMsg);}
};
The conversion:
// ===================================================================
// NativeWindow Subclassing
// ===================================================================
ref class Subclass : public System::Windows::Forms::NativeWindow
{
public: delegate void WindowsEventHandler(Object ^sender, Message ^uMsg);
event WindowsEventHandler^ NativeWindowsEvent;
Subclass(IntPtr pWindowHandle) {
this->AssignHandle(pWindowHandle);
}
void SendWndProc( System::Windows::Forms::Message ^uMsg ) {
this->WndProc(uMsg); //__super::WndProc(uMsg);
}
protected: void WndProc( System::Windows::Forms::Message ^uMsg ) {
this->WndProc(uMsg); //__super::WndProc(uMsg);
if ( NativeWindowsEvent != nullptr )
NativeWindowsEvent(this, uMsg); }
//private: NativeWindowsEvent(Object^ sender, Message ^uMsg);
};
The error was on the bold part:
Error C3918: usage requires 'Project::Subclass::NativeWindowsEvent' to be a data member, see declaration of 'Project::Subclass::NativeWindowsEvent'
How to solve this?
Thank you very much.
|
|
|
|
|
|
Hi, I tried to compile this code in vs 2005 and it does not work.
It seems hangs.
Can you help?
Thanks
|
|
|
|
|
Nice work.
I'd like to know if your solution still works when RichTextBoxes are replaced with Panels. E.g. there are 2 panels; each has a picturebox. However Panel doesn't have an Panel.VScroll/HScroll event. Do you have any solution to this issue? Thanks.
David ye
|
|
|
|
|
Try this solution from mike-obrien:
http://www.codeproject.com/vb/net/RTFSynchronizedScrolling.asp
Works fine for me.
Mike defines a class which does the whole work. This solution is much more flexible than any other i've seen.
You only have to integrate his class (clsRTFScrollSync) in your project and add a new instance of this class to your project:
Private objScrollSync As New clsRTFScrollSync
In the Form_Load event of your form you then have to add the Textboxes to be sychronized:
Private Sub Form1_Load(...)...
objScrollSync.ScrollBarToSync = ScrollBars.Vertical
objScrollSync.AddControl(RichTextBox1)
objScrollSync.AddControl(RichTextBox2)
End Sub
Thats all.
|
|
|
|
|
I haven't checked out all the new messaging system in VB2005 yet, but here is the new test code (based on the old code) that works in VS2005 if any one wants to give it a try.
'-------------------------------------------------------------
Option Explicit On
Imports System
Imports System.IO
Imports System.Data
Imports System.Text
Imports System.Drawing
Imports System.Collections
Imports System.Windows.Forms
Imports System.Windows.Forms.Message
Imports System.Runtime.InteropServices.Marshal
Public Class Form1
Inherits System.Windows.Forms.Form
#Region " Windows Form Designer generated code "
Public Sub New()
MyBase.New()
'This call is required by the Windows Form Designer.
InitializeComponent()
'Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
Friend WithEvents RichTextBox1 As System.Windows.Forms.RichTextBox
Friend WithEvents RichTextBox2 As System.Windows.Forms.RichTextBox
Friend WithEvents RichTextBox3 As System.Windows.Forms.RichTextBox
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
Me.RichTextBox1 = New System.Windows.Forms.RichTextBox
Me.RichTextBox2 = New System.Windows.Forms.RichTextBox
Me.RichTextBox3 = New System.Windows.Forms.RichTextBox
Me.SuspendLayout()
'
'RichTextBox1
'
Me.RichTextBox1.Location = New System.Drawing.Point(24, 24)
Me.RichTextBox1.Name = "RichTextBox1"
Me.RichTextBox1.Size = New System.Drawing.Size(128, 128)
Me.RichTextBox1.TabIndex = 0
Me.RichTextBox1.Text = "RichTextBox1"
Me.RichTextBox1.WordWrap = False
'
'RichTextBox2
'
Me.RichTextBox2.Location = New System.Drawing.Point(160, 24)
Me.RichTextBox2.Name = "RichTextBox2"
Me.RichTextBox2.Size = New System.Drawing.Size(128, 128)
Me.RichTextBox2.TabIndex = 1
Me.RichTextBox2.Text = "RichTextBox2"
Me.RichTextBox2.WordWrap = False
'
'RichTextBox3
'
Me.RichTextBox3.Location = New System.Drawing.Point(296, 24)
Me.RichTextBox3.Name = "RichTextBox3"
Me.RichTextBox3.Size = New System.Drawing.Size(128, 128)
Me.RichTextBox3.TabIndex = 3
Me.RichTextBox3.Text = "RichTextBox3"
Me.RichTextBox3.WordWrap = False
'
'Form1
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(448, 174)
Me.Controls.Add(Me.RichTextBox3)
Me.Controls.Add(Me.RichTextBox2)
Me.Controls.Add(Me.RichTextBox1)
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)
End Sub
#End Region
'===================================================================
' for NativeWindow and PostMessageA
'===================================================================
Private Const WM_USER As Integer = &H400
Private Const WM_COMMAND As Integer = &H111
Private Const WM_HSCROLL As Integer = &H114
Private Const WM_VSCROLL As Integer = &H115
Private Const EN_UPDATE As Integer = &H400
Private Const EM_GETTHUMB As Integer = &HBE
Private Const SBS_HORZ As Integer = 0
Private Const SBS_VERT As Integer = 1
Private Const SB_THUMBPOSITION As Integer = 4
'===================================================================
' for SubClassing
'===================================================================
Private WithEvents sClass1 As Subclass
Private WithEvents sClass2 As Subclass
Private WithEvents sClass3 As Subclass
Private WithEvents sClassF As Subclass
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' clear the rtb text
RichTextBox1.Text = ""
RichTextBox2.Text = ""
RichTextBox3.Text = ""
' setup the sSubclass
sClass1 = New Subclass(RichTextBox1.Handle)
sClass2 = New Subclass(RichTextBox2.Handle)
sClass3 = New Subclass(RichTextBox3.Handle)
sClassF = New Subclass(Me.Handle)
Dim i As Integer
' put some formated text in the RichTextBox's
While i < 100
RichTextBox1.AppendText(" this is a string " & i & vbCrLf)
RichTextBox2.AppendText(" this is a string " & i & vbCrLf)
RichTextBox3.AppendText(" this is a string " & i & vbCrLf)
If i Mod 4 = 0 Then
RichTextBox1.AppendText(" this is a longer string to force HScroll " & i & vbCrLf)
RichTextBox2.AppendText(" this is a longer string to force HScroll " & i & vbCrLf)
RichTextBox3.AppendText(" this is a longer string to force HScroll " & i & vbCrLf)
End If
i += 1
End While
End Sub
Public Sub sClass_WindowProcedure(ByRef uMsg As Message) Handles sClass1.WindowProcedure, sClass2.WindowProcedure, sClass3.WindowProcedure, sClassF.WindowProcedure
Select Case uMsg.Msg
Case WM_VSCROLL ' WM_VSCROLL Message's for RTB's
If uMsg.HWnd.Equals(RichTextBox1.Handle) Then
'Debug.WriteLine(GetLowWord(uMsg.WParam.ToInt32))
RemoveHandler sClass1.WindowProcedure, AddressOf sClass_WindowProcedure
sClass1.SendWndProc(Message.Create(RichTextBox2.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam))
sClass1.SendWndProc(Message.Create(RichTextBox3.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam))
AddHandler sClass1.WindowProcedure, AddressOf sClass_WindowProcedure
End If
If uMsg.HWnd.Equals(RichTextBox2.Handle) Then
RemoveHandler sClass2.WindowProcedure, AddressOf sClass_WindowProcedure
sClass2.SendWndProc(Message.Create(RichTextBox1.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam))
sClass2.SendWndProc(Message.Create(RichTextBox3.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam))
AddHandler sClass2.WindowProcedure, AddressOf sClass_WindowProcedure
End If
If uMsg.HWnd.Equals(RichTextBox3.Handle) Then
RemoveHandler sClass3.WindowProcedure, AddressOf sClass_WindowProcedure
sClass3.SendWndProc(Message.Create(RichTextBox1.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam))
sClass3.SendWndProc(Message.Create(RichTextBox2.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam))
AddHandler sClass3.WindowProcedure, AddressOf sClass_WindowProcedure
End If
Case WM_HSCROLL ' WM_HSCROLL Message's for RTB's
If uMsg.HWnd.Equals(RichTextBox1.Handle) Then
'Debug.WriteLine(GetLowWord(uMsg.WParam.ToInt32))
RemoveHandler sClass1.WindowProcedure, AddressOf sClass_WindowProcedure
sClass1.SendWndProc(Message.Create(RichTextBox2.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam))
sClass1.SendWndProc(Message.Create(RichTextBox3.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam))
AddHandler sClass1.WindowProcedure, AddressOf sClass_WindowProcedure
End If
If uMsg.HWnd.Equals(RichTextBox2.Handle) Then
RemoveHandler sClass2.WindowProcedure, AddressOf sClass_WindowProcedure
sClass2.SendWndProc(Message.Create(RichTextBox1.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam))
sClass2.SendWndProc(Message.Create(RichTextBox3.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam))
AddHandler sClass2.WindowProcedure, AddressOf sClass_WindowProcedure
End If
If uMsg.HWnd.Equals(RichTextBox3.Handle) Then
RemoveHandler sClass3.WindowProcedure, AddressOf sClass_WindowProcedure
sClass3.SendWndProc(Message.Create(RichTextBox1.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam))
sClass3.SendWndProc(Message.Create(RichTextBox2.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam))
AddHandler sClass3.WindowProcedure, AddressOf sClass_WindowProcedure
End If
Case WM_COMMAND ' Form1 Command messages
If uMsg.LParam.Equals(RichTextBox1.Handle) Then
'Debug.WriteLine("Low: " & GetLowWord(uMsg.WParam.ToInt32))
'Debug.WriteLine("High: " & GetHighWord(uMsg.WParam.ToInt32))
Dim rtbUpdate As Integer = GetHighWord(uMsg.WParam.ToInt32)
'The EN_UPDATE notification message is sent when an
'edit control is about to redraw itself
'so we will look for the EN_UPDATE event message
If rtbUpdate = EN_UPDATE Then '(1024)
'The EM_GETTHUMB message retrieves the position of the
'scroll box (thumb) in the vertical scroll bar only.
'(TODO: Why there is NO horizontal message I can find.)
Dim msg1 As Message
uMsg.Msg = EM_GETTHUMB
msg1 = Message.Create(RichTextBox1.Handle, uMsg.Msg, IntPtr.Zero, IntPtr.Zero)
' send message
RemoveHandler sClass1.WindowProcedure, AddressOf sClass_WindowProcedure
sClass1.SendWndProc(msg1)
AddHandler sClass1.WindowProcedure, AddressOf sClass_WindowProcedure
'Debug.WriteLine("Msg1.Result :" & msg1.Result.ToInt32)
' make sure we resend the message to rtb1 in case we're on rtb2 or rtb3
SetScrollPos(RichTextBox1.Handle, SBS_VERT, msg1.Result.ToInt32, True)
SetScrollPos(RichTextBox2.Handle, SBS_VERT, msg1.Result.ToInt32, True)
SetScrollPos(RichTextBox3.Handle, SBS_VERT, msg1.Result.ToInt32, True)
End If
End If
End Select
End Sub
Private Declare Function GetScrollPos Lib "user32.dll" ( _
ByVal hWnd As IntPtr, _
ByVal nBar As Integer) As Integer
Private Declare Function SetScrollPos Lib "user32.dll" ( _
ByVal hWnd As IntPtr, _
ByVal nBar As Integer, _
ByVal nPos As Integer, _
ByVal bRedraw As Boolean) As Integer
Private Declare Function PostMessageA Lib "user32.dll" ( _
ByVal hwnd As IntPtr, _
ByVal wMsg As Integer, _
ByVal wParam As Integer, _
ByVal lParam As Integer) As Integer
'HScroll
Private Sub RichTextBox1_HScroll(ByVal sender As Object, ByVal e As System.EventArgs) Handles RichTextBox1.HScroll
If Control.MouseButtons = Windows.Forms.MouseButtons.Left Then Exit Sub
If Me.RichTextBox1.ContainsFocus Then
Dim RTB1Position As Integer
RTB1Position = GetScrollPos(RichTextBox1.Handle, SBS_HORZ)
PostMessageA(RichTextBox2.Handle, WM_HSCROLL, SB_THUMBPOSITION + &H10000 * RTB1Position, 0)
PostMessageA(RichTextBox3.Handle, WM_HSCROLL, SB_THUMBPOSITION + &H10000 * RTB1Position, 0)
End If
End Sub
Private Sub RichTextBox2_HScroll(ByVal sender As Object, ByVal e As System.EventArgs) Handles RichTextBox2.HScroll
If Control.MouseButtons = Windows.Forms.MouseButtons.Left Then Exit Sub
If Me.RichTextBox2.ContainsFocus Then
Dim RTB2Position As Integer
RTB2Position = GetScrollPos(RichTextBox2.Handle, SBS_HORZ)
PostMessageA(RichTextBox1.Handle, WM_HSCROLL, SB_THUMBPOSITION + &H10000 * RTB2Position, 0)
PostMessageA(RichTextBox3.Handle, WM_HSCROLL, SB_THUMBPOSITION + &H10000 * RTB2Position, 0)
End If
End Sub
Private Sub RichTextBox3_HScroll(ByVal sender As Object, ByVal e As System.EventArgs) Handles RichTextBox3.HScroll
If Control.MouseButtons = Windows.Forms.MouseButtons.Left Then Exit Sub
If Me.RichTextBox3.ContainsFocus Then
Dim RTB3Position As Integer
RTB3Position = GetScrollPos(RichTextBox3.Handle, SBS_HORZ)
PostMessageA(RichTextBox1.Handle, WM_HSCROLL, SB_THUMBPOSITION + &H10000 * RTB3Position, 0)
PostMessageA(RichTextBox2.Handle, WM_HSCROLL, SB_THUMBPOSITION + &H10000 * RTB3Position, 0)
End If
End Sub
'VScroll
Private Sub RichTextBox1_VScroll(ByVal sender As Object, ByVal e As System.EventArgs) Handles RichTextBox1.VScroll
If Me.RichTextBox1.ContainsFocus Then
Dim RTB1Position As Integer
RTB1Position = GetScrollPos(RichTextBox1.Handle, SBS_VERT)
PostMessageA(RichTextBox2.Handle, WM_VSCROLL, SB_THUMBPOSITION + &H10000 * RTB1Position, 0)
PostMessageA(RichTextBox3.Handle, WM_VSCROLL, SB_THUMBPOSITION + &H10000 * RTB1Position, 0)
End If
End Sub
Private Sub RichTextBox2_VScroll(ByVal sender As Object, ByVal e As System.EventArgs) Handles RichTextBox2.VScroll
If Me.RichTextBox2.ContainsFocus Then
Dim RTB2Position As Integer
RTB2Position = GetScrollPos(RichTextBox2.Handle, SBS_VERT)
PostMessageA(RichTextBox1.Handle, WM_VSCROLL, SB_THUMBPOSITION + &H10000 * RTB2Position, 0)
PostMessageA(RichTextBox3.Handle, WM_VSCROLL, SB_THUMBPOSITION + &H10000 * RTB2Position, 0)
End If
End Sub
Private Sub RichTextBox3_VScroll(ByVal sender As Object, ByVal e As System.EventArgs) Handles RichTextBox3.VScroll
If Me.RichTextBox3.ContainsFocus Then
Dim RTB3Position As Integer
RTB3Position = GetScrollPos(RichTextBox3.Handle, SBS_VERT)
PostMessageA(RichTextBox1.Handle, WM_VSCROLL, SB_THUMBPOSITION + &H10000 * RTB3Position, 0)
PostMessageA(RichTextBox2.Handle, WM_VSCROLL, SB_THUMBPOSITION + &H10000 * RTB3Position, 0)
End If
End Sub
'===================================================================
' Temporary Functions for the Debugger
'===================================================================
Public Function GetLowWord(ByRef pintValue As Int32) As Int32
Return pintValue And &HFFFF
End Function
Public Function GetLowWord(ByRef pudtValue As IntPtr) As Int32
Return GetLowWord(pudtValue.ToInt32)
End Function
Public Function GetHighWord(ByRef pintValue As Int32) As Int32
If (pintValue And &H80000000) = &H80000000 Then
Return ((pintValue And &H7FFF0000) \ &H10000) Or &H8000&
Else
Return (pintValue And &HFFFF0000) \ &H10000
End If
End Function
'===================================================================
' End Temporary Functions for the Debugger
'===================================================================
End Class
Public Class Subclass
'===================================================================
' NativeWindow Subclassing
'===================================================================
Inherits System.Windows.Forms.NativeWindow
Public Event WindowProcedure(ByRef uMsg As Message)
Public Sub New(ByVal pWindowHandle As IntPtr)
MyBase.AssignHandle(pWindowHandle)
End Sub
Protected Overrides Sub WndProc(ByRef uMsg As System.Windows.Forms.Message)
MyBase.WndProc(uMsg)
RaiseEvent WindowProcedure(uMsg)
End Sub
Public Sub SendWndProc(ByRef uMsg As System.Windows.Forms.Message)
MyBase.WndProc(uMsg)
End Sub
End Class
'-----------------------------------------------------
progload
|
|
|
|
|
public partial class FormPDetails : Form<br />
{<br />
public FormPDetails()<br />
{<br />
InitializeComponent();<br />
<br />
sClass1 = new NativeWindowExt(txtHex.Handle);<br />
sClass2 = new NativeWindowExt(txtRaw.Handle);<br />
this.sClass1.NativeWindowsEvent += new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);<br />
this.sClass2.NativeWindowsEvent += new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);<br />
}<br />
<br />
[DllImport("user32.dll")]<br />
private static extern int GetScrollPos(IntPtr hwnd, int nBar);<br />
[DllImport("user32.dll")]<br />
private static extern int SetScrollPos(IntPtr hwnd, int nBar, int nPos, bool bRedraw);<br />
[DllImport("user32.dll", EntryPoint = "PostMessageA")]<br />
private static extern int PostMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);<br />
<br />
const int WM_USER = 0x400;<br />
const int WM_COMMAND = 0x111;<br />
const int WM_HSCROLL = 0x114;<br />
const int WM_VSCROLL = 0x115;<br />
const int EN_UPDATE = 0x400;<br />
const int EM_GETTHUMB = 0xBE;<br />
const int SBS_HORZ = 0x0;<br />
const int SBS_VERT = 0x1;<br />
const int SB_THUMBPOSITION = 4;<br />
<br />
private NativeWindowExt sClass1, sClass2;<br />
<br />
private void txtHex_HScroll(object sender, EventArgs e)<br />
{<br />
if(Control.MouseButtons == MouseButtons.Left)<br />
return;<br />
if(txtHex.ContainsFocus)<br />
{<br />
int iPos = GetScrollPos(txtHex.Handle, SBS_HORZ);<br />
PostMessage(txtRaw.Handle, WM_HSCROLL, SB_THUMBPOSITION + 0x10000 * iPos, 0);<br />
}<br />
}<br />
<br />
private void txtHex_VScroll(object sender, EventArgs e)<br />
{<br />
if(txtHex.ContainsFocus)<br />
{<br />
int iPos = GetScrollPos(txtHex.Handle, SBS_VERT);<br />
PostMessage(txtRaw.Handle, WM_VSCROLL, SB_THUMBPOSITION + 0x10000 * iPos, 0);<br />
}<br />
}<br />
<br />
private void txtRaw_HScroll(object sender, EventArgs e)<br />
{<br />
if(Control.MouseButtons == MouseButtons.Left)<br />
return;<br />
if(txtRaw.ContainsFocus)<br />
{<br />
int iPos = GetScrollPos(txtRaw.Handle, SBS_HORZ);<br />
PostMessage(txtHex.Handle, WM_HSCROLL, SB_THUMBPOSITION + 0x10000 * iPos, 0);<br />
}<br />
}<br />
<br />
private void txtRaw_VScroll(object sender, EventArgs e)<br />
{<br />
if(txtRaw.ContainsFocus)<br />
{<br />
int iPos = GetScrollPos(txtRaw.Handle, SBS_VERT);<br />
PostMessage(txtHex.Handle, WM_VSCROLL, SB_THUMBPOSITION + 0x10000 * iPos, 0);<br />
}<br />
}<br />
<br />
private int GetLowWord(int pIntValue)<br />
{<br />
return pIntValue & 0xFFFF;<br />
}<br />
<br />
private int GetLowWord(IntPtr pUdtValue)<br />
{<br />
return GetLowWord((int)pUdtValue.ToInt32());<br />
}<br />
<br />
private int GetHighWord(int pIntValue)<br />
{<br />
if((pIntValue & 0x80000000) == 0x80000000)<br />
return ((pIntValue & 0x7FFF0000) / 0x10000) | 0x8000;<br />
else<br />
return (int)(pIntValue & 0xFFFF0000) / 0x10000;<br />
}<br />
<br />
public void sClass_WindowProcedure(ref Message uMsg)<br />
{<br />
switch(uMsg.Msg)<br />
{<br />
case WM_VSCROLL:<br />
{<br />
if(uMsg.HWnd.Equals(txtHex.Handle))<br />
{<br />
sClass1.NativeWindowsEvent -= new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);<br />
sClass1.SendWndProc(Message.Create(txtHex.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam));<br />
sClass1.NativeWindowsEvent += new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);<br />
}<br />
if(uMsg.HWnd.Equals(txtRaw.Handle))<br />
{<br />
sClass2.NativeWindowsEvent -= new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);<br />
sClass2.SendWndProc(Message.Create(txtRaw.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam));<br />
sClass2.NativeWindowsEvent += new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);<br />
}<br />
break;<br />
}<br />
case WM_HSCROLL:<br />
{<br />
if(uMsg.HWnd.Equals(txtHex.Handle))<br />
{<br />
sClass2.NativeWindowsEvent -= new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);<br />
sClass2.SendWndProc(Message.Create(txtHex.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam));<br />
sClass2.NativeWindowsEvent += new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);<br />
}<br />
if(uMsg.HWnd.Equals(txtRaw.Handle))<br />
{<br />
sClass2.NativeWindowsEvent -= new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);<br />
sClass2.SendWndProc(Message.Create(txtRaw.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam));<br />
sClass2.NativeWindowsEvent += new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);<br />
}<br />
break;<br />
}<br />
case WM_COMMAND:<br />
{<br />
if(uMsg.LParam.Equals(txtRaw.Handle))<br />
{<br />
int rtbUpdate = GetHighWord((int)uMsg.WParam.ToInt32());<br />
if(rtbUpdate == EN_UPDATE)<br />
{<br />
Message msg1;<br />
uMsg.Msg = EM_GETTHUMB;<br />
msg1 = Message.Create(txtRaw.Handle, uMsg.Msg, IntPtr.Zero, IntPtr.Zero);<br />
sClass2.NativeWindowsEvent -= new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);<br />
sClass2.SendWndProc(msg1);<br />
sClass2.NativeWindowsEvent += new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);<br />
SetScrollPos(txtRaw.Handle, SBS_VERT, msg1.Result.ToInt32(), true);<br />
SetScrollPos(txtRaw.Handle, SBS_VERT, msg1.Result.ToInt32(), true);<br />
SetScrollPos(txtRaw.Handle, SBS_VERT, msg1.Result.ToInt32(), true);<br />
}<br />
}<br />
else if(uMsg.LParam.Equals(txtHex.Handle))<br />
{<br />
int rtbUpdate = GetHighWord((int)uMsg.WParam.ToInt32());<br />
if(rtbUpdate == EN_UPDATE)<br />
{<br />
Message msg1;<br />
uMsg.Msg = EM_GETTHUMB;<br />
msg1 = Message.Create(txtHex.Handle, uMsg.Msg, IntPtr.Zero, IntPtr.Zero);<br />
sClass2.NativeWindowsEvent -= new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);<br />
sClass2.SendWndProc(msg1);<br />
sClass2.NativeWindowsEvent += new NativeWindowExt.WindowsEventHandler(sClass_WindowProcedure);<br />
SetScrollPos(txtHex.Handle, SBS_VERT, msg1.Result.ToInt32(), true);<br />
SetScrollPos(txtHex.Handle, SBS_VERT, msg1.Result.ToInt32(), true);<br />
SetScrollPos(txtHex.Handle, SBS_VERT, msg1.Result.ToInt32(), true);<br />
}<br />
}<br />
break;<br />
}<br />
}<br />
}<br />
}<br />
<br />
public class NativeWindowExt : NativeWindow<br />
{<br />
public NativeWindowExt(IntPtr pWindowHandle)<br />
{<br />
this.AssignHandle(pWindowHandle);<br />
}<br />
<br />
public event WindowsEventHandler NativeWindowsEvent;<br />
public delegate void WindowsEventHandler(ref Message uMsg);<br />
<br />
protected override void WndProc(ref Message m)<br />
{<br />
base.WndProc(ref m);<br />
if(NativeWindowsEvent != null)<br />
NativeWindowsEvent(ref m);<br />
}<br />
<br />
public void SendWndProc(Message uMsg)<br />
{<br />
base.WndProc(ref uMsg);<br />
}<br />
}
|
|
|
|
|
|
Thank You,
Yes, I went to visit the blog a bit a go, He did shorten it up a bit in his C# code.
I appreciate it.
Thanks Again,
progload
|
|
|
|
|
Hellow,
I am new for vb.net programing i like your project very much.But when i run your project then i get this message System.ArithmaticExecption occured in System.drawing.dll additionan information overflow and under flow in the arithmatic operation.Plz give me solution.
|
|
|
|
|
vaibhav tiwari,
I'm not sure what could cause that problem, unless maybe your using .Net 2.0 or 1.0.
None of this code was written for Version 2.0 or the old 1.0, and at this time I don't have 2.0 or the beta 2.0 .Net installed because I am still working on source projects in .Net 1.1 and I don't Install a Beta anything on a production machine.
I'll be glag to try help you if you can supply more info about that error, and what OS and Version of .Net you are using.
Thank you,
progload
|
|
|
|
|
The RichTextBox control is sometimes quite problematic for ascertaining the contents height. Solutions usually involve looking through each line of text in the control and adding font height of each line. Unfortunately richtext in particular can contain other things such as embedded graphics and spacing and so on that muck up this process.
Before delving into the mucky world of rtf codes, I'd thought there might be a shortcut to calculating the height of the content by looking at the scrollbar values on the control (of course, this would apply to any kind of control). Windows seems to internally know the height of the content so that it can calculate the correct height of the scroll thumb.
I wasn't able to understand all that goes on in your code re how to use user32.dll to read a controls scrolling height. Can you please explain or point me in the right direction for documentation?
|
|
|
|
|
|
For each of the uMsg.Create expressions I get the following warning: "Access of shared member or nested type through an instance; qualifying expression will not be evaluated."
msg1 = uMsg.Create(RichTextBox2.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam)
the autocorrect wants to replace uMsg.Create with System.Windows.Forms.Message.Create
I have tried this but it doesn't work. Any ideas? It compiles fine but does not scroll at all.
|
|
|
|
|
Wow,
Matt I never saw this message posted before, realy sorry I missed it.
None of this code was written for Version 2.0 or the old 1.0, and at this time I don't have 2.0 production or the beta 2.0 .Net installed because I am still working on source projects in .Net 1.1 and I don't Install a Beta anything on a production machine.
When I'm done working on 1.1 production code, I'll go get 2.0 Installed and working and see what's up.
Sorry again,
progload
|
|
|
|
|
#pragma once
//==================================================
// Form1.h
//==================================================
namespace TestMultScroll
{
using namespace System;
using namespace System::IO;
using namespace System::Data;
using namespace System::Text;
using namespace System::Drawing;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Runtime::InteropServices;
// ===================================================================
// NativeWindow Subclassing
// ===================================================================
__gc class Subclass : public System::Windows::Forms::NativeWindow
{
public:
__delegate void WindowsEventHandler(Object * sender, Message * uMsg);
__event WindowsEventHandler * NativeWindowsEvent;
Subclass(IntPtr pWindowHandle)
{
this->AssignHandle(pWindowHandle);
}
void SendWndProc( System::Windows::Forms::Message * uMsg)
{
__super::WndProc(uMsg);
}
protected: void WndProc( System::Windows::Forms::Message * uMsg)
{
__super::WndProc(uMsg);
if (NativeWindowsEvent != 0)
NativeWindowsEvent(this, uMsg);
}
};
// ===================================================================
// API Function: GetScrollPos()
// ===================================================================
[DllImport("user32.dll")]
extern int GetScrollPos(IntPtr hWnd, int nBar);
// ===================================================================
// API Function: PostMessageA()
// ===================================================================
[DllImport("user32.dll")]
extern bool PostMessageA(IntPtr hwnd, int wMsg, int wParam, int lParam);
///
/// Summary for Form1
///
/// WARNING: If you change the name of this class, you will need to change the
/// 'Resource File Name' property for the managed resource compiler tool
/// associated with all .resx files this class depends on. Otherwise,
/// the designers will not be able to interact properly with localized
/// resources associated with this form.
///
public __gc class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{
InitializeComponent();
}
protected:
void Dispose(Boolean disposing)
{
if (disposing && components)
{
components->Dispose();
}
__super::Dispose(disposing);
}
private:System::ComponentModel::Container * components;
private: Subclass * sClass1 ;
private: Subclass * sClass2 ;
private: Subclass * sClass3 ;
public: System::Windows::Forms::RichTextBox * RichTextBox1 ;
public: System::Windows::Forms::RichTextBox * RichTextBox2 ;
public: System::Windows::Forms::RichTextBox * RichTextBox3 ;
// ===================================================================
// for NativeWindow and PostMessageA
// ===================================================================
__value enum NWConst {
SBS_HORZ = 0,
SBS_VERT = 1,
SB_THUMBPOSITION = 4,
WM_COMMAND = 0x111,
WM_HSCROLL = 0x114,
WM_VSCROLL = 0x115,
WM_MOUSEWHEEL = 0x20A,
WM_USER = 0x400
};
// ===================================================================
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///
private:
void InitializeComponent()
{
this->RichTextBox1 = new System::Windows::Forms::RichTextBox ();
this->RichTextBox2 = new System::Windows::Forms::RichTextBox ();
this->RichTextBox3 = new System::Windows::Forms::RichTextBox ();
this->SuspendLayout();
//
// RichTextBox1
//
this->RichTextBox1->Location = System::Drawing::Point (24, 24);
this->RichTextBox1->Name = "RichTextBox1";
this->RichTextBox1->Size = System::Drawing::Size (128, 128);
this->RichTextBox1->TabIndex = 0;
this->RichTextBox1->Text = "RichTextBox1";
this->RichTextBox1->WordWrap = false;
//
// RichTextBox2
//
this->RichTextBox2->Location = System::Drawing::Point (160, 24);
this->RichTextBox2->Name = "RichTextBox2";
this->RichTextBox2->Size = System::Drawing::Size (128, 128);
this->RichTextBox2->TabIndex = 1;
this->RichTextBox2->Text = "RichTextBox2";
this->RichTextBox2->WordWrap = false;
//
// RichTextBox3
//
this->RichTextBox3->Location = System::Drawing::Point (296, 24);
this->RichTextBox3->Name = "RichTextBox3";
this->RichTextBox3->Size = System::Drawing::Size (128, 128);
this->RichTextBox3->TabIndex = 3;
this->RichTextBox3->Text = "RichTextBox3";
this->RichTextBox3->WordWrap = false;
//
// Form1
//
this->AutoScaleBaseSize = System::Drawing::Size (5, 13);
this->ClientSize = System::Drawing::Size (448, 174);
this->Controls->Add(this->RichTextBox3);
this->Controls->Add(this->RichTextBox2);
this->Controls->Add(this->RichTextBox1);
this->Name = "Form1";
this->Text = "Form1";
this->ResumeLayout(false);
this->Load += new System::EventHandler (this, Form1_Load);
this->RichTextBox1->VScroll += new System::EventHandler (this,RichTextBox1_VScroll);
this->RichTextBox2->VScroll += new System::EventHandler (this,RichTextBox2_VScroll);
this->RichTextBox3->VScroll += new System::EventHandler (this,RichTextBox3_VScroll);
this->RichTextBox1->HScroll += new System::EventHandler (this,RichTextBox1_HScroll);
this->RichTextBox2->HScroll += new System::EventHandler (this,RichTextBox2_HScroll);
this->RichTextBox3->HScroll += new System::EventHandler (this,RichTextBox3_HScroll);
}
void Form1_Load(System::Object * sender, System::EventArgs * e)
{
sClass1 = new Subclass(RichTextBox1->Handle);
sClass2 = new Subclass(RichTextBox2->Handle);
sClass3 = new Subclass(RichTextBox3->Handle);
this->sClass1->NativeWindowsEvent += new Subclass::WindowsEventHandler (this,sClass_WindowProcedure);
this->sClass2->NativeWindowsEvent += new Subclass::WindowsEventHandler (this,sClass_WindowProcedure);
this->sClass3->NativeWindowsEvent += new Subclass::WindowsEventHandler (this,sClass_WindowProcedure);
for (int i = 0; i <= 100; i++)
{
String * msg;
if (i % 4 == 0)
{
msg = String::Format(" this is a longer string to force HScroll {0} \n", __box(i));
RichTextBox1->AppendText(msg);
RichTextBox2->AppendText(msg);
RichTextBox3->AppendText(msg);
}
else
{
msg = String::Format(" this is a string {0} \n", __box(i));
RichTextBox1->AppendText(msg);
RichTextBox2->AppendText(msg);
RichTextBox3->AppendText(msg);
}
}
}
public: void sClass_WindowProcedure(Object * sender, System::Windows::Forms::Message * uMsg)
{
switch (uMsg->Msg)
{
case (WM_VSCROLL):
case (WM_HSCROLL):
if (uMsg->HWnd == RichTextBox1->Handle)
{
ArrayList * x = new ArrayList(2);
x->Add(RichTextBox2);
x->Add(RichTextBox3);
ThumbScrollHandler(RichTextBox1, x, uMsg);
}
else if (uMsg->HWnd == RichTextBox2->Handle)
{
ArrayList * x = new ArrayList(2);
x->Add(RichTextBox1);
x->Add(RichTextBox3);
ThumbScrollHandler(RichTextBox2, x, uMsg);
}
else if (uMsg->HWnd == RichTextBox3->Handle)
{
ArrayList * x = new ArrayList(2);
x->Add(RichTextBox1);
x->Add(RichTextBox2);
ThumbScrollHandler(RichTextBox3, x, uMsg);
}
break;
}
}
private: void ThumbScrollHandler(RichTextBox * sender, ArrayList* receivers, Message * uMsg)
{
sClass2->NativeWindowsEvent -= new Subclass::WindowsEventHandler(this, sClass_WindowProcedure);
for (int i=0; i<receivers->Count; i++)
{
RichTextBox * rtbox = dynamic_cast<richtextbox *="">(receivers->get_Item(i));
Message msg = Message::Create(rtbox->Handle, uMsg->Msg, uMsg->WParam, uMsg->LParam);
sClass2->SendWndProc(&msg);
}
sClass2->NativeWindowsEvent += new Subclass::WindowsEventHandler(this, sClass_WindowProcedure);
}
private: void RichTextBox1_VScroll(Object * sender, System::EventArgs * e)
{
ArrayList * richTextBoxes = new ArrayList(2);
richTextBoxes->Add( RichTextBox2);
richTextBoxes->Add( RichTextBox3);
VerticalScroll(RichTextBox1, richTextBoxes);
}
private: void RichTextBox2_VScroll(Object * sender,System::EventArgs * e)
{
ArrayList * richTextBoxes = new ArrayList(2);
richTextBoxes->Add( RichTextBox1);
richTextBoxes->Add( RichTextBox3);
VerticalScroll(RichTextBox2, richTextBoxes);
}
private: void RichTextBox3_VScroll(Object * sender,System::EventArgs * e)
{
ArrayList * richTextBoxes = new ArrayList(2);
richTextBoxes->Add( RichTextBox1);
richTextBoxes->Add( RichTextBox2);
VerticalScroll(RichTextBox3, richTextBoxes);
}
private: void RichTextBox1_HScroll(Object * sender,System::EventArgs * e)
{
ArrayList * richTextBoxes = new ArrayList(2);
richTextBoxes->Add( RichTextBox2);
richTextBoxes->Add( RichTextBox3);
HorizontalScroll(RichTextBox1, richTextBoxes);
}
private: void RichTextBox2_HScroll(Object * sender,System::EventArgs * e)
{
ArrayList * richTextBoxes = new ArrayList(2);
richTextBoxes->Add( RichTextBox1);
richTextBoxes->Add( RichTextBox3);
HorizontalScroll(RichTextBox2, richTextBoxes);
}
private: void RichTextBox3_HScroll(Object * sender,System::EventArgs * e)
{
ArrayList * richTextBoxes = new ArrayList(2);
richTextBoxes->Add( RichTextBox1);
richTextBoxes->Add( RichTextBox2);
HorizontalScroll(RichTextBox3, richTextBoxes);
}
private: void VerticalScroll(RichTextBox * sender, ArrayList * receivers)
{
int position = GetScrollPos(sender->Handle, SBS_VERT);
for (int i=0; i<receivers->Count; i++)
{
RichTextBox * rtbox = dynamic_cast<richtextbox *="">(receivers->get_Item(i));
PostMessageA(rtbox->Handle, WM_VSCROLL, SB_THUMBPOSITION + 0x10000 * position, 0);
}
}
private: void HorizontalScroll(RichTextBox * sender, ArrayList * receivers)
{
int position = GetScrollPos(sender->Handle, SBS_HORZ);
for (int i=0; i<receivers->Count; i++)
{
RichTextBox * rtbox = dynamic_cast<richtextbox *="">(receivers->get_Item(i));
PostMessageA(rtbox->Handle, WM_HSCROLL, SB_THUMBPOSITION + 0x10000 * position, 0);
}
}
};
}
//============================================
// Form1.cpp
//============================================
#include "stdafx.h"
#include "Form1.h"
#include <windows.h>
using namespace TestMultScroll;
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
System::Threading::Thread::CurrentThread->ApartmentState = System::Threading::ApartmentState::STA;
Application::Run(new Form1());
return 0;
}
|
|
|
|
|
yy678,
Thank you for the conversion, good work.
progload
|
|
|
|
|
I noticed Today that theRealCondor has posted a C# version here in the forum.
http://www.codeproject.com/script/comments/forums.asp?forumid=1649&select=912488&df=100&fr=2496.5#xx912488xx
Thanks again, for the work theRealCondor.
progload.
here it is again.
using System;
using System.IO;
using System.Data;
using System.Text;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace TestMultiScroll
{
public class Form1 : System.Windows.Forms.Form
{
private System.ComponentModel.IContainer components = null;
public System.Windows.Forms.RichTextBox RichTextBox1 = null;
public System.Windows.Forms.RichTextBox RichTextBox2 = null;
public System.Windows.Forms.RichTextBox RichTextBox3 = null;
private const int WM_HSCROLL = 0x114;
private const int WM_VSCROLL = 0x115;
private const int WM_MOUSEWHEEL = 0x20A;
private const int WM_COMMAND = 0x111;
private const int WM_USER = 0x400;
private const int SBS_HORZ = 0;
private const int SBS_VERT = 1;
private const int SB_THUMBPOSITION = 4;
private Subclass sClass1 = null;
private Subclass sClass2 = null;
private Subclass sClass3 = null;
public Form1()
{
InitializeComponent();
}
protected void Dispose(bool disposing)
{
if (disposing)
{
if ( !( (components == null)))
{
components.Dispose();
}
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
private void InitializeComponent()
{
this.RichTextBox1 = new System.Windows.Forms.RichTextBox ();
this.RichTextBox2 = new System.Windows.Forms.RichTextBox ();
this.RichTextBox3 = new System.Windows.Forms.RichTextBox ();
this.SuspendLayout();
this.RichTextBox1.Location = new System.Drawing.Point (24, 24);
this.RichTextBox1.Name = "RichTextBox1";
this.RichTextBox1.Size = new System.Drawing.Size (128, 128);
this.RichTextBox1.TabIndex = 0;
this.RichTextBox1.Text = "RichTextBox1";
this.RichTextBox1.WordWrap = false;
this.RichTextBox2.Location = new System.Drawing.Point (160, 24);
this.RichTextBox2.Name = "RichTextBox2";
this.RichTextBox2.Size = new System.Drawing.Size (128, 128);
this.RichTextBox2.TabIndex = 1;
this.RichTextBox2.Text = "RichTextBox2";
this.RichTextBox2.WordWrap = false;
this.RichTextBox3.Location = new System.Drawing.Point (296, 24);
this.RichTextBox3.Name = "RichTextBox3";
this.RichTextBox3.Size = new System.Drawing.Size (128, 128);
this.RichTextBox3.TabIndex = 3;
this.RichTextBox3.Text = "RichTextBox3";
this.RichTextBox3.WordWrap = false;
this.AutoScaleBaseSize = new System.Drawing.Size (5, 13);
this.ClientSize = new System.Drawing.Size (448, 174);
this.Controls.Add(this.RichTextBox3);
this.Controls.Add(this.RichTextBox2);
this.Controls.Add(this.RichTextBox1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
this.Load += new System.EventHandler (Form1_Load);
this.RichTextBox1.VScroll += new System.EventHandler (RichTextBox1_VScroll);
this.RichTextBox2.VScroll += new System.EventHandler (RichTextBox2_VScroll);
this.RichTextBox3.VScroll += new System.EventHandler (RichTextBox3_VScroll);
this.RichTextBox1.HScroll += new System.EventHandler (RichTextBox1_HScroll);
this.RichTextBox2.HScroll += new System.EventHandler (RichTextBox2_HScroll);
this.RichTextBox3.HScroll += new System.EventHandler (RichTextBox3_HScroll);
}
#endregion
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void Form1_Load(System.Object sender,System.EventArgs e)
{
sClass1 = new Subclass(RichTextBox1.Handle);
sClass2 = new Subclass(RichTextBox2.Handle);
sClass3 = new Subclass(RichTextBox3.Handle);
this.sClass1.NativeWindowsEvent += new Subclass.WindowsEventHandler (sClass_WindowProcedure);
this.sClass2.NativeWindowsEvent += new Subclass.WindowsEventHandler (sClass_WindowProcedure);
this.sClass3.NativeWindowsEvent += new Subclass.WindowsEventHandler (sClass_WindowProcedure);
for (int i = 0; i <= 100; i++)
{
if (i % 4 == 0)
{
RichTextBox1.AppendText(" this is a longer string to force HScroll " + i + System.Environment.NewLine);
RichTextBox2.AppendText(" this is a longer string to force HScroll " + i + System.Environment.NewLine);
RichTextBox3.AppendText(" this is a longer string to force HScroll " + i + System.Environment.NewLine);
}
else
{
RichTextBox1.AppendText(" this is a string " + i + System.Environment.NewLine);
RichTextBox2.AppendText(" this is a string " + i + System.Environment.NewLine);
RichTextBox3.AppendText(" this is a string " + i + System.Environment.NewLine);
}
}
}
public void sClass_WindowProcedure(ref Message uMsg)
{
switch (uMsg.Msg)
{
case (WM_VSCROLL):
if (uMsg.HWnd.Equals(RichTextBox1.Handle))
{
ThumbScrollHandler(RichTextBox1, new RichTextBox[] {RichTextBox2, RichTextBox3}, ref uMsg);
}
if (uMsg.HWnd.Equals(RichTextBox2.Handle))
{
ThumbScrollHandler(RichTextBox2, new RichTextBox[] {RichTextBox1, RichTextBox3}, ref uMsg);
}
if (uMsg.HWnd.Equals(RichTextBox3.Handle))
{
ThumbScrollHandler(RichTextBox3, new RichTextBox[] {RichTextBox1, RichTextBox2}, ref uMsg);
}
break;
case (WM_HSCROLL):
if (uMsg.HWnd.Equals(RichTextBox1.Handle))
{
ThumbScrollHandler(RichTextBox1, new RichTextBox[] {RichTextBox2, RichTextBox3}, ref uMsg);
}
if (uMsg.HWnd.Equals(RichTextBox2.Handle))
{
ThumbScrollHandler(RichTextBox2, new RichTextBox[] {RichTextBox1, RichTextBox3}, ref uMsg);
}
if (uMsg.HWnd.Equals(RichTextBox3.Handle))
{
ThumbScrollHandler(RichTextBox3, new RichTextBox[] {RichTextBox1, RichTextBox2}, ref uMsg);
}
break;
}
}
private void ThumbScrollHandler(RichTextBox sender, RichTextBox[] receivers, ref Message uMsg)
{
sClass2.NativeWindowsEvent -= new Subclass.WindowsEventHandler(ref sClass_WindowProcedure);
foreach (RichTextBox receiver in receivers)
{
Message msg = Message.Create(receiver.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam);
sClass2.SendWndProc(ref msg);
}
sClass2.NativeWindowsEvent += new Subclass.WindowsEventHandler(ref sClass_WindowProcedure);
}
private void RichTextBox1_VScroll(object sender,System.EventArgs e)
{
VerticalScroll(RichTextBox1, new RichTextBox[2] {RichTextBox2, RichTextBox3});
}
private void RichTextBox2_VScroll(object sender,System.EventArgs e)
{
VerticalScroll(RichTextBox2, new RichTextBox[2] {RichTextBox1, RichTextBox3});
}
private void RichTextBox3_VScroll(object sender,System.EventArgs e)
{
VerticalScroll(RichTextBox3, new RichTextBox[2] {RichTextBox1, RichTextBox2});
}
private void RichTextBox1_HScroll(object sender,System.EventArgs e)
{
HorizontalScroll(RichTextBox1, new RichTextBox[2] {RichTextBox2, RichTextBox3});
}
private void RichTextBox2_HScroll(object sender,System.EventArgs e)
{
HorizontalScroll(RichTextBox2, new RichTextBox[2] {RichTextBox1, RichTextBox3});
}
private void RichTextBox3_HScroll(object sender,System.EventArgs e)
{
HorizontalScroll(RichTextBox3, new RichTextBox[2] {RichTextBox1, RichTextBox2});
}
private void VerticalScroll(RichTextBox sender, RichTextBox[] receivers)
{
int position = GetScrollPos(sender.Handle, SBS_VERT);
foreach (RichTextBox receiver in receivers)
{
PostMessageA(receiver.Handle, WM_VSCROLL, SB_THUMBPOSITION + 0x10000 * position, 0);
}
}
private void HorizontalScroll(RichTextBox sender, RichTextBox[] receivers)
{
int position = GetScrollPos(sender.Handle, SBS_HORZ);
foreach(RichTextBox receiver in receivers)
{
PostMessageA(receiver.Handle, WM_HSCROLL, SB_THUMBPOSITION + 0x10000 * position, 0);
}
}
[DllImport("user32.dll")]
private static extern int GetScrollPos(IntPtr hWnd, int nBar);
[DllImport("user32.dll")]
private static extern bool PostMessageA(IntPtr hwnd, int wMsg, int wParam, int lParam);
}
public class Subclass : System.Windows.Forms.NativeWindow
{
public event WindowsEventHandler NativeWindowsEvent;
public delegate void WindowsEventHandler(ref Message uMsg);
public Subclass(IntPtr pWindowHandle):base()
{
base.AssignHandle(pWindowHandle);
}
protected override void WndProc(ref System.Windows.Forms.Message uMsg)
{
base.WndProc(ref uMsg);
if (NativeWindowsEvent != null)
NativeWindowsEvent(ref uMsg);
}
public void SendWndProc(ref System.Windows.Forms.Message uMsg)
{
base.WndProc(ref uMsg);
}
}
}
|
|
|
|
|
I have an addition to the code for making the "thumbs" on the vertical scrollbars sync. I should have a update re-written for the article by the end of the month, but if you need the code, drop me an email.
|
|
|
|
|
Hi Progload,
Just found one minor bug, i.e. when I scroll using scroll bar's thumb, the thumb of the active control gets continuously updated, where as other thumb of other controls do not get updated continuously.
Regards,
Jay.
|
|
|
|
|
Thanks for the great reponse Jay,
I'll work on getting a C# version of this somtime soon, It will require a re-write as C# uses the NativeWindow class a slightly different way.
Also, the thumb message can be found in the EM_SCROLL messages, I'll track them down and try to add the code for that.
This was designed for use where you Wouldn't see the second and third vertical scroll bars in the UI as shown in the second picture, but I do see your point, the thumbs by themself's do not sync until you let off the mouse button.
Thanks,
ProgLoad
|
|
|
|
|