How to create Slideshow and VideoConverter by FFmpeg MediaToolkit.
This is one tab on one of the my interesting program for creating slide show. In this page I describe one tabs of this program - tab fo training for processing one simple slideshow, without Polly and Pixabay. However this program can resize photo before processing, insert text (like lyrics or subtitles) and insert music. By this program you can create beautiful video from your travel, insert description for each photo and insert music to your video.
This program working on .NET interface to compiled FFMpeg to Windows - https://github.com/AydinAdn/MediaToolkit. Program working carefully, with catching error, without freezing GUI (all durable operation going in background), scale photo images to HD video, store sequence video number in registry and has many various modes to tune working. This is common view of tab I describe in this page.
And this is name of form variaables in this tab.
And this is a code of my Slideshow creator.
1: Imports System.Collections.ObjectModel
2: Imports System.ComponentModel
3: Imports System.Drawing.Drawing2D
4: Imports System.Drawing.Imaging
5: Imports MediaToolkit
6:
7: Public Class StartForm
8:
9:
10: Private Sub StartForm_Load(sender As Object, e As EventArgs) Handles Me.Load
11: Application.DoEvents()
12: GoNum = CInt(RegistryCreateOrRead(10))
13: Dim Assembly As System.Reflection.Assembly = System.Reflection.Assembly.GetExecutingAssembly()
14: Dim fvi As FileVersionInfo = FileVersionInfo.GetVersionInfo(Assembly.Location)
15: Dim Version = fvi.FileVersion
16: Me.Text &= " (" & Version & ")"
17: TabControl1.DrawMode = TabDrawMode.OwnerDrawFixed
18: TabControl1.SelectedIndex = 1
19: TabControl1.SelectedIndex = 0
20: Step1Panel.Visible = True
21: Step2Panel.Visible = False
22: End Sub
23:
24: Private Sub TabControl1_Selected(sender As Object, e As TabControlEventArgs) Handles TabControl1.Selected
25: CurrenPageIndex = e.TabPageIndex
26: TabControl1.Refresh()
27:
28: If e.TabPage.Name = "StartTab" Then
...
41: ElseIf e.TabPage.Name = "SettingTab" Then
...
52: ElseIf e.TabPage.Name = "SupportTab" Then
...
58: ElseIf e.TabPage.Name = "TrainingTab" Then
59:
60: ElseIf e.TabPage.Name = "PollyTab" Then
...
66: ElseIf e.TabPage.Name = "PixabayTab" Then
...
75: End If
76: End Sub
77:
78:
79: #Region "Master"
80:
81: Dim CurrentStep As Integer
82: Dim CurrenPageIndex As Integer
83: Private Overloads Sub tabControl1_DrawItem(ByVal sender As Object, ByVal e As DrawItemEventArgs) Handles TabControl1.DrawItem
84: Try
85: Dim br As Brush = New SolidBrush(System.Drawing.SystemColors.Highlight)
86: Dim sz As SizeF
87: If e.Index = CurrenPageIndex Then
88: sz = e.Graphics.MeasureString(TabControl1.TabPages(e.Index).Text, e.Font)
89: e.Graphics.DrawString(TabControl1.TabPages(e.Index).Text, e.Font, br, e.Bounds.Left + (e.Bounds.Width - sz.Width) / 2, e.Bounds.Top + (e.Bounds.Height - sz.Height) / 2 + 1)
90: Else
91: sz = e.Graphics.MeasureString(TabControl1.TabPages(e.Index).Text, e.Font)
92: e.Graphics.DrawString(TabControl1.TabPages(e.Index).Text, e.Font, Brushes.Black, e.Bounds.Left + (e.Bounds.Width - sz.Width) / 2, e.Bounds.Top + (e.Bounds.Height - sz.Height) / 2 + 1)
93: End If
94: Catch ex As Exception
95:
96: End Try
97: End Sub
...
719: #Region "Test Form"
720: Dim ffmpeg As MediaToolkit.Engine
721: Dim WithEvents BG1 As BackgroundWorker
722: Dim WithEvents BG2 As BackgroundWorker
723: Dim CMD As String
724: Dim GoNum As Integer
725: Dim IsProgress As Boolean = False
726: Private Sub Button1_Click(sender As Object, e As EventArgs) Handles TstGoButton1.Click
727: Try
728:
729: BG2 = New BackgroundWorker
730: 'CMD = " -f concat -safe 0 -i ""E:\Tmp\IMG\concat.txt"" " &
731: ' "-i ""E:\Angular\YTB076.mp3"" " &
732: ' "-c:v libx264 -vcodec libx264 -c:a aac -pix_fmt yuv420p -framerate 30 -shortest " &
733: ' "-y E:\Angular\out.mp4"
734:
735: GoNum += 1
736: RegistryUpdate(GoNum)
737:
738: Dim TXT As String() = System.IO.File.ReadAllLines(CaptionFile)
739: Dim Prm2 = New With {.ImageFiles = ImageFiles, .TXT = TXT}
740: BG2.RunWorkerAsync(Prm2)
741:
742: Catch ex As Exception
743: MsgBox(ex.Message)
744: End Try
745:
746: End Sub
747:
748: '?????? ?????? ?? ???????????? ????????????
749: Private Sub BG1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BG1.DoWork
750: Using ffmpeg = New MediaToolkit.Engine
751: AddHandler ffmpeg.ConversionCompleteEvent, AddressOf ConversionCompleteEvent
752: AddHandler ffmpeg.ConvertProgressEvent, AddressOf ConvertProgressEvent
753: ffmpeg.CustomCommand(e.Argument)
754: End Using
755: End Sub
756:
757: '?????????? ?????????? ?? ???????????????? ????????????
758: Private Sub BG1_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BG1.RunWorkerCompleted
759: If Not IsProgress Then
760: Dim X As New ErrForm
761: X.RedText.Add({0, 36})
762: X.RedText.Add({260, 500})
763: X.ErrorMessage = "Video creating process not started." & vbCrLf & vbCrLf &
764: "If you want more details information about this error" & vbCrLf &
765: "please install fistly FFMPEG from https://ffmpeg.zeranoe.com/builds/" & vbCrLf &
766: "than open CMD.EXE, navigate to BIN folder of installed program (CD .../BIN)" & vbCrLf &
767: "and type command below" & vbCrLf & vbCrLf &
768: "ffmpeg " & CMD
769: X.ShowDialog()
770: Else
771: For Each One In ImageFiles
772: My.Computer.FileSystem.DeleteFile(One.ToLower.Replace(".jpg", "_x.jpg"))
773: Next
774: OpenOutputButton.Enabled = True
775: End If
776: IsProgress = False
777: End Sub
778:
779: Function ConversionCompleteEvent(sender As Object, e As MediaToolkit.ConversionCompleteEventArgs)
780: If Me.InvokeRequired Then
781: StartForm_Instance.BeginInvoke(Sub()
782: StatusLabel1.Text = "Complete. Frame=" & e.Frame & " ,ProcessedDuration=" & e.ProcessedDuration.ToString & ", SizeKb=" & e.SizeKb
783: StatusStrip1.Refresh()
784: IsProgress = True
785: End Sub)
786: End If
787:
788: End Function
789:
790: Function ConvertProgressEvent(sender As Object, e As MediaToolkit.ConvertProgressEventArgs)
791: If Me.InvokeRequired Then
792: StartForm_Instance.BeginInvoke(Sub()
793: StatusLabel1.Text = "Progress. Frame=" & e.Frame & ", TotalDurationSec=" & e.ProcessedDuration.ToString & ", SizeKb=" & e.SizeKb
794: StatusStrip1.Refresh()
795: IsProgress = True
796: End Sub)
797:
798: End If
799: End Function
800:
801:
802: Public Delegate Sub UpdateLabelHandler(sender As Object, name As String)
803: Private Sub UpdateProgressLabel(sender As Object, value As String)
804: sender.txt = value
805: End Sub
806:
807: '?????? ?????? ?? ???????????? ????????????
808: Private Sub BG2_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BG2.DoWork
809: Try
810: Dim ImageNum As Integer = 0
811: Using FNT As Font = New Font("Arial", FontSize)
812: Using BR As SolidBrush = New SolidBrush(FontColor)
813: For Each One As String In e.Argument.ImageFiles
814: If One.ToLower.Contains(".jpg") Then
815: Dim BM As Bitmap = TryCast(Image.FromFile(One), Bitmap)
816: Dim SourceH As Integer = BM.Height
817: Dim SourceW As Integer = BM.Width
818: Dim SourceRatio As Single = SourceW / SourceH
819: Dim DivInH As Single = SourceH / MaxHeigth
820: Dim DivInW As Single = SourceW / MaxWidth
821: Dim NewBitmap As Bitmap
822: If DivInW > DivInH Then
823: NewBitmap = ResizeBitmap(BM, MaxWidth, SourceH / SourceRatio)
824: Else
825: NewBitmap = ResizeBitmap(BM, SourceW / SourceRatio, MaxHeigth)
826: End If
827: Using GR As Graphics = Graphics.FromImage(NewBitmap)
828: 'GR.DrawString(ImageNum.ToString, FNT, New SolidBrush(FontColor), New PointF(LeftGap / 2, TopGap / 2))
829: For RowNum As Integer = 0 To RowPerSlide - 1
830: 'Debug.Print(FNT.Size)
831: GR.DrawString(GetNextLine(e.Argument.TXT, ImageNum, RowNum), FNT, New SolidBrush(FontColor), GetNewPointF(RowNum))
832: Next
833: End Using
834: NewBitmap.Save(One.ToLower.Replace(".jpg", "_x.jpg"))
835: StartForm_Instance.BeginInvoke(Sub()
836: StatusLabel1.Text = One
837: StatusStrip1.Refresh()
838: End Sub)
839: End If
840: ImageNum += 1
841: Next
842: End Using
843: End Using
844: Catch ex As Exception
845: StartForm_Instance.BeginInvoke(Sub()
846: Dim X As New ErrForm
847: X.ErrorMessage = ex.Message
848: X.ShowDialog()
849: End Sub)
850: End Try
851:
852: End Sub
853:
854: Public Function ResizeBitmap(ByVal bmp As Bitmap, ByVal width As Integer, ByVal height As Integer) As Bitmap
855: Dim result As Bitmap = New Bitmap(width, height)
856: Using g As Graphics = Graphics.FromImage(result)
857: g.DrawImage(bmp, 0, 0, width, height)
858: End Using
859: Return result
860: End Function
861:
...
881: Function GetNextLine(TXT As String(), ImageNum As Integer, RowNum As Integer) As String
882: If RowNum + ImageNum * RowPerSlide < TXT.Length Then
883: 'Debug.WriteLine("(" & RowNum + ImageNum * RowPerSlide & ") " & TXT(RowNum + ImageNum * RowPerSlide))
884: Return (TXT(RowNum + ImageNum * RowPerSlide))
885: Else
886: Return ""
887: End If
888: End Function
889:
890: Function GetNewPointF(RowNum As Integer) As PointF
891: If TopGap + RowNum * (FontSize + FontLineSpacing) > MaxHeigth Then
892: StartForm_Instance.BeginInvoke(Sub()
893: Dim X As New ErrForm
894: X.ErrorMessage = "Text line truncated because " & vbCrLf & "MaxHeigth=" & MaxHeigth & "RowPerSlide=" & RowPerSlide & vbCrLf & "caption line try to place outside of image Y-dimension, in pos=" & TopGap + RowNum * (FontSize + FontLineSpacing)
895: X.ShowDialog()
896: End Sub)
897: Else
898: Return New PointF(LeftGap, TopGap + RowNum * (FontSize + FontLineSpacing))
899: End If
900:
901: End Function
902:
903: Private Sub BG2_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BG2.RunWorkerCompleted
904: StatusLabel1.Text = "Done."
905: StatusStrip1.Refresh()
906: '
907:
908: Dim DemuxerFile As String = IO.Path.Combine(System.IO.Path.GetTempPath, GoNum & ".txt")
909: CreateDemuxer(DemuxerFile)
910:
911: BG1 = New BackgroundWorker
912:
913: CMD = String.Format(" -f concat -safe 0 -i ""{0}"" " &
914: "-i ""{1}"" " &
915: "-c:v libx264 -vcodec libx264 -c:a aac -pix_fmt yuv420p -framerate {3} {4} {5}" &
916: "-y ""{2}"" ", DemuxerFile, MusicFile, IO.Path.Combine(OutputFolderPath, GoNum & ".mp4"), Framerate, Shortest, AnyOut)
917: IsProgress = False
918: BG1.RunWorkerAsync(CMD)
919: End Sub
920:
921:
922: Dim CaptionFile As String
923: Private Sub TstTextSelectButton_Click(sender As Object, e As EventArgs) Handles TstTextSelectButton.Click
924: Dim FB7 = New System.Windows.Forms.OpenFileDialog()
925: FB7.Title = "Select txt file"
926: FB7.DefaultExt = "txt"
927: FB7.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*"
928: FB7.FilterIndex = 1
929: FB7.CheckFileExists = True
930: FB7.CheckPathExists = True
931: Dim Res3 = FB7.ShowDialog
932: If Res3 = DialogResult.OK Then
933: CaptionFile = FB7.FileName
934: Label14.ForeColor = SystemColors.ActiveCaption
935: CheckTstReady()
936: End If
937: End Sub
938:
939: Dim MusicFile As String
940: Private Sub TstMusicSelectButton_Click(sender As Object, e As EventArgs) Handles TstMusicSelectButton.Click
941: Dim FB6 = New System.Windows.Forms.OpenFileDialog()
942: FB6.Title = "Select music file"
943: FB6.DefaultExt = "mp3"
944: FB6.Filter = "mp3 files (*.mp3)|*.mp3|All files (*.*)|*.*"
945: FB6.FilterIndex = 1
946: FB6.CheckFileExists = True
947: FB6.CheckPathExists = True
948: Dim Res3 = FB6.ShowDialog
949: If Res3 = DialogResult.OK Then
950: MusicFile = FB6.FileName
951: Label15.ForeColor = SystemColors.ActiveCaption
952: CheckTstReady()
953: End If
954: End Sub
955:
956: Private Sub TstImagesSelectButton_Click(sender As Object, e As EventArgs) Handles TstImagesSelectButton.Click
957: Dim FB5 = New System.Windows.Forms.FolderBrowserDialog()
958: FB5.Description = "Select images folder"
959: Dim Res3 As DialogResult = FB5.ShowDialog
960: If Res3 = DialogResult.OK Then
961: ImagesFolderPath = FB5.SelectedPath
962: ImageFiles = My.Computer.FileSystem.GetFiles(ImagesFolderPath)
963: Label16.ForeColor = SystemColors.ActiveCaption
964: CheckTstReady()
965: End If
966: End Sub
967:
968: Dim OutputFolderPath As String
969: Private Sub TstOutFolderButton_Click(sender As Object, e As EventArgs) Handles TstOutFolderButton.Click
970: Dim FB4 = New System.Windows.Forms.FolderBrowserDialog()
971: FB4.Description = "Select output folder"
972: Dim Res3 As DialogResult = FB4.ShowDialog
973: If Res3 = DialogResult.OK Then
974: OutputFolderPath = FB4.SelectedPath
975: Label18.ForeColor = SystemColors.ActiveCaption
976: CheckTstReady()
977: End If
978: End Sub
979:
980: Sub CheckTstReady()
981: If Label14.ForeColor = SystemColors.ActiveCaption And
982: Label15.ForeColor = SystemColors.ActiveCaption And
983: Label16.ForeColor = SystemColors.ActiveCaption And
984: Label18.ForeColor = SystemColors.ActiveCaption Then
985: TstGoButton1.Enabled = True
986: End If
987: End Sub
988:
989: Sub CreateDemuxer(DemuxerFile As String)
990: Dim Str1 As New Text.StringBuilder
991: For Each One As String In ImageFiles
992: If One.ToLower.Contains(".jpg") Then
993: Str1.AppendLine("file " & "'" & One.ToLower.Replace(".jpg", "_x.jpg") & "'")
994: Str1.AppendLine("duration " & Duration.ToString & ".0")
995: End If
996: Next
997: Dim utf8WithoutBom As New System.Text.UTF8Encoding(False)
998: My.Computer.FileSystem.WriteAllText(DemuxerFile, Str1.ToString, False, utf8WithoutBom)
999:
1000: End Sub
1001: #End Region
1002:
1003: #Region "Registry"
1004:
1005: Dim SubKeyName As String = "VideoCreator2"
1006: Dim ValueName As String = "Num"
1007: Function RegistryCreateOrRead(SetNewValue As String) As String
1008: Using LogonKey As Microsoft.Win32.RegistryKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("SOFTWARE\" & SubKeyName, True)
1009: If LogonKey Is Nothing Then
1010: Using SOFTWARE As Microsoft.Win32.RegistryKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("SOFTWARE", True)
1011: Using MyKey As Microsoft.Win32.RegistryKey = SOFTWARE.CreateSubKey(SubKeyName)
1012: MyKey.SetValue(ValueName, SetNewValue)
1013: End Using
1014: End Using
1015: Else
1016: Return LogonKey.GetValue(ValueName)
1017: End If
1018: End Using
1019: End Function
1020:
1021: Sub RegistryUpdate(SetNewValue As String)
1022: Using LogonKey As Microsoft.Win32.RegistryKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("SOFTWARE\" & SubKeyName, True)
1023: If LogonKey Is Nothing Then
1024: Using SOFTWARE As Microsoft.Win32.RegistryKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("SOFTWARE", True)
1025: Using MyKey As Microsoft.Win32.RegistryKey = SOFTWARE.CreateSubKey(SubKeyName)
1026: MyKey.SetValue(ValueName, SetNewValue)
1027: End Using
1028: End Using
1029: Else
1030: Using MyKey As Microsoft.Win32.RegistryKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("SOFTWARE\" & SubKeyName, True)
1031: MyKey.SetValue(ValueName, SetNewValue)
1032: End Using
1033: End If
1034: End Using
1035: End Sub
1036: #End Region
1037:
1038: Private Sub TuneTxtButton_Click(sender As Object, e As EventArgs) Handles TuneTxtButton.Click
1039: Dim X As New TuneTxtForm
1040: X.ShowDialog()
1041: End Sub
1042:
1043: Public Framerate As Integer = 30
1044: Public Shortest As String = "-shortest"
1045: Public AnyOut As String = ""
1046: Public Duration As Integer = 4
1047: Public FontColor As Color = Color.Black
1048: Public FontSize As Integer = 30
1049: Public FontLineSpacing As Integer = 100
1050: Public RowPerSlide As Integer = 7
1051: Public TopGap As Integer = 100
1052: Public LeftGap As Integer = 100
1053: Public MaxWidth As Integer = 1920
1054: Public MaxHeigth As Integer = 1080
1055: Public OrderBy As String = "Name (asc)"
1056:
1057:
1058: Private Sub TuneOutButton_Click(sender As Object, e As EventArgs) Handles TuneOutButton.Click
1059: Dim X As New TuneOutputForm
1060: X.ShowDialog()
1061: End Sub
1062:
1063: Private Sub TuneImageButton_Click(sender As Object, e As EventArgs) Handles TuneImageButton.Click
1064: Dim X As New TuneSlideShowForm
1065: X.ShowDialog()
1066: End Sub
1067:
1068: Private Sub OpenOutputButton_Click(sender As Object, e As EventArgs) Handles OpenOutputButton.Click
1069: Process.Start("explorer.exe", OutputFolderPath)
1070: End Sub
1071:
1072: Private Sub ConvertJpegButton_Click(sender As Object, e As EventArgs)
1073: Dim X As New ErrForm
1074: X.ErrorMessage = "Sorry in this version you have to convert images folder to needed size manually" & vbCrLf &
1075: "try to use https://www.xnview.com/en/xnview/" & vbCrLf &
1076: "install it, than navigate Tools->Batch Processing"
1077: X.ShowDialog()
1078: End Sub
1079:
1080: Private Sub Button2_Click(sender As Object, e As EventArgs)
1081: BG2 = New BackgroundWorker
1082: Dim TXT As String() = System.IO.File.ReadAllLines(CaptionFile)
1083: Dim Prm2 = New With {.ImageFiles = ImageFiles, .TXT = TXT}
1084: BG2.RunWorkerAsync(Prm2)
1085: End Sub
1086: End Class
Also program has some additional window - Set caption mode, Set output video mode and Set slideshow mode. And ErrorForm with one decked Richtextbox.
1: Public Class TuneTxtForm
2:
3: Private Sub TuneTxtForm_Load(sender As Object, e As EventArgs) Handles Me.Load
4: RowPerSlideNumericUpDown.Value = StartForm_Instance.RowPerSlide
5: FontSizeNumericUpDown.Value = StartForm_Instance.FontSize
6: TopGapNumericUpDown.Value = StartForm_Instance.TopGap
7: LineSpacingNumericUpDown.Value = StartForm_Instance.FontLineSpacing
8: LeftGapNumericUpDown.Value = StartForm_Instance.LeftGap
9: End Sub
10:
11: Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
12: Dim X As New ColorDialog
13: If X.ShowDialog() = DialogResult.OK Then
14: StartForm_Instance.FontColor = X.Color
15: End If
16: End Sub
17:
18: Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
19: StartForm_Instance.RowPerSlide = RowPerSlideNumericUpDown.Value
20: StartForm_Instance.FontSize = FontSizeNumericUpDown.Value
21: StartForm_Instance.TopGap = TopGapNumericUpDown.Value
22: StartForm_Instance.LeftGap = LeftGapNumericUpDown.Value
23: StartForm_Instance.FontLineSpacing = LineSpacingNumericUpDown.Value
24: Me.Close()
25: End Sub
26:
27: End Class
1: Public Class TuneOutputForm
2:
3: Private Sub TuneOutputForm_Load(sender As Object, e As EventArgs) Handles Me.Load
4: FramerateNumericUpDown.Value = StartForm_Instance.Framerate
5: AnyOutTextBox.Text = StartForm_Instance.AnyOut
6: If StartForm_Instance.Shortest = "-shortest" Then ShortestCheckBox.Checked = True
7: End Sub
8:
9: Private Sub LinkLabel1_LinkClicked(sender As Object, e As LinkLabelLinkClickedEventArgs) Handles LinkLabel1.LinkClicked, LinkLabel2.LinkClicked
10: Process.Start("C:\Program Files\Mozilla Firefox\Firefox.exe", "https://ffmpeg.org/ffmpeg.html")
11: End Sub
12:
13: Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
14: StartForm_Instance.Framerate = FramerateNumericUpDown.Value
15: If ShortestCheckBox.Checked Then StartForm_Instance.Shortest = "-shortest" Else StartForm_Instance.Shortest = ""
16: StartForm_Instance.AnyOut = AnyOutTextBox.Text
17: Me.Close()
18: End Sub
19:
20:
21: End Class
1: Public Class TuneSlideShowForm
2:
3:
4: Private Sub TuneSlideShowForm_Load(sender As Object, e As EventArgs) Handles Me.Load
5: DurationNumericUpDown.Value = StartForm_Instance.Duration
6: MaxHeigthNumericUpDown.Value = StartForm_Instance.MaxHeigth
7: MaxWidthNumericUpDown.Value = StartForm_Instance.MaxWidth
8: OrderByComboBox.SelectedText = StartForm_Instance.OrderBy
9: End Sub
10:
11: Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
12: StartForm_Instance.Duration = DurationNumericUpDown.Value
13: StartForm_Instance.MaxHeigth = MaxHeigthNumericUpDown.Value
14: StartForm_Instance.MaxWidth = MaxWidthNumericUpDown.Value
15: StartForm_Instance.OrderBy = OrderByComboBox.Text
16: Me.Close()
17: End Sub
18:
19: End Class
1: Public Class ErrForm
2: Public Property ErrorMessage As String
3: Public Property RedText As New ArrayList
4:
5: Private Sub ErrForm_Load(sender As Object, e As EventArgs) Handles Me.Load
6: RichTextBox1.Text = ErrorMessage
7: RichTextBox1.DeselectAll()
8: For Each One In RedText
9: RichTextBox1.Select(One(0), One(1))
10: RichTextBox1.SelectionColor = Color.Brown
11: Next
12: RichTextBox1.DeselectAll()
13: End Sub
14: End Class
|