Avatar billede morano Nybegynder
02. september 2006 - 00:46 Der er 25 kommentarer

linie række

Hej,
jeg har en RichTextBox i mit program og jeg vil godt have sådan en liste til venstre for den. Sådan de næsten hænger sammen bare med en  streg imellem eller noget, hvor der så står hvilken linie nummer det er.
Hvad er den bedste måde at gøre det på? det har nemlig endnu ikke lykkedes mig at komme med et godt resultat. Det har ikke lykkedes mig at komme med noget, overhovedet!
Avatar billede bulgroz Nybegynder
02. september 2006 - 07:26 #1
Og det skal være en RichTextBox? Det er jo et væld af andre kontroller som er bedre egnet til "linieopdeling".
Men ellers kan du vel bare formatere teksten, med linieskift mellem hver linie osv. Tallene må du skrive selv.
Avatar billede bulgroz Nybegynder
02. september 2006 - 07:36 #2
Her et lille eksempel med flere linier og numre...

StringBuilder stringBuilder = new StringBuilder();

for (int i = 1; i <= 10; i++)
{
    stringBuilder.AppendLine(String.Format("Linie: {0} Dette er en test.", i));
}

this.richTextBox.Text = stringBuilder.ToString();
Avatar billede bulgroz Nybegynder
02. september 2006 - 07:38 #3
Men afhængigt af hvad det skal bruges til, ville jeg nok overveje en alternativ kontrol så som DataGridView, ListView...
Avatar billede bulgroz Nybegynder
02. september 2006 - 07:47 #4
Hvis det er sådan at du vil have en RichTextBox til at gøre det samme når du editerer teksten, er du nødsaget til at lave din egen kontrol som selv sørger for at tegne "nummerrækken". (Eller anvende en alternativ kontrol...)
Avatar billede bulgroz Nybegynder
02. september 2006 - 08:08 #5
Her er et eksempel på hvorledes man kan gøre.
http://www.codeproject.com/cs/miscctrl/numberedtextbox.asp
Avatar billede morano Nybegynder
02. september 2006 - 09:07 #6
nej nej jeg tror i misforstod. Den liste med numre skal viser linienumrene 'fra en richtextbox'
Avatar billede bitsch Nybegynder
02. september 2006 - 10:26 #7
? det er jo også hvad den gør.
RichTextBox kan ikke vise linienumre, ved mindre at du presser den til det.
Enten som i eksemplet ved at lave en kontrol med en kombination af RichTextBox og label til at vise linienumre. Eller også den mere komplicerede hvor du går ind og laver en masse measures på RichTextBox hvorefter du så selv tegner numrene ved at override OnPaint.
Avatar billede bulgroz Nybegynder
02. september 2006 - 10:46 #8
Du kan prøve min version af samme. Her ser linienumrene ud til at være en del af RichTextBoxen


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

namespace CommonControls
{
    public partial class NumberedRichTextBox : UserControl
    {
        #region Private Fields

        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// The RichTextBox
        /// </summary>
        private System.Windows.Forms.RichTextBox richTextBox;

        /// <summary>
        /// Label used to display Line Numbers.
        /// </summary>
        private System.Windows.Forms.Label labelNumbers;

        /// <summary>
        /// Container used in order to position the label and text box.
        /// </summary>
        private System.Windows.Forms.SplitContainer splitContainer;

        #endregion // Private Fields

        #region Public Constructors

        public NumberedRichTextBox()
        {
            this.InitializeComponent();

            this.InitializeLineNumbers();
        }

        #endregion // Public Constructors

        #region Protected Methods

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }

            base.Dispose(disposing);
        }

        #endregion // Protected Methods

        #region Private Methods

        /// <summary>
        /// Caled in order to initialize the number label.
        /// </summary>
        private void InitializeLineNumbers()
        {
            this.labelNumbers.Font = new Font(this.richTextBox.Font.FontFamily, this.richTextBox.Font.Size + 1.019f);

            this.BackColor = this.richTextBox.BackColor;
        }

        /// <summary>
        /// Updates line numbers for the lines in the text box.
        /// </summary>
        private void UpdateLineNumbers()
        {
            int firstLine = this.GetFirstLineNumber();
            int lastLineNumber = this.GetLastLineNumber();

            this.labelNumbers.Text = this.GetLineNumbersString(firstLine, lastLineNumber);
        }

        /// <summary>
        /// Gets the line number for the first visible line.
        /// </summary>
        /// <returns>Number of the first visible line.</returns>
        private int GetFirstLineNumber()
        {
            Point pos = new Point(0, 0);
           
            int firstIndex = this.richTextBox.GetCharIndexFromPosition(pos);
           
            return this.richTextBox.GetLineFromCharIndex(firstIndex) + 1;
        }

        /// <summary>
        /// Gets the line number for the last visible line.
        /// </summary>
        /// <returns>Number of the last visible line.</returns>
        private int GetLastLineNumber()
        {
            Point pos = new Point(0, 0);

            pos.X = this.ClientRectangle.Width;
            pos.Y = this.ClientRectangle.Height;
           
            int lastIndex = this.richTextBox.GetCharIndexFromPosition(pos);

            return this.richTextBox.GetLineFromCharIndex(lastIndex) + 1;
        }

        /// <summary>
        /// Returns a string with numbers on separate lines.
        /// </summary>
        /// <param name="firstLine">First number in the string.</param>
        /// <param name="lastLine">Last number in the string.</param>
        /// <returns>string of numbers.</returns>
        private string GetLineNumbersString(int firstNumber, int lastNumber)
        {
            StringBuilder stringBuilder = new StringBuilder();

            for (int i = firstNumber; i <= lastNumber + 1; i++)
            {
                stringBuilder.AppendLine(i.ToString());
            }

            return stringBuilder.ToString();
        }

        /// <summary>
        /// Updates numbers and position for the lines in the text box.
        /// </summary>
        private void UpdateLineNumbersAndPosition()
        {
            this.UpdateNumberPosition();

            this.UpdateLineNumbers();
        }

        /// <summary>
        /// Called in order to update the position of the line numbers.
        /// </summary>
        private void UpdateNumberPosition()
        {
            int y = this.richTextBox.GetPositionFromCharIndex(0).Y % (this.richTextBox.Font.Height + 1);

            this.labelNumbers.Location = new Point(0, y);
        }

        /// <summary>
        /// Called in order to update line numbers when text changes.
        /// </summary>
        /// <param name="sender">The text box currently beeing edited.</param>
        /// <param name="eventArgs">Ignored!</param>
        private void RichTextBoxTextChanged(object sender, EventArgs eventArgs)
        {
            this.UpdateLineNumbers();
        }

        /// <summary>
        /// Called in order to make line numbers follow the lines when scroolling.
        /// </summary>
        /// <param name="sender">The text box currently beeing scrolled in the vertical direction.</param>
        /// <param name="eventArgs">Ignored!</param>
        private void RichTextBoxVScroll(object sender, EventArgs eventArgs)
        {
            this.UpdateLineNumbersAndPosition();
        }

        /// <summary>
        /// Called in order to make line numbers follow the lines when resized.
        /// </summary>
        /// <param name="sender">The text box currently beeing resized.</param>
        /// <param name="eventArgs">Ignored!</param>
        private void RichTextBoxResize(object sender, EventArgs eventArgs)
        {
            this.UpdateLineNumbersAndPosition();
        }

        /// <summary>
        /// Called in order to make line numbers follow the lines when the font is changed.
        /// </summary>
        /// <param name="sender">The text box where the font is changed.</param>
        /// <param name="eventArgs">Ignored!</param>
        private void RichTextBoxFontChanged(object sender, EventArgs eventArgs)
        {
            this.UpdateLineNumbersAndPosition();
        }

        #region Component Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.labelNumbers = new System.Windows.Forms.Label();
            this.splitContainer = new System.Windows.Forms.SplitContainer();
            this.richTextBox = new System.Windows.Forms.RichTextBox();
            this.splitContainer.Panel1.SuspendLayout();
            this.splitContainer.Panel2.SuspendLayout();
            this.splitContainer.SuspendLayout();
            this.SuspendLayout();
            //
            // labelNumbers
            //
            this.labelNumbers.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
            this.labelNumbers.ForeColor = System.Drawing.SystemColors.ControlDark;
            this.labelNumbers.Location = new System.Drawing.Point(3, 0);
            this.labelNumbers.Name = "labelNumbers";
            this.labelNumbers.Size = new System.Drawing.Size(37, 267);
            this.labelNumbers.TabIndex = 1;
            this.labelNumbers.TextAlign = System.Drawing.ContentAlignment.TopRight;
            //
            // splitContainer
            //
            this.splitContainer.Dock = System.Windows.Forms.DockStyle.Fill;
            this.splitContainer.FixedPanel = System.Windows.Forms.FixedPanel.Panel1;
            this.splitContainer.IsSplitterFixed = true;
            this.splitContainer.Location = new System.Drawing.Point(0, 0);
            this.splitContainer.Name = "splitContainer";
            //
            // splitContainer.Panel1
            //
            this.splitContainer.Panel1.Controls.Add(this.labelNumbers);
            //
            // splitContainer.Panel2
            //
            this.splitContainer.Panel2.Controls.Add(this.richTextBox);
            this.splitContainer.Size = new System.Drawing.Size(403, 267);
            this.splitContainer.SplitterDistance = 41;
            this.splitContainer.SplitterWidth = 1;
            this.splitContainer.TabIndex = 2;
            this.splitContainer.Text = "splitContainer1";
            //
            // richTextBox
            //
            this.richTextBox.BorderStyle = System.Windows.Forms.BorderStyle.None;
            this.richTextBox.Dock = System.Windows.Forms.DockStyle.Fill;
            this.richTextBox.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
            this.richTextBox.Location = new System.Drawing.Point(0, 0);
            this.richTextBox.Name = "richTextBox";
            this.richTextBox.Size = new System.Drawing.Size(361, 267);
            this.richTextBox.TabIndex = 0;
            this.richTextBox.Text = "";
            this.richTextBox.WordWrap = false;
            this.richTextBox.Resize += new System.EventHandler(this.RichTextBoxResize);
            this.richTextBox.FontChanged += new System.EventHandler(this.RichTextBoxFontChanged);
            this.richTextBox.VScroll += new System.EventHandler(this.RichTextBoxVScroll);
            this.richTextBox.TextChanged += new System.EventHandler(this.RichTextBoxTextChanged);
            //
            // NumberedRichTextBox
            //
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.Controls.Add(this.splitContainer);
            this.Name = "NumberedRichTextBox";
            this.Size = new System.Drawing.Size(403, 267);
            this.splitContainer.Panel1.ResumeLayout(false);
            this.splitContainer.Panel2.ResumeLayout(false);
            this.splitContainer.ResumeLayout(false);
            this.ResumeLayout(false);

        }

        #endregion // Component Designer generated code

        #endregion // Private Methods
    }
}
Avatar billede morano Nybegynder
02. september 2006 - 11:56 #9
Bulgroz...
den kode fik mig til at tænke på en lidt anderledes måde.
Er der en måde man fx. kan finde ud af hvor mange a'er der er eller for eksempel linier::)?
Avatar billede bulgroz Nybegynder
02. september 2006 - 15:10 #10
Naturligvis, men det vil give noget performance tab ved store tekster, da du er nødt til at optælle antallet for samtlige linier, hver gang TextChanged eventet fyres.
Avatar billede bulgroz Nybegynder
02. september 2006 - 15:12 #11
RichTextBox'en fortæller kun at teksten er ændret, men ikke hvor den er ændret!
Avatar billede morano Nybegynder
02. september 2006 - 15:58 #12
Hvis du gider, kunne du så ikke lige komme med noget der talte hvor mange linie der er - det ville være perfekt... tror jeg da.
Så du sød:)
Avatar billede morano Nybegynder
02. september 2006 - 18:10 #13
det var jo ikke svært...
multiline sat til true og så bare richTextBox1.Lines.Length;
Avatar billede morano Nybegynder
02. september 2006 - 18:11 #14
nu har jeg så bare det program at når der er at vidst antal linie, så forsvinder talene bare ud, eftersom at der ikke er noget scroll'ting' overhovedet i det panel der indeholder label med talene.
Hvordan får jeg det panel til at scrolle præcist som mit tekstfelt gør?
Avatar billede bulgroz Nybegynder
02. september 2006 - 18:45 #15
? Det problem har jeg ikke check din ScrollBars property. Den bør stå til "Both"
Avatar billede morano Nybegynder
02. september 2006 - 18:57 #16
nej, men jeg har heller ikke brugt din kode!
jeg har et panel med et label på.
Hvergang der kommer en ny linie eller bliver fjernet en bliver der henholdvist trykket fra eller sat 15 extra på en højden på label't og der bliver skriver det nye tal ned. Men problemet er bare at når label't er støre end panelet forsvinder det ud. Så på en eller måde skal de scrolle med richtextbox'en
Avatar billede bulgroz Nybegynder
02. september 2006 - 19:13 #17
Jamen så er det en god idé at kigge lidt nærmere på min kode, der netop tager højde for vertikal scrolling.
Avatar billede morano Nybegynder
02. september 2006 - 20:26 #18
yeah men først og fremmet er det horisontal scrolling der er problemet og så fik jeg lavet det, ved at få idé ud fra din kode, på en måde som jeg synes er yderst tilfreds stillende. Bortset fra at den har det med scrolling problem, som jeg ved godt kan løses,  da jeg for nogen dage siden har læst om problemet, som senere hen blev løst, i et c# fora, men jeg kan desværre ikke huske noget derfra:D
Avatar billede morano Nybegynder
02. september 2006 - 21:32 #19
rettelse*vertikal - my bad
Avatar billede bulgroz Nybegynder
03. september 2006 - 09:52 #20
Mit eksempel scroller som set i vertical retning uden problemer, men linienumrene scroller ikke med ved horizontal scrollning hvilket er helt bevidst, da man normalt kun vil scrolle text delen, og stadig vil have mulighed for at se linienumre...
Hvis du vil ændre på dette er du derfor nødsaget til at kode noget mere på den split container som grupperer labelen og RichTextBoxen.

Men husk at denne "Label Løsning" i virkeligheden er meget begrænset (simpel) og der er en masse ting som ikke supportes. Prøv f.eks. at have forskellig font størrelse i RichTextBoxen, så vil kæden falde af ;-) Men til almindeligt hus behov er det naturligvis ok.

Med hensyn til at lave counter pr. linie, så er her et eksempel. Du skal huske at øge bredden på din label (hvilket i mit eksempel gøres ved at sætte SplitterDistance) på split kontrollen.

Jeg bruger i eksemplet et simpelt pattern som matcher "a"! Du kan naturligvis anføre et hvilket somhelst pattern.

Nb. Antallet af linier kan du få fra this.richTextBox.Lines.Length.

Og så lidt kode som kan erstatte tidligere...

        /// <summary>
        /// Returns a string with numbers on separate lines.
        /// </summary>
        /// <param name="firstLine">First number in the string.</param>
        /// <param name="lastLine">Last number in the string.</param>
        /// <returns>string of numbers.</returns>
        /// <remarks>Remember to adjust SplitterDistance so the lines doesen't wrap!</remarks>
        private string GetLineNumbersString(int firstNumber, int lastNumber)
        {
            StringBuilder stringBuilder = new StringBuilder();

            for (int i = firstNumber; i <= lastNumber + 1; i++)
            {
                if (i <= this.richTextBox.Lines.Length)
                {
                    string line = this.richTextBox.Lines[i - 1];

                    MatchCollection matchCollection = Regex.Matches(line, "[a]"); // TODO: Expose pattern through property!
                    int counter = matchCollection.Count;

                    stringBuilder.AppendLine(string.Format(CultureInfo.InvariantCulture, "{0} c:{1}", i, counter));
                }
                else
                {
                    stringBuilder.AppendLine(i.ToString());
                }
            }

            return stringBuilder.ToString();
        }
Avatar billede morano Nybegynder
03. september 2006 - 10:27 #21
jeg vil lige spørger...
Hvorfor gøre det sværere end det er?
jeg er MEGET ny indenfor C#, men fra mit synspunkt, er det der at lave unødvendig fancy kode.

Det jeg har gjort for at få skrevet talene er bare:

                String lineNumbers = "";

        int nSizeY = richTextBox1.Lines.Length*13;

        lineNumberLabel.Size = new Size(33,nSizeY);

        for(int i = 1;i <= richTextBox1.Lines.Length;i++) {
            lineNumbers = lineNumbers + i + "\n";
        }

        lineNumberLabel.Text = lineNumbers;

Så bliver talene helt fint skrevet.

Mit interface, for tekstfelt og linie numre, er bare et richtextbox der har dockstyle sat til fill, og et panel der har dockstyle sat til left og så har panelet bare fået klistret et label på.
Avatar billede bulgroz Nybegynder
03. september 2006 - 12:01 #22
Ja men der er da mange løsningsmuligheder. Min løsning er der dog til dels tænkt lidt på performance, da det kun er synlige linier som betragtes for beregninger etc.

Har du imidlertid kun få linier kan du jo gøre hvad du har lyst til.

Men stadigvæk er hverken din eller min approach pæn, da den f.eks. ikke tager højde for den fysiske højde på hver linie. Når man begynder at gøre det er det nødvendigt at gå væk fra "Labelløsningen" og udføre den egentlige tegning af linienumrene selv.
Avatar billede bulgroz Nybegynder
03. september 2006 - 18:08 #23
Er mine svar tilstrækkelige så spørgsmålet kan lukkes?
Avatar billede morano Nybegynder
03. september 2006 - 20:06 #24
jeg mangler stadigvæk at få svar på om man kan få fx et panel til at skrive præcist med fx en richtextbox. Altså så scrollbaren er for begge komponenter
Avatar billede bulgroz Nybegynder
03. september 2006 - 21:01 #25
Hvis det du ønsker er at linienumrene figurerer som en del af teksten, og derved scroller med en fælles scrollbar for hele kontrollen, så kan du kun opnå dette ved at kode dig ud af det. Men det kan naturligvis lade sig gøre.
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