DOBON.NET DOBON.NETプログラミング掲示板過去ログ

DataGridViewの横スクロールバーについて

環境/言語:[WindowsXP VS.NET2005]
分類:[.NET]

いつもお世話になっています。

環境は:WindowsXP VS.NET2005

DataGridViewの横スクロールバーの移動量を設定できるでしょうか?

お願いします。
お疲れ様です。

DataGridViewのHorizontalScrollOffsetプロパティが使えそうです。
横スクロールバーの矢印ボタンの上にダミーのボタンを置いて、
そのボタンをクリックしたときにHorizontalScrollOffsetの値を加減すればOKでした。
長いコードになってしまいましたが試してみてください。


Public Class Form_DataGridViewScrollTest
    Inherits Form

    Dim DataGridView1 As New DataGridViewScrollTest

    Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)

        With Me.DataGridView1
            .Dock = DockStyle.Fill
            .RowCount = 10
            .ColumnCount = 5
            ' ↓矢印ボタン押下で横スクロールする量を設定する
            .HorizontalScrollAmount = 5
        End With
        Me.Controls.Add(Me.DataGridView1)

        MyBase.OnLoad(e)
    End Sub

End Class


''' <summary>
''' 横スクロール量設定機能付きDataGridView
''' </summary>
Public Class DataGridViewScrollTest
    Inherits DataGridView

    Dim WithEvents ArrowLeft As New ControlEx(ScrollButton.Left)
    Dim WithEvents ArrowRight As New ControlEx(ScrollButton.Right)

    Public Sub New()
        AddHandler Me.HorizontalScrollBar.SizeChanged, AddressOf Me.HorizontalScrollBar_SizeChanged
        Me._attachArrowButtonsToHorizontalScrollBar()
    End Sub

    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        Try
            If disposing Then
                RemoveHandler Me.HorizontalScrollBar.SizeChanged, AddressOf Me.HorizontalScrollBar_SizeChanged
                Me.ArrowRight.Dispose()
                Me.ArrowLeft.Dispose()
            End If
        Finally
            MyBase.Dispose(disposing)
        End Try
    End Sub


    Dim _horizontalScrolAmount As Integer = 3
    ''' <summary>
    ''' 矢印ボタン押下時の移動量
    ''' </summary>
    Public Property HorizontalScrollAmount() As Integer
        Get
            Return Me._horizontalScrolAmount
        End Get
        Set(ByVal value As Integer)
            Me._horizontalScrolAmount = Math.Max(value, 0)
        End Set
    End Property

    ''' <summary>
    ''' 矢印ボタンを横スクロールバーに配置します
    ''' </summary>
    Private Sub _attachArrowButtonsToHorizontalScrollBar()
        Me._setArrowButtonBoundsCore()

        Me.HorizontalScrollBar.Controls.Add(Me.ArrowLeft)
        Me.HorizontalScrollBar.Controls.Add(Me.ArrowRight)
    End Sub


    ''' <summary>
    ''' 横スクロールバーのサイズ変更にあわせてボタンを移動
    ''' </summary>
    Private Sub HorizontalScrollBar_SizeChanged(ByVal sender As Object, ByVal e As EventArgs)
        Me._setArrowButtonBoundsCore()
    End Sub

    Private Sub _setArrowButtonBoundsCore()
        Dim arrowsize As New Size(SystemInformation.HorizontalScrollBarArrowWidth, _
                                  SystemInformation.HorizontalScrollBarHeight)
        Me.ArrowLeft.Location = New Point(0, 0)
        Me.ArrowLeft.Size = arrowsize
        Me.ArrowRight.Location = New Point(Me.HorizontalScrollBar.ClientSize.Width - arrowsize.Width, 0)
        Me.ArrowRight.Size = arrowsize
    End Sub


    ''' <summary>
    ''' 矢印ボタンClickで横スクロールします
    ''' </summary>
    Private Sub Arrow_ScrollNeeded(ByVal sender As Object, ByVal e As System.EventArgs) _
        Handles ArrowLeft.ScrollNeeded, ArrowRight.ScrollNeeded
        Select Case DirectCast(sender, ControlEx)._direction
            Case ScrollButton.Left
                Dim newvalue As Integer = Me.HorizontalScrollingOffset - Me.HorizontalScrollAmount
                Me.HorizontalScrollingOffset = Math.Max(newvalue, 0) ' 負の値は不可
            Case ScrollButton.Right
                Me.HorizontalScrollingOffset += Me.HorizontalScrollAmount
        End Select
    End Sub


    ''' <summary>
    ''' ScrollBarの矢印ボタンの上に配置する矢印ボタン
    ''' </summary>
    Private Class ControlEx
        Inherits Control

        Public Event ScrollNeeded As EventHandler

        Protected Overridable Sub OnScrollNeeded(ByVal e As EventArgs)
            RaiseEvent ScrollNeeded(Me, e)
        End Sub

        Public ReadOnly _direction As ScrollButton
        Dim _buttonState As VisualStyles.ScrollBarArrowButtonState
        ' 矢印ボタン連続押下時のリピート動作を再現するためのTimer
        Dim WithEvents Timer1 As New Timer

        Public Sub New(ByVal direction As ScrollButton)
            Me._direction = direction
            Me._setButtonStateNormalCore()
        End Sub

        Protected Overrides Sub Dispose(ByVal disposing As Boolean)
            Try
                If disposing Then
                    Me.Timer1.Stop()
                    Me.Timer1.Dispose()
                End If
            Finally
                MyBase.Dispose(disposing)
            End Try
        End Sub

        Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
            ScrollBarRenderer.DrawArrowButton(e.Graphics, Me.ClientRectangle, Me._buttonState)
            MyBase.OnPaint(e)
        End Sub

        Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs)
            Me._setButtonStatePressedCore()
            Me.OnScrollNeeded(EventArgs.Empty)
            Me.Timer1.Interval = 400 ' 矢印ボタン連続押下時のリピート開始待ち(ms)
            Me.Timer1.Start()
            MyBase.OnMouseDown(e)
        End Sub

        Protected Overrides Sub OnMouseUp(ByVal e As System.Windows.Forms.MouseEventArgs)
            Me._setButtonStateNormalCore()
            Me.Timer1.Stop()
            MyBase.OnMouseUp(e)
        End Sub

        Private Sub _setButtonStateNormalCore()
            Select Case Me._direction
                Case ScrollButton.Left
                    Me._buttonState = VisualStyles.ScrollBarArrowButtonState.LeftNormal
                Case ScrollButton.Right
                    Me._buttonState = VisualStyles.ScrollBarArrowButtonState.RightNormal
            End Select
            Me.Invalidate()
        End Sub

        Private Sub _setButtonStatePressedCore()
            Select Case Me._direction
                Case ScrollButton.Left
                    Me._buttonState = VisualStyles.ScrollBarArrowButtonState.LeftPressed
                Case ScrollButton.Right
                    Me._buttonState = VisualStyles.ScrollBarArrowButtonState.RightPressed
            End Select
            Me.Invalidate()
        End Sub

        Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Timer1.Tick
            Me.Timer1.Interval = 50 ' 矢印ボタン連続押下時のリピート間隔(ms)
            Me.OnScrollNeeded(EventArgs.Empty)
        End Sub
    End Class

End Class
■No26087に返信(H.K.R.さんの記事)

H.K.R.さん、丁寧なアドバイス、なんとテストソースまで書いていただいて
まことに感謝いたします。

> 横スクロールバーの矢印ボタンの上にダミーのボタンを置いて、
なるほど、そんな手がありましたね。

以前私の調べによってHorizontalScrollOffsetを使用することを考えたが、
でもその元々付いていた矢印ボタンのイベントを拾うことに悩んでいました。
そのこで、ダミーのボタンを作っとけば、完璧ですね。

試してみたところ、うまくできました。
ありがとうございます!!!

またよろしくお願いいたします。
解決済み!
お疲れ様です。

解決済みのところお邪魔しますが、以下の2点を修正しましたので、
矢印ボタンクラスのコード修正版を掲載します。
(修正箇所)
・矢印ボタン内にマウスカーソルを移動した場合の動作
・矢印ボタン押下のままマウスカーソルを矢印ボタンの外に移動した場合の動作

    ''' <summary>
    ''' ScrollBarの矢印ボタンの上に配置する矢印ボタン
    ''' </summary>
    Private Class ControlEx
        Inherits Control

        Public Event ScrollNeeded As EventHandler

        Protected Overridable Sub OnScrollNeeded(ByVal e As EventArgs)
            RaiseEvent ScrollNeeded(Me, e)
        End Sub

        Public ReadOnly _direction As ScrollButton
        Dim _buttonState As VisualStyles.ScrollBarArrowButtonState
        ' 矢印ボタン連続押下時のリピート動作を再現するためのTimer
        Dim WithEvents Timer1 As New Timer

        Public Sub New(ByVal direction As ScrollButton)
            Me._direction = direction
            Me._setButtonStateNormalCore()
        End Sub

        Protected Overrides Sub Dispose(ByVal disposing As Boolean)
            Try
                If disposing Then
                    Me.Timer1.Stop()
                    Me.Timer1.Dispose()
                End If
            Finally
                MyBase.Dispose(disposing)
            End Try
        End Sub

        Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
            ScrollBarRenderer.DrawArrowButton(e.Graphics, Me.ClientRectangle, Me._buttonState)
            MyBase.OnPaint(e)
        End Sub

        Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs)
            Me._setButtonStatePressedCore()
            Me.OnScrollNeeded(EventArgs.Empty)
            Me.Timer1.Interval = 400 ' 矢印ボタン連続押下時のリピート開始待ち(ms)
            Me.Timer1.Start()
            MyBase.OnMouseDown(e)
        End Sub

        Protected Overrides Sub OnMouseEnter(ByVal e As System.EventArgs)
            Me._setButtonStateHotCore()
            MyBase.OnMouseEnter(e)
        End Sub

        Protected Overrides Sub OnMouseLeave(ByVal e As System.EventArgs)
            Me._setButtonStateNormalCore()
            MyBase.OnMouseLeave(e)
        End Sub

        Protected Overrides Sub OnMouseUp(ByVal e As System.Windows.Forms.MouseEventArgs)
            Me._stopScrollCore()
            MyBase.OnMouseUp(e)
        End Sub

        Protected Overrides Sub OnMouseMove(ByVal e As System.Windows.Forms.MouseEventArgs)
            If Me.Timer1.Enabled AndAlso Me.ClientRectangle.Contains(e.X, e.Y) = False Then
                Me._stopScrollCore()
            End If
            MyBase.OnMouseMove(e)
        End Sub

        Private Sub _stopScrollCore()
            Me.Timer1.Stop()
            Me._setButtonStateNormalCore()
        End Sub

        Private Sub _setButtonStateHotCore()
            Select Case Me._direction
                Case ScrollButton.Left
                    Me._buttonState = VisualStyles.ScrollBarArrowButtonState.LeftHot
                Case ScrollButton.Right
                    Me._buttonState = VisualStyles.ScrollBarArrowButtonState.RightHot
            End Select
            Me.Invalidate()
        End Sub

        Private Sub _setButtonStateNormalCore()
            Select Case Me._direction
                Case ScrollButton.Left
                    Me._buttonState = VisualStyles.ScrollBarArrowButtonState.LeftNormal
                Case ScrollButton.Right
                    Me._buttonState = VisualStyles.ScrollBarArrowButtonState.RightNormal
            End Select
            Me.Invalidate()
        End Sub

        Private Sub _setButtonStatePressedCore()
            Select Case Me._direction
                Case ScrollButton.Left
                    Me._buttonState = VisualStyles.ScrollBarArrowButtonState.LeftPressed
                Case ScrollButton.Right
                    Me._buttonState = VisualStyles.ScrollBarArrowButtonState.RightPressed
            End Select
            Me.Invalidate()
        End Sub

        Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Timer1.Tick
            Me.Timer1.Interval = 50 ' 矢印ボタン連続押下時のリピート間隔(ms)
            Me.OnScrollNeeded(EventArgs.Empty)
        End Sub
    End Class
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板