Link to home
Start Free TrialLog in
Avatar of Sukhwinder Singh
Sukhwinder SinghFlag for India

asked on

Which Component is used for text editors edit window?

Hello,
     
     I have 1 question related to VB 6.0
     
     Which Component is mostly used for creating a Text editor's edit window(where files are displayed and edited). For example to enable syntax highlighting. Textbox cannot be used because of its size limit and also it doesn't allow highlighting particular words. Should I use Rich Text Box? Do most editors like Editplus, Ultraedit etc. use richtext box and save file as plain text?  Or they use some commercial component for this purpose (which I cannot use). But I think rtf cannot be used to show line numbers on left side and to disable selection of these line nos when selecting text; as these editors allow.
Avatar of Anthony Perkins
Anthony Perkins
Flag of United States of America image

Please maintain your open questions.  For the record:

Questions Asked 20
Last 10 Grades Given B A B B C B B B B A  
Question Grading Record 13 Answers Graded / 13 Answers Received

Also, you may want to re-read the EE Guidelines (https://www.experts-exchange.com/jsp/cmtyQuestAnswer.jsp) regarding grading standards used here.

Thanks,
Anthony
Why not create your own word processor control? It is easier that it sounds.

Set your form's keypreview  to true and you can pickup all key down/press/up events on your form. The hard bit is handling the caret and knowing where the operator is typing.

Here is some code to show that VB is fast enough for the job.

1) Create new project:
2) Set the form scalemode to pixel
3) Add a command button: command1
4) Add a VScroll: VScroll1
5) Add a picture box: picture1 and set AutoRedraw to true
6) Paste the following code and hit run, then click load.

Resize and scroll at will. Have fun...

If you want to go this way I could help further.....

Option Explicit

Dim Loaded As Boolean
Private Type LineDef
    startword As Long
    lastword As Long
End Type
Private Type Pointerdef
    Para As Long    ' Pointer to Para
    LIP As Long     ' Line in Para
End Type

Private Type FontDef
    Font As Font
    SpaceWidth As Long
    LineHeight As Long
End Type

Dim MyFonts() As FontDef

Private Type ParaDef
  Text As String
  WordCount As Long
  Words() As String
  Fonts() As Long
  PosX() As Long
  WLen() As Long     ' Length of each word
  Lines() As LineDef ' words in each line
End Type

Private Type DocDef
    Name As String
    Paras() As ParaDef
    ALP() As Pointerdef      ' Absolute line pointer to para ans line within para
End Type


Dim PB As PictureBox ' or picturebox

Dim Doc As DocDef

Dim CP As Long ' Current Para
Dim CW As Long ' Current Word
Dim CC As Long ' Current Character In Word
Dim TLOS As Long ' topline on screen
Dim SpaceWidth As Long

Dim ML As Long
Dim MR As Long
Dim MT As Long
Dim MB As Long
Dim w As Long
Dim h As Long

Dim LineHeight

Sub DisplayData()

' Get Size of window
w = PB.ScaleWidth - ML - MR
h = PB.ScaleHeight - MT - MB

Dim PosX As Long
Dim posY As Long
Dim lc As Long
Dim abslc As Long ' absolute linecount

PB.Cls ' clear window

Dim wc As Long ' word count


lc = 0
Dim startword As Long
Dim lastword As Long
Dim MaxHeight As Long
Dim cf As Long      ' current font
Dim lf As Long      ' last font
Dim P As Long

posY = MT

'Dim st As Single
'st = Timer

Do
   
    PosX = ML
    PB.CurrentY = posY ' if using multi fonts needs to be set for each word
       
    abslc = TLOS + lc
    If abslc > UBound(Doc.ALP) Then Exit Do
    P = Doc.ALP(abslc).Para ' para for this line
   
    MaxHeight = 0
   
    startword = Doc.Paras(P).Lines(Doc.ALP(abslc).LIP).startword
    lastword = Doc.Paras(P).Lines(Doc.ALP(abslc).LIP).lastword
   
    For wc = startword To lastword
        cf = Doc.Paras(P).Fonts(wc)
        If cf <> lf Then
           ' set new font here
           'set pb.font = myfonts.font
           lf = cf
        End If
       
        PB.CurrentX = Doc.Paras(P).PosX(wc)
        PB.Print Doc.Paras(P).Words(wc);
        If MyFonts(cf).LineHeight > MaxHeight Then
            MaxHeight = MyFonts(cf).LineHeight
        End If
       
    Next wc

    lc = lc + 1
   
    posY = posY + MaxHeight
   
    If posY + MyFonts(cf).LineHeight > h Then Exit Do
   
Loop

'MsgBox Format(Timer - st, "0.000") + " seconds to display page"
End Sub

Private Sub Command1_Click()

Dim YourText As String
ReDim Lines(0) As String
ReDim Doc.Paras(UBound(Lines))
Dim pc As Long
Dim wc As Long
Dim cf As Long
ReDim MyFonts(0)
Dim ddone As Boolean
Dim estlos As Long
Dim vs As VB.VScrollBar

' Create some test data
Dim ok
Dim k As Long
For wc = 1 To 4
    YourText = YourText + "Here is an example of some test data. "
Next wc


k = Val(InputBox("How many KB in your test data"))
If k < 1 Then
    k = 1
End If
k = k * 1024


YourText = Trim(YourText) + vbCrLf
Do
    YourText = YourText + YourText
    If Len(YourText) > k Then Exit Do
Loop
YourText = Left(YourText, k)


' Start the data loading

' set margins
ML = 10 ' left
MR = 10 ' right
MT = 10 ' top
MB = 10 ' bottom



Set PB = Picture1 ' pb can be a form or a picture box
PB.Font.Name = "Arial"

' Get Size of window
w = PB.ScaleWidth - ML - MR
h = PB.ScaleHeight - MT - MB
   
Set MyFonts(0).Font = PB.Font
MyFonts(0).SpaceWidth = PB.TextWidth(Space$(1))
MyFonts(0).LineHeight = PB.TextHeight("Z") + 1 ' 1 pixel gap between lines
estlos = h / MyFonts(0).LineHeight

'First get paragraphs:

Lines = Split(YourText, vbCrLf)
YourText = ""

ReDim Doc.Paras(UBound(Lines))

ReDim Doc.ALP(100)

Dim lc As Long ' current line

Dim pos As Long
Dim startword As Long
Dim tlc As Long ' total line count

Dim st As Single
st = Timer

       
' Now Get Words
For pc = 0 To UBound(Lines)
    lc = 0
    pos = 0
    Doc.Paras(pc).Text = Lines(pc)
    Lines(pc) = ""
    Doc.Paras(pc).WordCount = 0
    If Len(Doc.Paras(pc).Text) > 0 Then
        Doc.Paras(pc).Words = Split(Doc.Paras(pc).Text, Space$(1))
       
        Doc.Paras(pc).WordCount = UBound(Doc.Paras(pc).Words) + 1
        ReDim Doc.Paras(pc).WLen(Doc.Paras(pc).WordCount - 1)
        ReDim Doc.Paras(pc).PosX(Doc.Paras(pc).WordCount - 1)
        ReDim Doc.Paras(pc).Fonts(Doc.Paras(pc).WordCount - 1)
       
        ReDim Doc.Paras(pc).Lines(10)
       
        'Doc.Paras(lc)
        ' How big is each word?
        startword = 0
        pos = 0
        For wc = 0 To Doc.Paras(pc).WordCount - 1
            cf = 0
            Doc.Paras(pc).Fonts(wc) = cf
           
            Doc.Paras(pc).WLen(wc) = PB.TextWidth(Doc.Paras(pc).Words(wc))
            If pos + Doc.Paras(pc).WLen(wc) + MyFonts(cf).SpaceWidth > w Then
                pos = 0
                Doc.Paras(pc).PosX(wc) = pos

                Doc.Paras(pc).Lines(lc).startword = startword
                Doc.Paras(pc).Lines(lc).lastword = wc - 1
                startword = wc
                If tlc > UBound(Doc.ALP) Then
                    ReDim Preserve Doc.ALP(tlc)
                End If
                Doc.ALP(tlc).LIP = lc
                Doc.ALP(tlc).Para = pc
                tlc = tlc + 1   ' increase the absolute line count
                lc = lc + 1     ' and line within para count
                If lc > UBound(Doc.Paras(pc).Lines) Then
                    ReDim Preserve Doc.Paras(pc).Lines(lc + 10)
                End If
            Else
                Doc.Paras(pc).PosX(wc) = pos
            End If
            pos = pos + Doc.Paras(pc).WLen(wc) + MyFonts(cf).SpaceWidth
        Next wc
        ReDim Preserve Doc.Paras(pc).Lines(lc)
        If tlc > UBound(Doc.ALP) Then
            ReDim Preserve Doc.ALP(tlc + tlc * 0.25 + 100)
        End If
        Doc.ALP(tlc).LIP = lc
        Doc.ALP(tlc).Para = pc
        tlc = tlc + 1   ' increase the absolute line count
       
        Doc.Paras(pc).Lines(lc).startword = startword
        Doc.Paras(pc).Lines(lc).lastword = Doc.Paras(pc).WordCount - 1
    End If
    If Not ddone Then
        If tlc - 10 > estlos Then
            DisplayData
            DoEvents
            ddone = True
        End If
    End If
       
Next pc
Set vs = VScroll1

vs.Value = 0
vs.Max = tlc

ReDim Preserve Doc.ALP(tlc - 1)

Erase Lines

MsgBox "Data loaded in: " + Format(Timer - st, "0.000") + "seconds"

Loaded = True


CP = 0 ' Current Para
CW = 0 ' Currnt Word
CC = 0 ' Currnt Character In Word


End Sub

Private Sub Form_Load()

Command1.Caption = "Load Data"

End Sub

Private Sub Form_Resize()
Command1.Move 0, 0
Picture1.Move 0, Command1.Height, Me.ScaleWidth - VScroll1.Width, _
    Me.ScaleHeight - Command1.Height
VScroll1.Top = Picture1.Top
VScroll1.Height = Picture1.Height
VScroll1.Left = Picture1.Width
If Loaded Then
    w = PB.ScaleWidth - ML - MR
    h = PB.ScaleHeight - MT - MB
    RepaginateDocument Doc, w, h
    DisplayData
End If
End Sub

Private Sub VScroll1_Change()

VScroll1_Scroll
End Sub


Private Sub VScroll1_Scroll()
TLOS = VScroll1.Value
DisplayData

End Sub

Private Sub RepaginateDocument(ByRef Doc As DocDef, w As Long, h As Long)

Dim pc As Long

Dim wc As Long
Dim lc As Long
Dim pos As Long
Dim tlc As Long     ' total line count
Dim startword As Long
Dim lastword As Long
Dim cf As Long
Dim vs

tlc = 0

For pc = 0 To UBound(Doc.Paras)
    lc = 0
    pos = 0
   
    startword = 0
    pos = 0
    For wc = 0 To Doc.Paras(pc).WordCount - 1
        cf = Doc.Paras(pc).Fonts(wc)
        If pos + Doc.Paras(pc).WLen(wc) + MyFonts(cf).SpaceWidth > w Then
            pos = 0
            Doc.Paras(pc).PosX(wc) = pos

            Doc.Paras(pc).Lines(lc).startword = startword
            Doc.Paras(pc).Lines(lc).lastword = wc - 1
            startword = wc
            If tlc > UBound(Doc.ALP) Then
                ReDim Preserve Doc.ALP(tlc)
            End If
            Doc.ALP(tlc).LIP = lc
            Doc.ALP(tlc).Para = pc
            tlc = tlc + 1   ' increase the absolute line count

            lc = lc + 1     ' and line within para count
            If lc > UBound(Doc.Paras(pc).Lines) Then
                ReDim Preserve Doc.Paras(pc).Lines(lc + 10)
            End If
        Else
            Doc.Paras(pc).PosX(wc) = pos
        End If
        pos = pos + Doc.Paras(pc).WLen(wc) + MyFonts(cf).SpaceWidth
    Next wc
    ReDim Preserve Doc.Paras(pc).Lines(lc)
    If tlc > UBound(Doc.ALP) Then
        ReDim Preserve Doc.ALP(tlc + 100 + tlc * 0.25)
    End If
    Doc.ALP(tlc).LIP = lc
    Doc.ALP(tlc).Para = pc
    tlc = tlc + 1   ' increase the absolute line count
   
    Doc.Paras(pc).Lines(lc).startword = startword
    Doc.Paras(pc).Lines(lc).lastword = Doc.Paras(pc).WordCount - 1

Next pc
Set vs = VScroll1

vs.Value = 0
vs.Max = tlc

ReDim Preserve Doc.ALP(tlc - 1)

End Sub
Avatar of Mike McCracken
Mike McCracken

listening
Avatar of Sukhwinder Singh

ASKER

Hello inthedark

Thank you. I think you have spent some time for this long code. Example you provided is very good but there is small problem.
I did everything as you said but when I executed the program and straight way tried to move scroller run time error occurred:

Runtime error 91:
Object Variable or with block variable not set:

Sub DisplayData()

' Get Size of window
->w = PB.ScaleWidth - ML - MR
h = PB.ScaleHeight - MT - MB

Problem is with PB. I think it doesn't contain any valid object references at that time.

Problem doesn't arise when I first load data and then use scroll bar.

You have used picturebox as edit window. So question is:

1. Can it be used to highlight different keywords with different colors and fonts (as in editplus)?

2. Is there any limit on amount of data it can load.

Because when I tried to load 1044 kb of data it took 40 seconds but edit plus took only 7 seconds to load 1044 kb (even binary file) file even when it is a complete editor.

3. Do you think every one uses their custom controls for editors? Or there is any other control provided with VB enterprise edition which can be used? Or these editors are created in VC++?

I have modified the loading and now it loads 1044000 bytes in just 0.020 seconds.

So I only make if calculate size of words when it needs to display a line.

Dim st As Single
st = Timer

For pc = 0 To UBound(Lines)
    lc = 0
    pos = 0
    Doc.Paras(pc).Text = Lines(pc)
       
    Lines(pc) = ""
    ' whole load of stuff deleted from here
Next pc

Erase Lines

MsgBox "Data loaded in: " + Format(Timer - st, "0.000") + "seconds"

The target time for loading a 1MB file for me is 3.5 seconds as this is how long MS Word takes.
>1. Can it be used to highlight different keywords with >different colors and fonts (as in editplus)?

If you create the code you can make it do anything..

>2. Is there any limit on amount of data it can load.

Same limitation as any other program.
ASKER CERTIFIED SOLUTION
Avatar of inthedark
inthedark
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
What I asked about syntax highlighting is that is it possible to to something like changing color of different words using different colors using Picture box. Like changing fontsize of one word and changing font of another.
indianmunda, what time zone are you in?

I will post some other code that you will need but I would prefer to email it to you.  I am going to be busy for a few days so it could be some time before I can get back to you.

I have now improved the loading example as with super large documents you can't page directly to the end of the document.  But I have now resolved this - instead of using the scroll bar to select a line of the screen I will multiply the number of paragraphs by 10 and use this as a key to the line to display, so the user can page doen in paragraphs and won't know the difference. Or I may just add up each line in all paragraphs and do away with an absolute pointer to a specifc line - the problem with this is that for documents whic are serveral MB it would get slower - so the solution would be to be able to handle both types of addressing for best of both worlds.  In this way the max value can be found in a split second.  When all the paras in the document have been calculated to see how many lines on the screen that they would occupy the program will then revert to using absolute addressing to a specific line.

