Avatar billede nwn Nybegynder
16. februar 2008 - 21:28 Der er 20 kommentarer og
1 løsning

Når RichTextBox1 scrolles, så scroller RichTextBox2 med itakt

Hvis jeg nu f.eks vælger at scrolle nedad med RichTextBox1, hvordan kan jeg så lave så RichTextBox2 også scroller med ned? Altså i takt.
Avatar billede skov_p Praktikant
16. februar 2008 - 23:23 #1
Her scroller de i sync

using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace PaintIt {
    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();
        }

        [DllImport( "user32.dll" )]
        [return: MarshalAs( UnmanagedType.Bool )]
        static extern bool GetScrollInfo(IntPtr hwnd, int fnBar, ref SCROLLINFO lpsi);

        [DllImport( "user32.dll" )]
        static extern int SetScrollInfo(IntPtr hwnd, int fnBar, [In] ref SCROLLINFO lpsi, bool fRedraw);

        [DllImport( "User32.dll", CharSet = CharSet.Auto, EntryPoint = "SendMessage" )]
        static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        struct SCROLLINFO {
            public uint cbSize;
            public uint fMask;
            public int nMin;
            public int nMax;
            public uint nPage;
            public int nPos;
            public int nTrackPos;
        }

        enum ScrollBarDirection {
            SB_HORZ = 0,
            SB_VERT = 1,
            SB_CTL = 2,
            SB_BOTH = 3
        }

        enum ScrollInfoMask {
            SIF_RANGE = 0x1,
            SIF_PAGE = 0x2,
            SIF_POS = 0x4,
            SIF_DISABLENOSCROLL = 0x8,
            SIF_TRACKPOS = 0x10,
            SIF_ALL = SIF_RANGE + SIF_PAGE + SIF_POS + SIF_TRACKPOS
        }

        const int WM_VSCROLL = 277;
        const int SB_LINEUP = 0;
        const int SB_LINEDOWN = 1;
        const int SB_THUMBPOSITION = 4;
        const int SB_THUMBTRACK = 5;
        const int SB_TOP = 6;
        const int SB_BOTTOM = 7;
        const int SB_ENDSCROLL = 8;

        void scrollSync(RichTextBox rtbm, RichTextBox rtbs) {
            int masterPos = GetPos( rtbm.Handle );
            scroll( rtbs.Handle, masterPos );
        }

        int GetPos(IntPtr handle) {
            IntPtr ptrLparam = new IntPtr( 0 );
            IntPtr ptrWparam;

            // Get current scroller posion
            SCROLLINFO si = new SCROLLINFO();
            si.cbSize = (uint)Marshal.SizeOf( si );
            si.fMask = (uint)ScrollInfoMask.SIF_ALL;
            GetScrollInfo( handle, (int)ScrollBarDirection.SB_VERT, ref si );
            return si.nPos;
        }

        // Scrolls a given textbox. handle: an handle to our textbox. pixels: number of pixels to scroll.
        void scroll(IntPtr handle, int pos) {
            IntPtr ptrLparam = new IntPtr( 0 );
            IntPtr ptrWparam;

            // Get current scroller posion
            SCROLLINFO si = new SCROLLINFO();
            si.cbSize = (uint)Marshal.SizeOf( si );
            si.fMask = (uint)ScrollInfoMask.SIF_ALL;
            GetScrollInfo( handle, (int)ScrollBarDirection.SB_VERT, ref si );

            // Get current scroller posion
            SCROLLINFO si2 = new SCROLLINFO();
            si2.cbSize = (uint)Marshal.SizeOf( si );
            si2.fMask = (uint)ScrollInfoMask.SIF_ALL;
            GetScrollInfo( handle, (int)ScrollBarDirection.SB_VERT, ref si2 );


            // Increase posion by pixles
            if( si.nPos < (si.nMax - si.nPage) )
                si.nPos = pos;
            else {
                ptrWparam = new IntPtr( SB_ENDSCROLL );
                t.Enabled = false;
                SendMessage( handle, WM_VSCROLL, ptrWparam, ptrLparam );
            }

            // Reposition scroller
            SetScrollInfo( handle, (int)ScrollBarDirection.SB_VERT, ref si, true );

            // Send a WM_VSCROLL scroll message using SB_THUMBTRACK as wParam
            // SB_THUMBTRACK: low-order word of wParam, si.nPos high-order word of wParam
            ptrWparam = new IntPtr( SB_THUMBTRACK + 0x10000 * si.nPos );
            SendMessage( handle, WM_VSCROLL, ptrWparam, ptrLparam );
        }

        private void scrolling1(object sender, EventArgs e) {
            scrollSync( richTextBox1, richTextBox2 );
        }

        private void scrolling2(object sender, EventArgs e) {
            scrollSync( richTextBox2, richTextBox1 );
        }
    }
}
Avatar billede skov_p Praktikant
16. februar 2008 - 23:24 #2
Du skal lægge Vscroll event på din/dine richtextbox. scrolling1 og 2
Avatar billede skov_p Praktikant
16. februar 2008 - 23:26 #3
slet t.Enabled = false;
Avatar billede nwn Nybegynder
16. februar 2008 - 23:49 #4
Okay, det prøver jeg (:
Avatar billede nwn Nybegynder
16. februar 2008 - 23:59 #5
Den skriver build succeded, og åbner programmet. Så begynder jeg at lave en masse linie skift i den ene RichTextBox med enter, og lige så snart scrollbaren bliver enabled, så hopper den ud af det.

Markerer dette med grønt: SendMessage(handle, WM_VSCROLL, ptrWparam, ptrLparam);

Og giver følgende fejlmeddelse: An unhandled exception of type 'System.StackOverflowException' occurred in mscorlib.dll

Det samme gælder, hvis jeg tildeler begge en value med mange linieskift. Så lige så snart programmet åbner, og jeg prøver at benytte scrollbaren, så kommer fejl meddelsen...
Avatar billede skov_p Praktikant
17. februar 2008 - 09:29 #6
Det ser jeg ikke her

Kalder begge dine richtext det samme event.

StackOverflowException kommer typisk fordi noget kode kalder sig selv som nedenfor

void M1(){
  M2()
}

void M2(){
  M1()
}
Avatar billede nwn Nybegynder
17. februar 2008 - 13:22 #7
Jeg har bare indsat det som du sagde, og så tilføjet Vscroll til begge. Men det er jo egentlig kun meningen, at man skal kunne scrolle i den ene richTextBox. Den anden har jeg fjernet scrollbars fra og sat enabled til false.
Avatar billede skov_p Praktikant
17. februar 2008 - 15:02 #8
Skal jeg tolke din sidste besked som at det virker nu
Avatar billede nwn Nybegynder
18. februar 2008 - 18:15 #9
Har lige selv læst 13:22:51 og der lyder det som om det virker, men nej, har ikke fået det til at virke.
Avatar billede skov_p Praktikant
19. februar 2008 - 07:44 #10
Lige for at være enige om funktionaliteten så prøve at gemme og køre dette program

http://www.skovkristensen.dk/paintit.exe

Den venstre richedit får den højre til at køre med. Det er lavet i VS2008 .NET 2.0

Du skal ikke tage dig at navnet, projektet var oprindeligt brugt til noget andet.
Avatar billede longkhi Nybegynder
21. februar 2008 - 13:56 #11
Hej skov_p.

Jeg ville høre om det kildekode du har hæftet ovenover, er det du har brugt til dit paintit.exe program.

Fordi jeg ahr også prøvet at tilpasse det til mig. Men det gider ikke at scrolle :( Men jeg bruger så heller ik RTB.

Mvh. Kim
Avatar billede nwn Nybegynder
22. februar 2008 - 20:13 #12
skov_p

Jeg kan ikke få det paintit til at virke. Når jeg har indtastet nok tekst i den begge så man kan scrolle, og jeg så scroller, så kommer der alt muligt application error osv.
Avatar billede skov_p Praktikant
22. februar 2008 - 22:37 #13
Her er kildekoden til det program i linket ovenover

using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace PaintIt {
    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();
        }

        [DllImport( "user32.dll" )]
        [return: MarshalAs( UnmanagedType.Bool )]
        static extern bool GetScrollInfo(IntPtr hwnd, int fnBar, ref SCROLLINFO lpsi);

        [DllImport( "user32.dll" )]
        static extern int SetScrollInfo(IntPtr hwnd, int fnBar, [In] ref SCROLLINFO lpsi, bool fRedraw);

        [DllImport( "User32.dll", CharSet = CharSet.Auto, EntryPoint = "SendMessage" )]
        static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        struct SCROLLINFO {
            public uint cbSize;
            public uint fMask;
            public int nMin;
            public int nMax;
            public uint nPage;
            public int nPos;
            public int nTrackPos;
        }

        enum ScrollBarDirection {
            SB_HORZ = 0,
            SB_VERT = 1,
            SB_CTL = 2,
            SB_BOTH = 3
        }

        enum ScrollInfoMask {
            SIF_RANGE = 0x1,
            SIF_PAGE = 0x2,
            SIF_POS = 0x4,
            SIF_DISABLENOSCROLL = 0x8,
            SIF_TRACKPOS = 0x10,
            SIF_ALL = SIF_RANGE + SIF_PAGE + SIF_POS + SIF_TRACKPOS
        }

        const int WM_VSCROLL = 277;
        const int SB_LINEUP = 0;
        const int SB_LINEDOWN = 1;
        const int SB_THUMBPOSITION = 4;
        const int SB_THUMBTRACK = 5;
        const int SB_TOP = 6;
        const int SB_BOTTOM = 7;
        const int SB_ENDSCROLL = 8;

        void scrollSync(RichTextBox rtbm, RichTextBox rtbs) {
            int masterPos = GetPos( rtbm.Handle );
            scroll( rtbs.Handle, masterPos );
        }

        int GetPos(IntPtr handle) {
            IntPtr ptrLparam = new IntPtr( 0 );
            IntPtr ptrWparam;

            // Get current scroller posion
            SCROLLINFO si = new SCROLLINFO();
            si.cbSize = (uint)Marshal.SizeOf( si );
            si.fMask = (uint)ScrollInfoMask.SIF_ALL;
            GetScrollInfo( handle, (int)ScrollBarDirection.SB_VERT, ref si );
            return si.nPos;
        }

        // Scrolls a given textbox. handle: an handle to our textbox. pixels: number of pixels to scroll.
        void scroll(IntPtr handle, int pos) {
            IntPtr ptrLparam = new IntPtr( 0 );
            IntPtr ptrWparam;

            // Get current scroller posion
            SCROLLINFO si = new SCROLLINFO();
            si.cbSize = (uint)Marshal.SizeOf( si );
            si.fMask = (uint)ScrollInfoMask.SIF_ALL;
            GetScrollInfo( handle, (int)ScrollBarDirection.SB_VERT, ref si );
           
            si.nPos = pos;
            // Increase posion by pixles
            //if( si.nPos < (si.nMax - si.nPage) )
            //  //si.nPos = pos;
            //  si.nPos = pos;
            //else {
            //  ptrWparam = new IntPtr( SB_ENDSCROLL );
               
            //  SendMessage( handle, WM_VSCROLL, ptrWparam, ptrLparam );
            //}

            // Reposition scroller
            SetScrollInfo( handle, (int)ScrollBarDirection.SB_VERT, ref si, true );

            // Send a WM_VSCROLL scroll message using SB_THUMBTRACK as wParam
            // SB_THUMBTRACK: low-order word of wParam, si.nPos high-order word of wParam
            ptrWparam = new IntPtr( SB_THUMBTRACK + 0x10000 * si.nPos );
            SendMessage( handle, WM_VSCROLL, ptrWparam, ptrLparam );
        }

        private void scrolling1(object sender, EventArgs e) {
            scrollSync( richTextBox1, richTextBox2 );
        }

        private void scrolling2(object sender, EventArgs e) {
            //scrollSync( richTextBox2, richTextBox1 );
        }
    }
}
Avatar billede skov_p Praktikant
22. februar 2008 - 22:39 #14
Avatar billede nwn Nybegynder
23. februar 2008 - 13:08 #15
Så fik jeg det sgu til at virke. Tusind tak skov_p (:

Jeg har lige et spørgsmål.

Det virker når man bruger musens scroll ting, og hvis man trykker på op eller ned pilene på scrollbaren, men hvis man klikker på selve scrollbaren og trækker den, så "opdaterer" den først når man slipper venstre museklik igen...

Er det ikke muligt at fikse ?
Avatar billede skov_p Praktikant
25. februar 2008 - 11:03 #16
Din GetPos skal returnere
si.nTrackPos
i stedet for
si.nPos
så virker det.
Avatar billede longkhi Nybegynder
25. februar 2008 - 12:55 #17
Hej Skov_p.

Virker din eksempel kun til RTB?
Avatar billede skov_p Praktikant
25. februar 2008 - 15:08 #18
Du kan bruge textbox hvis du kan nøjes med at scrolle via page og pil tasterne. Der er ingen scroll event på en textbox
Avatar billede longkhi Nybegynder
25. februar 2008 - 15:44 #19
Nåh ok. Det er fordi jeg bruger et komponent "Gravitybox". Den har også et scroll, men ikke nogen event som hedder Vscroll. Den har dog VerticalScroll, men det mærkelige er, at den ikke kan læse WM_SCROLL. Den opfanger den slet ikke. Jeg har så prøvet med WM_MOUSEWHEEL, men den fungerer helt forkert.

Kan du hjælpe mig ud af denne her? :)
Avatar billede longkhi Nybegynder
25. februar 2008 - 15:47 #20
Også selve si.nPos værdien er 0 hele vejen igennem. Ved denne if sætning burde den gå ind i if, men den tager else i stedet for, pga. de andre si. værdier er lig 0.

if (si.nPos < (si.nMax - si.nPage))
                si.nPos = pos;
            else
            {
                ptrWparam = new IntPtr(SB_ENDSCROLL);
                SendMessage(handle, WM_MOUSEWHEEL, ptrWparam, ptrLparam);
            }
Avatar billede nwn Nybegynder
26. februar 2008 - 22:00 #21
Tusind tak for hjælpen skov_ p !

Du har virkelig fortjent point (:
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester