Visual Basic: Bir konsol uygulamasında ASCII metnin kenarlığını nasıl çizersiniz?(tr-TR)

Visual Basic: Bir konsol uygulamasında ASCII metnin kenarlığını nasıl çizersiniz?(tr-TR)



Giriş


Konsol uygulaması çok bir kullanıcı arabirimi gerektirmeyen basit bir yardımcı program yazmak için kullanışlı bir yoldur.Genellikle bir konsol uygulaması presler girin ve pencereyi geri satırlık metin komut yürütme sonuç raporları nerede kullanıcı türleri penceresine komutları bir komut satırı arabirimi kullanır.

Ama önce programları ile pencere ve düğmeler ve fancy widget tıklatın için programların menüleri ile vardı ve anahtar maps ve GUI'leri ASCII karakter kurdu. Sen bile böyle bir ekran yeni bir işletim sistemi veya bir BIOS yapılandırma yüklerken görmüş olabilirsiniz. Kez bugün ne zaman bir komut istemi penceresinde çalışır ASCII olarak tasarlanmış basit bir arayüzü kullanan modern bir uygulama oluşturmak için mantıklı olabilir.

Biri bugün böyle bir arayüz yapma hakkında gidebilir yolları vardır. Karakter (aslında kendi "tampon" konsol penceresi için) iki boyutlu bir dizi tanımlamak ve el ile "pencere" çerçeve yapma ve bu karakterler diziyi depolama ASCII karakterleri dizi eşlemek için geleneksel bir yaklaşım olurdu. Program kendi arabellek penceresine göre atanan karakter sonra çekiyor.Farklı tasarımlar ara belleğe yüklenen ve konsola yazılmış.

Bu yazı biraz daha gelişmiş bir yaklaşım alacak ve düzenine uygun dizi ASCII karakteri tanımlanmış dikdörtgen pencere çerçevesi temsil eden bir dizi dayalı bir algoritma kullanır. Bu tarif için en kolay yolu, bir resim ile olabilir:



Burada bir çift çizgili kenarlık altında ve üstünde de bir kutu ile pencere iç görebilirsiniz. Bu çerçevede, dikdörtgenler tarif edilebilir:

border 

"Biraz daha gelişmiş" burada sunulan bir yaklaşım olabilir ancak, düz ileri ve bir daha çok takip edilmesi kolay kullanılan algoritma (ya da gerçekten) gelişmiş versiyonu-hala var hazırlanmış.

Devam etmeden önce okuyun!

Devam etmeden önce lütfen okuyun nasıl metin kaydırma olmadan konsol penceresine yazınBu makaledeki kod kullanmadan önce bu makalede gösterilen örnek tamamlamak gerekir.

FrameRenderer oluşturma

Bu örnekte bize tüm özellikleri ve ASCII karakter dikdörtgen üzerinde temel bir çerçeve oluşturmak için gereken işlevselliği sağlamak FrameRenderer adındaki bir statik sınıf oluşturur.

Ama FrameRenderer oluşturabilmeniz için gerekli olacak destek nesneleri bir çift vardır; "FrameCellType" ve dikdörtgen çerçeve belirli bir parçası kullanılan ASCII karakter türünü izlemek sağlamak için yani.

Dikdörtgen yapısı

Tek ihtiyacımız olan basit bir dikdörtgen bir başvuru System.Drawing eklemek gerek tutmak için amacımıza uygun olarak kendi küçük yapısını tanımlayın:

Public Structure  Rectangle
    Public Left As Integer
    Public Height As Integer
    Public Top As Integer
    Public Width As Integer
   
    Public Function  Right() As  Integer
        Return Left + Width - 1
    End Function
   
    Public Function  Bottom() As  Integer
        Return Top + Height - 1
    End Function
   
    Public Sub  New(l As Integer, t As  Integer, w As Integer, h As  Integer)
        Left = l
        Top = t
        Width = w
        Height = h
    End Sub
End Structure

Bu yapı basit bir sol, üst, genişlik ve yükseklik değeri bizim için ayarlanmış tutar. Sadece kolaylık için sağ ve alt bir yöntem sunar.

FrameCellType numaralandırma

Geleneksel Karakter Eşlem'i kullanarak yaptığımız gibi bizim çerçeve yapmak karakterler izlemek için iki boyutlu bir dizi tanımlamak olacaktır. Ama gerçek ASCII karakterleri depolamak yerine, belirli bir karakterin bizi ipe olmadan karakterler çerçeve içinde başvurmak izin numaralandırma değerleri depolar. Biz kısa bir süre sonra bu FrameRenderer sınıfa çok yönlülük ekler nasıl görürsünüz.

Enum çerçeve her olası bir bölümünü tanımlayan değerleri içerir:

Public Enum FrameCellType
    Empty
   
    Horizontal
    Vertical
   
    BottomLeft
    BottomRight
    TopLeft
    TopRight
   
    TeeBottom
    TeeLeft
    TeeRight
    TeeTop
   
    Cross
End Enum

Yani burada biz karakterler için yatay ve dikey çizgiler, bir dikdörtgen herhangi bir tarafındaki kesişim noktasını (T) ve bir dikdörtgen köşelerini tanımlayın. Elinde bu bilgi ile artık dikdörtgenler tek bir kare birleştirebilirsiniz bir algoritma yazmaya başlayabiliriz.

Ön sınıf düzeni

Bir yerde bizim destek nesneleri ile artık FrameRenderer sınıf tasarlamak başlayabilirsiniz. Bu tüm statik (paylaşılan) üyeleri ile mühürlenmiş bir sınıf olabilir. Kullanıcılar, bu sınıfın bir örneğini oluşturmak değil ama oldukça sade bir şekilde sınıf işlevi kullanmak için paylaşılan yöntemleri arayacağım. Başlamak için biz kapalı sınıf bildirmek ve çerçeve ve bireysel karakterlerinin kullanılmasını sağlayacak karakter dizisi karakterleri izlemek için kullanılan hücre türü dizi tanımlayın:

Public NotInheritable  Class FrameRenderer
   
    Private Shared  _Cells(,) As  FrameCellType
    Private Shared  _Characters() As Char  "╚╝╬═╩╠╣╦╔╗║"
   
    Protected Sub  New()
    End Sub
   
End Class

Bu örnek ASCII karakter bir çift çizgili kenarlığı için varsayılan olarak kullanır, ancak onbir karakterleri herhangi bir dizi _Characters() dizi ayarlayabilirsiniz. Örneğin, işte tek çizgili kenarlık karakter dizisi: "└┘┼─┴├┤┬┌┐│"

Algoritma yazın ve izleyin kolay yapmak için biz onbir özellikleri bize göre çerçeve türü adını _Characters() diziden bir karakter erişmesine izin veren bir sınıfa ekleyeceğiz:

Public Shared ReadOnly Property BottomLeft As Char
    Get
        Return _Characters(0)
    End Get
End Property
Public Shared ReadOnly Property BottomRight As Char
    Get
        Return _Characters(1)
    End Get
End Property
   
...
   
Public Shared ReadOnly Property Vertical As Char
    Get
        Return _Characters(10)
    End Get
End Property

Şimdi bizim algoritması içerir ve dikdörtgenler tarafından tanımlanan karakter çizimi işi yapmak DrawFrame() yöntemi oluşturabilirsiniz. Yöntem de yöntem imzası ve kod ilk satırları olursunuz, renk belirtmek için parametre alacak:

Public Shared Sub DrawFrame(forecolor As ConsoleColor, backcolor As ConsoleColor, ParamArray bounds() AsRectangle)
    Dim forecolorDelta As ConsoleColor = Console.ForegroundColor
    Dim backcolorDelta As ConsoleColor = Console.BackgroundColor
    Console.ForegroundColor = forecolor
    Console.BackgroundColor = backcolor
    ReDim _Cells(Console.WindowWidth - 1, Console.WindowHeight - 1)
   
End Sub

Bu her şeyi göre dikdörtgen çerçeve çizim başlamak hazır hale getirilir. 

Algoritma