All you have seen so far is the code to display the data real fast.  But there are two major step for you to achieve next:

1) Control of Caret - I have created a handy simple class which does this.

2) Interfacing with the keyboard - I will post some examples of the keyboard events that you need to handle - but they were written for a different concept.

As you can guess I have already written sevral word processors.  But the last version I created I was not happy with the load speed as it used Public Classes which are very slow.

Eventually I will take the loading example above and make a WP program from it - but not for serveral weeks.

You asked how to handle words with different Fonts/colours:

First you need to understand the document structure:

' Pointers to the start and end words for each line within a para.
Private Type LineDef
   startword As Long
   lastword As Long
End Type

' An element for an absolute line number which points to a specifc line within a paragraph.
' I intend to make this redudant.
Private Type Pointerdef
   Para As Long    ' Pointer to Para
   LIP As Long     ' Line in Para
End Type

' Each word can point to a different font.
' So for each font variation you need one of these

Simple:

Private Type FontDef
   StyleName as String
   Font As Font   ' Points to a collection of pre-loaded fonts
   SpaceWidth As Long
   LineHeight As Long
End Type

More Complex:
Private Type FontDef
   StyleName as String
   FontName as String
   FontSize as String
   Color
   Bold
   etc.
   SpaceWidth As Long
   LineHeight As Long
End Type


' Are store of the fonts used in the document
' This should be moved to be a part of the DocDef structure
Dim MyFonts() As FontDef

' Each Paragrapgs is loaded into this structure:
Private Type ParaDef
 Text As String
 WordCount As Long
 Words() As String
 WordsAttributes() As String
 Fonts() As Long
 PosX() As Long
 WLen() As Long     ' Length of each word
 Lines() As LineDef ' words in each line
End Type

' This structure contains document data
' I will move the document parameters and fonts into here
Private Type DocDef
   Name As String
   Paras() As ParaDef
   ALP() As Pointerdef      ' Absolute line pointer to para and line within para
   MyFonts() as FontDef
   Parameters() AS ParamsDef ' Create a structure to hold document parameters
End Type


So when displaying a word you can see if the Word's font has changed

' Each Word can have a different font pointer
Word = Doc.Paras(CP).Word(WC)
CF = Doc.Paras(CP).Fonts(WC)

So when displaying a word you can see if the Font has Changed:

If CF <> LF Then ' Current Font <> Last Font
   Set PB.Font = Doc.MyFonts(CF).Font
End If

This means that you have to preload all of the required fonts into Doc.MyFonts()

Another more simple way to do it is to store the Font details in the FontDefs struture the you can say:

If CF <> LF Then ' Current Font <> Last Font
   PB.Font.Name = Doc.MyFonts(CF).FontName
   PB.Font.Size = Doc.MyFonts(CF).FontSize
   PB.Font.Bold = Doc.MyFonts(CF).FontBold
   etc.
End If













Once again thank you very much sir
I forgot to mention my time zone is gmt + 5:30 and myemail ssruprai@hotmail.com. Whenever you are free you can send that code.
Thanks
Hello,
     What I want is an editor similar to VB's Code Editor(but it is limited). An editor for programming like editplus(http://www.editplus.com/). You can check editplus and then you'll know what I want to do. I don't want a word processor like wordpad or MsWord and text will be saved as plain text.
     
     So I want a syntax file to be loaded in memory according to file extension of the current file. So when someone opens .Java file then words like int, long and for etc. should be highlighted in different colors. When editing a file when someone types a keyword it should automatically highlighted.
     But problem is how to change color or font of only that particular word in Picture Box. I mean is there any way where I can do something like:

     pictureBox.currentword.foreColor = vbRed      or
     pictureBox.words(35).foreColor = vbRed          or
     pictureBox.words(35).font = "Times new Roman"

     So, problem is giving a word a foreColor, backcolor or a font property. I think you got the Idea.
Control created using above code loads text very fast but scrolling speed isn't acceptable at all. Which means refreshing has a big problem.