RunningCSharp

C#メインの開発者による、雑多な開発記事。記事は個人の見解であり、所属組織を代表するものてはありません。

VB(.net) Windows10 WinForms ComboBox(DrowDownStyle = DropDownList , FlatStyle=Standard)の背景色を白くする

掲題の条件下では、コンボボックスの背景色は灰色となります。

f:id:ys-soniclab:20190407194806p:plain

f:id:ys-soniclab:20190407194842p:plain

下記手順で、コンボボックスの背景色を白くできます。

①DrawModeを、「OwnerDrawFixed」に変更

f:id:ys-soniclab:20190407194927p:plain

②下記例のように、ComboBoxのDrawItemイベントへ関連付けたメソッドに処理を追加する

    Private Sub combobox1_DrawItem(sender As Object, e As DrawItemEventArgs) Handles ComboBox1.DrawItem
        If e.Index >= 0 Then
            e.DrawBackground()
            e.Graphics.DrawString(ComboBox1.Items(e.Index).ToString(), e.Font, Brushes.Black, e.Bounds, StringFormat.GenericDefault)
            e.DrawFocusRectangle()
        End If
    End Sub

上記対応を行うと、コンボボックスが下記のようになる。

f:id:ys-soniclab:20190407194948p:plain

f:id:ys-soniclab:20190407195010p:plain

オブジェクト指向(言語ではない)の簡単な説明

~~~ 本記事は、「オブジェクト指向の考え方は、普段の人間の認識と近いと感じた」ということを言いたいだけの、緩い記事です。 オブジェクト指向言語特有の機能を主軸とした話ではありません。 ~~~

オブジェクトとは、「物」です。 「物」は、状態を示す「データ」と、能動的または受動的に行われる「振る舞い」の塊と捉えることが出来ます。

例えば、無〇良品あたりのリングノートであれば 「ページ数」「各ページの記載内容」「紙を纏めるリングの数」等といった「データ」と、 「ノートを持つ」「ノートに文字を書く」「ノートの文字を消す」「ノートのページを剥がす」など、物に関連する「振る舞い」があります。

上記のように、「データ」と「振る舞い」の塊である「物」には、「役割」を与えられます。

リングノートであれば「会議用のメモ帳」、「子供のお絵描き帳」、「家計簿」などの役割を与えられます。

ただし、場合によっては「扇子の代わり」、「チリ紙」、「(丸めて)メガホンにする」「背中に入れてコルセット代わり」といった役割を担わされる場合もあります。

「リングノート」を見て、「これ、メモ帳かな」と思うことはあっても、「これ、チリ紙だな」とは思わない事でしょう。 しかし、物に対し本来の「役割」と異なる使い方をしてしまう事も、稀にあります。本記事では、これを「誤用」と呼びます。

多くの人は、「リングノート = 開いて文字を書き、記録を行うもの」という「文脈」を読み取る事で、何の説明を受けずとも、本来の「役割」通りにリングノートを扱っている事と思います。

さて、今度はソフトウェアにおける例を見てみましょう。

例えば、単純にDB接続を行うオブジェクトを作ろうと思った場合、 「接続先サーバー」「接続先DB」「データ操作SQL」「接続状態」などのデータと、 「DB接続」「セッション確立」「データ操作」「コミット」「ロールバック」「DB切断」などの振る舞いを作ることでしょう。

上記のオブジェクトは、当然「データ接続を行うもの」であることが明白であるため、それ以外の何かとして「誤用」される可能性は必然的に低くなります。

「誤用」が減る理由の一つに、「DB接続オブジェクトはDB接続に使うもの」という「文脈」が生まれる事によるものが考えられます。

ごくごく当たり前の話なのですが、上記の「文脈」による「誤用」の抑制は、オブジェクト指向を用いるメリットとして大きいかと感じ、書かせて頂きました。

〜〜〜 最後に、ちょっとオブジェクト指向言語の話をしてしまいます。

これまでの構造化言語でも、ファイル単位やスコープ、構造体を用いたデータ集約などを用いて、データと振る舞いの関係性を整理していくことは可能です。

しかしながら、作り手のポリシー差異や作成期間の問題で、データと振る舞いが正しい関係性が保てなくなってしまうことが、少なくはなかったと思います。

オブジェクト指向言語は、データと振る舞いをより簡単に整理することが出来るため、データと振る舞いの関係性を保ちやすくなっております。(もちろん、絶対「誤用」はない、と保証するものではありませんが。)

更に、他の記事ではたくさん取り上げられております 、継承、多態、包含、カプセル化などの特徴で、再利用性と利便性を向上など、さらなるメリットが提供されております。

VBA UTF-8のテキストファイルをソートして出力する

任意のテキストファイル(UTF-8)の内容を行単位で昇順ソートし、元のファイルに書き戻すコード例。

Public Sub SortText()

    Dim strarr() As String
    Dim strall As String
    'ファイル名、任意の内容を指定
    Dim filename As String: filename = "filepath(ex:C:\test\testflie.txt)"
    Dim strsave As Variant
    
    'ファイル読み込み(UTF-8はADODB.Streamを使うほかなさそう)
    Dim adodb As Object: Set adodb = CreateObject("ADODB.Stream")
    adodb.Charset = "UTF-8"
    adodb.Open
    adodb.LoadFromFile filename
    strall = adodb.ReadText
    adodb.Close
    
    '以下は対象ファイルの改行がLFの例。CRLFの場合はvbCrLfを使用する。
    strarr = Split(strall, vbLf)
    'ソート
    SortArray strarr
    '保存
    adodb.Open
    For Each strsave In strarr
        adodb.WriteText strsave & vbLf, 0
    Next
    adodb.SaveToFile filename, 2
    adodb.Close

End Sub
'配列引数arrのソートを実施
Private Sub SortArray(ByRef arr() As String)
    Dim arrCount As Integer
    Dim sortCount As Integer
    Dim strBuf As String
    
    For arrCount = 0 To UBound(arr)
        For sortCount = arrCount + 1 To UBound(arr)
            If arr(arrCount) > arr(sortCount) Then
            strBuf = arr(arrCount)
            arr(arrCount) = arr(sortCount)
            arr(sortCount) = strBuf
            End If
        Next sortCount
    Next arrCount
End Sub

下記のようなファイルを指定し実行すると、

c
d
f
3
1
ぬ
5
@

下記のようにソートされる。

@
1
3
5
c
d
f
ぬ

PowerShell テキストファイルをソートして出力する

同フォルダのUTF-8のテキストファイル「output.txt」の内容を行単位で文字コード昇順でソートし、「output2.txt」に出力する例

Get-Content -Encoding UTF8 -Path "./output.txt" | Sort-Object | Set-Content  -Encoding UTF8 "./output2.txt" 

降順だと以下の通り。

Get-Content -Encoding UTF8 -Path "./output.txt" | Sort-Object -Descending | Set-Content  -Encoding UTF8 "./output2.txt" 

上記ソートのPowerShellコマンドをコマンドプロンプトから実施させる場合、以下のようにbatファイルを作成。(昇順の例)

test.bat

powershell -Command "Get-Content -Encoding UTF8 -Path './output.txt' | Sort-Object | Set-Content  -Encoding UTF8 './output2.txt'" 

「output.txt」に下記のような内容を格納し実行すると、

c
d
f
3
1
ぬ
5
@

「output2.txt」は下記のように出力される。

@
1
3
5
c
d
f
ぬ

VB(.net) Windows10 WinForms・DataGridViewのColumnHeaderのソートを示す三角だけ操作する

記のようなコードを実行した際、右側のカラムをクリックした際、ソートはされないがソートを示す三角形が「昇順→降順→ソートなし」の順に変化する。

コード

Imports System.ComponentModel

Public Class Form1
    'ソートの状態を保存する変数
    Dim sordOrder As SortOrder = SortOrder.None

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        '以下はDataGridViewのデータ表示用コード
        Dim table As DataTable = New DataTable()

        table.Columns.Add("col1")
        table.Columns.Add("col2")
        table.Rows.Add({1, 1})
        table.Rows.Add({2, 2})
        table.Rows.Add({4, 4})
        table.Rows.Add({3, 3})
        DataGridView1.DataSource = table

        '自動ソートを停止
        DataGridView1.Columns.Item(1).SortMode = DataGridViewColumnSortMode.Programmatic

    End Sub

    Private Sub DataGridView1_ColumnHeaderMouseClick(sender As Object, e As DataGridViewCellMouseEventArgs) Handles DataGridView1.ColumnHeaderMouseClick
        '右側のカラムでのみ、「ソートなし」処理を実装
        If e.ColumnIndex = 1 Then
            Dim vc As DataGridViewColumn = DataGridView1.Columns.Item(e.ColumnIndex)
            'すでにソート中であれば、次のソート状態を保持
            sordOrder = GetNextOrder(sordOrder)

            '※データの独自ソートを行いたい場合は、ここでデータのソートを実施


            'カラムヘッダーの矢印を現在のソート状態に合わせる
            vc.HeaderCell.SortGlyphDirection = sordOrder

        End If

    End Sub

    'ソート順を受け取り、次のソート順を返す
    Private Function GetNextOrder(sortOrder As SortOrder) As SortOrder
        Dim rtn As SortOrder
        Select Case sortOrder
            Case SortOrder.Ascending
                rtn = SortOrder.Descending
            Case SortOrder.Descending
                rtn = SortOrder.None
            Case SortOrder.None
                rtn = SortOrder.Ascending
        End Select
        Return rtn
    End Function

End Class

f:id:ys-soniclab:20190119215201p:plain
クリック一回目

f:id:ys-soniclab:20190119215217p:plain
クリック二回目

f:id:ys-soniclab:20190119215232p:plain
クリック三回目

VB(.net) Windows10 WinForms・DataGridViewのカラムクリック時、「昇順→降順→ソートなし」の順となるようカスタム

デフォルトのDataGridViewはカラムをクリックすると、「昇順→降順」の順にソートされる。 この挙動を、「昇順→降順→ソートなし」となるようカスタムする。 下記例では、右側のカラムのみカスタムが実装される。

Imports System.ComponentModel

Public Class Form1
    'ソートの状態を保存する変数
    Dim sordOrder As SortOrder = SortOrder.None

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        '以下はDataGridViewのデータ表示用コード
        Dim table As DataTable = New DataTable()

        table.Columns.Add("col1")
        table.Columns.Add("col2")
        table.Rows.Add({1, 1})
        table.Rows.Add({2, 2})
        table.Rows.Add({4, 4})
        table.Rows.Add({3, 3})
        DataGridView1.DataSource = table

    End Sub

    Private Sub DataGridView1_ColumnHeaderMouseClick(sender As Object, e As DataGridViewCellMouseEventArgs) Handles DataGridView1.ColumnHeaderMouseClick
        '右側のカラムでのみ、「ソートなし」処理を実装
        If e.ColumnIndex = 1 Then
            Dim vc As DataGridViewColumn = DataGridView1.Columns.Item(e.ColumnIndex)
            'すでにソート中であれば、次のソート状態を保持
            sordOrder = GetNextOrder(sordOrder)

            If sordOrder = SortOrder.None Then
                'ソート状態をリセット
                DataGridView1.DataSource.DefaultView.Sort = String.Empty
            Else
                'ソートを実行
                DataGridView1.Sort(vc, IIf(sordOrder = SortOrder.Ascending, ListSortDirection.Ascending, ListSortDirection.Descending))
            End If

        End If

    End Sub

    'ソート順を受け取り、次のソート順を返す
    Private Function GetNextOrder(sortOrder As SortOrder) As SortOrder
        Dim rtn As SortOrder
        Select Case sortOrder
            Case SortOrder.Ascending
                rtn = SortOrder.Descending
            Case SortOrder.Descending
                rtn = SortOrder.None
            Case SortOrder.None
                rtn = SortOrder.Ascending
        End Select
        Return rtn
    End Function

End Class

f:id:ys-soniclab:20190119214313p:plain
クリック一回目

f:id:ys-soniclab:20190119214333p:plain
クリック二回目

f:id:ys-soniclab:20190119214349p:plain
クリック三回目

VB(.net) Windows10 WinForms・DataGridViewのColumnHeaderのソートを示す三角が見えなくなる

下記のようなコードを実行した際、右側のカラムにて、ColumnHeaderのソート順を示す三角形が表示されなくなる。

コード

Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        DataGridView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing
        DataGridView1.ColumnHeadersHeight = 20

        DataGridView1.Columns.Add("col1", "1")
        DataGridView1.Columns.Add("col2", "2222222222")
        DataGridView1.Rows.Add({1, 3})
        DataGridView1.Rows.Add({2, 4})

       DataGridView1.Columns().Item(1).Width = 110

    End Sub
End Class

実行結果

f:id:ys-soniclab:20190103185521p:plain
左側カラムでソート実施

f:id:ys-soniclab:20190103185545p:plain
右側カラムでソート実施

2枚目のスクリーンショットでは、右側のカラムでソートを実施しているが、ヘッダーに三角形が表示されない。 本問題は、文字がカラムいっぱいに広がることで、ソートを示す三角形が消えてしまうことで発生する。 カラムを広げる調整を行うことで、問題を回避できる。

コード

Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        DataGridView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing
        DataGridView1.ColumnHeadersHeight = 20

        DataGridView1.Columns.Add("col1", "1")
        DataGridView1.Columns.Add("col2", "2222222222")
        DataGridView1.Rows.Add({1, 3})
        DataGridView1.Rows.Add({2, 4})

        '以下を追加
        DataGridView1.Columns().Item(1).Width = 110

    End Sub
End Class

実行結果

f:id:ys-soniclab:20190103190025p:plain
コード変更後