Genel algoritması artık iç içe geçmiş döngüleri çok Select Case deyimi ile bir çift olur. En dış döngünün her yönteme geçirilen dikdörtgenler arasında yinelemek gerekir. Her dikdörtgen için kod dikdörtgenin üst kısmından altına döngü gerekebilir. Üst ve alt döngü içindeki her satırı için kod soldan sağa doğru döngü gerekebilir. -Sol döngü içinde kod İmlecin geçerli konumuna getirin ve sonra karakter geçerli konumda ayarlama veya karakter nedir ve hangi karakter için geçerli dikdörtgen gerekli temel karakter güncelleştirme türünü analiz.

For Each As Rectangle In bounds
    For As Integer = r.Top To r.Bottom
        For As Integer = r.Left To r.Right
            Console.SetCursorPosition(x, y)

Nerede bir Select deyimi tekrarlayan bloklarını gelmek içine oyun burada. Örneğin, algoritma için sol üst köşesinde durum denetler:

If x = r.Left Then
    If y = r.Top Then
        Select Case _Cells(x, y)
            Case FrameCellType.Empty
                _Cells(x, y) = FrameCellType.TopLeft
                Console.Write(TopLeft)
            Case FrameCellType.Horizontal
                _Cells(x, y) = FrameCellType.TeeTop
                Console.Write(TeeTop)
            Case FrameCellType.Vertical, FrameCellType.BottomLeft
                _Cells(x, y) = FrameCellType.TeeLeft
                Console.Write(TeeLeft)
            Case FrameCellType.TopRight
                _Cells(x, y) = FrameCellType.TeeTop
                Console.Write(TeeTop)
            Case FrameCellType.BottomRight, FrameCellType.TeeRight, FrameCellType.TeeBottom
                _Cells(x, y) = FrameCellType.Cross
                Console.Write(Cross)
        End Select

Ne zaman x = r.Left ve y = r.Top geçerli hücrenin sol üst köşesinde karakter olması gerekir. Bu yüzden geçerli hücre boşsa, TopLeft için sade bir şekilde ayarlanabilir. Hücreyi yatay karakter içeriyorsa, üst sol yatay birleştirmeyi Tee-üst karakter neden olur. Bu mantık, yazılması gereken karaktere göre mevcut karakter dönüştürme devam ediyor. Bunun gibi yedi blok daha vardır ama hepsi benzer mantık izleyin.

Algoritma ana çalışmalarını tamamladıktan sonra tüm kalan tek şey konsol renklerini geri yüklemek için:

                   ElseIf y = r.Bottom Then
                        Select Case _Cells(x, y)
                            Case FrameCellType.Empty
                                _Cells(x, y) = FrameCellType.Horizontal
                                Console.Write(Horizontal)
                            Case FrameCellType.Vertical, FrameCellType.TeeLeft, FrameCellType.TeeRight
                                _Cells(x, y) = FrameCellType.Cross
                                Console.Write(Cross)
                            Case FrameCellType.TopLeft, FrameCellType.TopRight
                                _Cells(x, y) = FrameCellType.TeeTop
                                Console.Write(TeeTop)
                            Case FrameCellType.BottomLeft, FrameCellType.BottomRight
                                _Cells(x, y) = FrameCellType.TeeBottom
                                Console.Write(TeeBottom)
                        End Select
                    End If
                End If
            Next
        Next
    Next
    Console.ForegroundColor = forecolorDelta
    Console.BackgroundColor = backcolorDelta
End Sub

Karakter çok yönlülük yararlanmak için biz de birkaç karakter kümesini kullanmak belirtmek için yardımcı yöntemler ekleyebilirsiniz:

Public Shared Sub SetCharacters(characters As String)
    If characters.Length = 11 Then
        _Characters = characters
    Else
        Throw New ArgumentException("Must supply exactly eleven characters.")
    End If
End Sub
   
Public Shared Sub SetDoubleBar()
    _Characters = "╚╝╬═╩╠╣╦╔╗║"
End Sub
   
Public Shared Sub SetSingleBar()
    _Characters = "└┘┼─┴├┤┬┌┐│"
End Sub

Örnek Program

FrameRenderer ile kullanıma hazır, çıkış aşağıdaki basit bir program ile ekran görüntüsünde oluşturabilirsiniz:

Module Module1
    Sub Main()
        NativeMethods.SetConsoleMode(NativeMethods.GetStdHandle(-11), 1)
        Console.BufferWidth = Console.WindowWidth
        Console.BufferHeight = Console.WindowHeight
        Console.CursorVisible = False
   
        Dim border As New Rectangle(0, 0, Console.WindowWidth, Console.WindowHeight)
        Dim title As New Rectangle(0, 0, Console.WindowWidth, 3)
        Dim command As New Rectangle(0, Console.WindowHeight - 3, Console.WindowWidth, 3)
        FrameRenderer.DrawFrame(border, title, command)
   
        Console.ReadKey()
    End Sub
End Module

Gördüğünüz gibi aslında konsolda bir kare çizmek için gittiğimizde behemoth algoritması yazma içine koymak iş kapalı öder. Ve daha karmaşık düzen, daha fazla ödeme.

Özet

Bir konsol uygulaması birbirine dikdörtgen pencere çerçevesi olarak kullanılmak ASCII karakterleri dışında bir dizi çekmek daha kolay olabilir. Dolaylı karakter harita etrafında alan bir algoritma tasarlayarak çok yönlülük çeşitli karakter kümesi için çerçeve çizim yaparken sağlamak mümkündür.

Bu makalede sunulan algoritma daha sofistike ve mantığı ile tek ve Çift Kişilik kare dikdörtgen (ASCII karakterler üzerinde haç var bunun için) birleştirmek için Genişletilmiş olmak için yeniden.

Ek A: tam kod örneği

Public NotInheritable Class FrameRenderer
  
    Public Shared ReadOnly Property BottomLeft As Char
        Get
            Return _Characters(0)
        End Get
    End Property
    Public Shared ReadOnly Property BottomRight As Char
        Get
            Return _Characters(1)
        End Get
    End Property
    Public Shared ReadOnly Property Cross As Char
        Get
            Return _Characters(2)
        End Get
    End Property
    Public Shared ReadOnly Property Horizontal As Char
        Get
            Return _Characters(3)
        End Get
    End Property
    Public Shared ReadOnly Property TeeBottom As Char
        Get
            Return _Characters(4)
        End Get
    End Property
    Public Shared ReadOnly Property TeeLeft As Char
        Get
            Return _Characters(5)
        End Get
    End Property
    Public Shared ReadOnly Property TeeRight As Char
        Get
            Return _Characters(6)
        End Get
    End Property
    Public Shared ReadOnly Property TeeTop As Char
        Get
            Return _Characters(7)
        End Get
    End Property
    Public Shared ReadOnly Property TopLeft As Char
        Get
            Return _Characters(8)
        End Get
    End Property
    Public Shared ReadOnly Property TopRight As Char
        Get
            Return _Characters(9)
        End Get
    End Property
    Public Shared ReadOnly Property Vertical As Char
        Get
            Return _Characters(10)
        End Get
    End Property
   
    Private Shared _Cells(,) As FrameCellType
    Private Shared _Characters() As Char "╚╝╬═╩╠╣╦╔╗║"
   
    Protected Sub New()
    End Sub
   
    Public Shared Sub DrawFrame(ParamArray bounds() As Rectangle)
        DrawFrame(Console.ForegroundColor, Console.BackgroundColor, bounds)
    End Sub
   
    Public Shared Sub DrawFrame(forecolor As ConsoleColor, ParamArray bounds() As Rectangle)
        DrawFrame(forecolor, Console.BackgroundColor, bounds)
    End Sub
   
    Public Shared Sub DrawFrame(forecolor As ConsoleColor, backcolor As ConsoleColor, ParamArray bounds() AsRectangle)
        Dim forecolorDelta As ConsoleColor = Console.ForegroundColor
        Dim backcolorDelta As ConsoleColor = Console.BackgroundColor
        Console.ForegroundColor = forecolor
        Console.BackgroundColor = backcolor
        ReDim _Cells(Console.WindowWidth - 1, Console.WindowHeight - 1)
        For Each As Rectangle In bounds
            For As Integer = r.Top To r.Bottom
                For As Integer = r.Left To r.Right
                    Console.SetCursorPosition(x, y)
                    If x = r.Left Then
                        If y = r.Top Then
                            Select Case _Cells(x, y)
                                Case FrameCellType.Empty
                                    _Cells(x, y) = FrameCellType.TopLeft
                                    Console.Write(TopLeft)
                                Case FrameCellType.Horizontal
                                    _Cells(x, y) = FrameCellType.TeeTop
                                    Console.Write(TeeTop)
                                Case FrameCellType.Vertical, FrameCellType.BottomLeft
                                    _Cells(x, y) = FrameCellType.TeeLeft
                                    Console.Write(TeeLeft)
                                Case FrameCellType.TopRight
                                    _Cells(x, y) = FrameCellType.TeeTop
                                    Console.Write(TeeTop)
                                Case FrameCellType.BottomRight, FrameCellType.TeeRight, FrameCellType.TeeBottom
                                    _Cells(x, y) = FrameCellType.Cross
                                    Console.Write(Cross)
                            End Select
                        ElseIf y = r.Bottom Then
                            Select Case _Cells(x, y)
                                Case FrameCellType.Empty
                                    _Cells(x, y) = FrameCellType.BottomLeft
                                    Console.Write(BottomLeft)
                                Case FrameCellType.Horizontal, FrameCellType.BottomRight
                                    _Cells(x, y) = FrameCellType.TeeBottom
                                    Console.Write(TeeBottom)
                                Case FrameCellType.Vertical, FrameCellType.TopLeft
                                    _Cells(x, y) = FrameCellType.TeeLeft
                                    Console.Write(TeeLeft)
                                Case FrameCellType.TopRight, FrameCellType.TeeRight, FrameCellType.TeeTop
                                    _Cells(x, y) = FrameCellType.Cross
                                    Console.Write(Cross)
                            End Select
                        Else
                            Select Case _Cells(x, y)
                                Case FrameCellType.Empty
                                    _Cells(x, y) = FrameCellType.Vertical
                                    Console.Write(Vertical)
                                Case FrameCellType.Horizontal, FrameCellType.TeeTop, FrameCellType.TeeBottom
                                    _Cells(x, y) = FrameCellType.Cross
                                    Console.Write(Cross)
                                Case FrameCellType.TopLeft, FrameCellType.BottomLeft
                                    _Cells(x, y) = FrameCellType.TeeLeft
                                    Console.Write(TeeLeft)
                                Case FrameCellType.TopRight, FrameCellType.BottomRight
                                    _Cells(x, y) = FrameCellType.TeeRight
                                    Console.Write(TeeRight)
                            End Select
                        End If
                    ElseIf x = r.Right Then
                        If y = r.Top Then
                            Select Case _Cells(x, y)
                                Case FrameCellType.Empty
                                    _Cells(x, y) = FrameCellType.TopRight
                                    Console.Write(TopRight)
                                Case FrameCellType.Horizontal
                                    _Cells(x, y) = FrameCellType.TeeTop
                                    Console.Write(TeeTop)
                                Case FrameCellType.Vertical, FrameCellType.BottomRight
                                    _Cells(x, y) = FrameCellType.TeeRight
                                    Console.Write(TeeRight)
                                Case FrameCellType.TopLeft
                                    _Cells(x, y) = FrameCellType.TeeTop
                                    Console.Write(TeeTop)
                                Case FrameCellType.BottomLeft, FrameCellType.TeeLeft, FrameCellType.TeeBottom
                                    _Cells(x, y) = FrameCellType.Cross
                                    Console.Write(Cross)
                            End Select
                        ElseIf y = r.Bottom Then
                            Select Case _Cells(x, y)
                                Case FrameCellType.Empty
                                    _Cells(x, y) = FrameCellType.BottomRight
                                    Console.Write(BottomRight)
                                Case FrameCellType.Horizontal, FrameCellType.BottomLeft
                                    _Cells(x, y) = FrameCellType.TeeBottom
                                    Console.Write(TeeBottom)
                                Case FrameCellType.Vertical, FrameCellType.TopRight
                                    _Cells(x, y) = FrameCellType.TeeRight
                                    Console.Write(TeeRight)
                                Case FrameCellType.TopLeft, FrameCellType.TeeLeft, FrameCellType.TeeTop
                                    _Cells(x, y) = FrameCellType.Cross
                                    Console.Write(Cross)
                            End Select
                        Else
                            Select Case _Cells(x, y)
                                Case FrameCellType.Empty
                                    _Cells(x, y) = FrameCellType.Vertical
                                    Console.Write(Vertical)
                                Case FrameCellType.Horizontal, FrameCellType.TeeTop, FrameCellType.TeeBottom
                                    _Cells(x, y) = FrameCellType.Cross
                                    Console.Write(Cross)
                                Case FrameCellType.TopLeft, FrameCellType.BottomLeft
                                    _Cells(x, y) = FrameCellType.TeeLeft
                                    Console.Write(TeeLeft)
                                Case FrameCellType.TopRight, FrameCellType.BottomRight
                                    _Cells(x, y) = FrameCellType.TeeRight
                                    Console.Write(TeeRight)
                            End Select
                        End If
                    Else
                        If y = r.Top Then
                            Select Case _Cells(x, y)
                                Case FrameCellType.Empty
                                    _Cells(x, y) = FrameCellType.Horizontal
                                    Console.Write(Horizontal)
                                Case FrameCellType.Vertical, FrameCellType.TeeLeft, FrameCellType.TeeRight
                                    _Cells(x, y) = FrameCellType.Cross
                                    Console.Write(Cross)
                                Case FrameCellType.TopLeft, FrameCellType.TopRight
                                    _Cells(x, y) = FrameCellType.TeeTop
                                    Console.Write(TeeTop)
                                Case FrameCellType.BottomLeft, FrameCellType.BottomRight
                                    _Cells(x, y) = FrameCellType.TeeBottom
                                    Console.Write(TeeBottom)
                            End Select
                        ElseIf y = r.Bottom Then
                            Select Case _Cells(x, y)
                                Case FrameCellType.Empty
                                    _Cells(x, y) = FrameCellType.Horizontal
                                    Console.Write(Horizontal)
                                Case FrameCellType.Vertical, FrameCellType.TeeLeft, FrameCellType.TeeRight
                                    _Cells(x, y) = FrameCellType.Cross
                                    Console.Write(Cross)
                                Case FrameCellType.TopLeft, FrameCellType.TopRight
                                    _Cells(x, y) = FrameCellType.TeeTop
                                    Console.Write(TeeTop)
                                Case FrameCellType.BottomLeft, FrameCellType.BottomRight
                                    _Cells(x, y) = FrameCellType.TeeBottom
                                    Console.Write(TeeBottom)
                            End Select
                        End If
                    End If
                Next
            Next
        Next
        Console.ForegroundColor = forecolorDelta
        Console.BackgroundColor = backcolorDelta
    End Sub
   
    Public Shared Sub SetCharacters(characters As String)
        If characters.Length = 11 Then
            _Characters = characters
        Else
            Throw New ArgumentException("Must supply exactly eleven characters.")
        End If
    End Sub
   
    Public Shared Sub SetDoubleBar()
        _Characters = "╚╝╬═╩╠╣╦╔╗║"
    End Sub
   
    Public Shared Sub SetSingleBar()
        _Characters = "└┘┼─┴├┤┬┌┐│"
    End Sub
End Class
   
Public Enum FrameCellType
    Empty
   
    Horizontal
    Vertical
   
    BottomLeft
    BottomRight
    TopLeft
    TopRight
   
    TeeBottom
    TeeLeft
    TeeRight
    TeeTop
   
    Cross
End Enum
   
Public Structure Rectangle
    Public Left As Integer
    Public Height As Integer
    Public Top As Integer
    Public Width As Integer
   
    Public Function Right() As Integer
        Return Left + Width - 1
    End Function
   
    Public Function Bottom() As Integer
        Return Top + Height - 1
    End Function
   
    Public Sub New(l As Integer, t As Integer, w As Integer, h As Integer)
        Left = l
        Top = t
        Width = w
        Height = h
    End Sub
End Structure



Diğer Diller

Visual Basic: How to Draw a Border of ASCII Text in a Console Application (en-US)