AutoScroll - лишняя полоса прокрутки

Язык Visual Basic на платформе .NET.

Модераторы: Ramzes, Sebas

Qwertiy
Доктор VB наук
Доктор VB наук
 
Сообщения: 2753
Зарегистрирован: 26.06.2011 (Вс) 21:26

AutoScroll - лишняя полоса прокрутки

Сообщение Qwertiy » 13.03.2012 (Вт) 2:08

Почему при 10м элементе появляется горизонтальная полоса прокрутки и как от неё избавиться? Мне нужна только вертикальная.
Пытался задавать HScroll, HorizontalScroll.Visible и даже CreateParams - не помогло :(

Код: Выделить всё
Public Class TestControl
Inherits Panel

Dim Pnl As New FlowLayoutPanel() With {.AutoSize = True, .AutoSizeMode = Windows.Forms.AutoSizeMode.GrowAndShrink, .Margin = New Padding(0), .Padding = New Padding(0)}
Dim WithEvents BtnNew As New Button() With {.Text = "+", .ForeColor = Color.Blue, .Visible = True}

Public Sub New()
  With Me
    .BackgroundImageLayout = ImageLayout.Zoom
    .AutoScroll = True
    .Location = New Point(4, 4)
    .Size = New Size(460, 323)
    .MinimumSize = New Size(460, 323)
    .MaximumSize = New Size(460, 323)
    AddHandler BtnNew.SizeChanged, Sub() If BtnNew.Height Then BtnNew.Font = New Font(BtnNew.Font.Name, BtnNew.Height >> 2)
    .Controls.Add(Pnl)
    Pnl.Controls.Add(BtnNew)
    SetSizes()
  End With
End Sub

Private Sub SetSizes()
  Dim Width As Integer = (Me.ClientSize.Width - 20) \ 3, Height As Integer = (Me.ClientSize.Height - 20) \ 3
  Pnl.Width = Me.ClientSize.Width - 2
  Pnl.MaximumSize = New Size(Me.ClientSize.Width - 2, Integer.MaxValue)

  For Each Ctrl As Control In Pnl.Controls
    With Ctrl
      .Width = Width
      .Height = Height
    End With
  Next Ctrl
End Sub

Protected Overrides Sub OnClientSizeChanged(ByVal e As System.EventArgs)
  SetSizes()
  MyBase.OnClientSizeChanged(e)
End Sub

Private Sub BtnNew_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles BtnNew.Click
  Pnl.Controls.Add(New CheckBox() With {.Size = BtnNew.Size, .Appearance = Windows.Forms.Appearance.Button})
End Sub

End Class
Код: Выделить всё
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
  Me.Controls.Add(New TestControl())
End Sub

Admiralisimys
Постоялец
Постоялец
 
Сообщения: 318
Зарегистрирован: 01.06.2009 (Пн) 10:26

Re: AutoScroll - лишняя полоса прокрутки

Сообщение Admiralisimys » 13.03.2012 (Вт) 16:14

Qwertiy возможно потому что она нужна.
AutoScroll весьма чувствителен к чёткости вместимости элементов.
У меня
Код: Выделить всё
Imports System
Imports System.Drawing
Imports System.Windows.Forms

Public Class TestControl
    Inherits Panel

    Private Pnl As New FlowLayoutPanel() With {.AutoSize = True, .AutoSizeMode = Windows.Forms.AutoSizeMode.GrowAndShrink, .Margin = New Padding(0), .Padding = New Padding(0)}
    Private WithEvents BtnNew As New Button() With {.Text = "+", .ForeColor = Color.Blue, .Visible = True}

    Public Sub New()
        With Me
            .BackgroundImageLayout = ImageLayout.Zoom
            .AutoScroll = True
            .Location = New Point(4, 4)
            .Size = New Size(460, 323)
            .MinimumSize = New Size(460, 323)
            .MaximumSize = New Size(460, 323)
#If VBC_VER > 9 Then
            AddHandler BtnNew.SizeChanged, Sub() If BtnNew.Height Then BtnNew.Font = New Font(BtnNew.Font.Name, BtnNew.Height >> 2)
#Else
            AddHandler BtnNew.SizeChanged, AddressOf OnButtonSizeChanged
#End If
            .Controls.Add(Pnl)
            Pnl.Controls.Add(BtnNew)
            SetSizes()

            'AddHandler Pnl.ControlAdded, AddressOf OnControllAdded

        End With
    End Sub

    'Private Sub OnControllAdded(ByVal obj As Object, ByVal cea As ControlEventArgs)

    '    Dim pnl = DirectCast(obj, Panel)
    '    If pnl Is Nothing Then Return

    '    Dim iCur As Integer = 0
    '    Dim iSumm As Integer = 0
    '    For Each ctr As Control In pnl.Controls
    '        If ctr.Bottom > iCur Then
    '            iCur = ctr.Bottom
    '            iSumm += iCur
    '        End If
    '    Next ctr

    '    If iSumm > pnl.Height Then
    '        pnl.VerticalScroll.Visible = True
    '    End If

    'End Sub


#If VBC_VER <= 9 Then
    Private Sub OnButtonSizeChanged(ByVal obj As Object, ByVal ea As EventArgs)
        If BtnNew.Height Then BtnNew.Font = New Font(BtnNew.Font.Name, BtnNew.Height >> 2)
    End Sub
#End If

    Private Sub SetSizes()
        Dim Width As Integer = (Me.ClientSize.Width - 20) \ 3, Height As Integer = (Me.ClientSize.Height - 20) \ 3
        Pnl.Width = Me.ClientSize.Width - 2
        Pnl.MaximumSize = New Size(Me.ClientSize.Width - 2, Integer.MaxValue)

        For Each Ctrl As Control In Pnl.Controls
            With Ctrl
                .Width = Width
                .Height = Height
            End With
        Next Ctrl
    End Sub

    Protected Overrides Sub OnClientSizeChanged(ByVal e As System.EventArgs)
        SetSizes()
        MyBase.OnClientSizeChanged(e)
    End Sub

    Private Sub BtnNew_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles BtnNew.Click
        Pnl.Controls.Add(New CheckBox() With {.Size = BtnNew.Size, .Appearance = Windows.Forms.Appearance.Button})
    End Sub
End Class

Class TestTheTestControl
    Inherits Form

    <STAThread()> Shared Sub Main()
        Application.EnableVisualStyles()
        Application.Run(New TestTheTestControl())
    End Sub

    Protected Overrides Sub OnLoad(ByVal ea As EventArgs)
        Me.Controls.Add(New TestControl())
        'MyBase.OnLoad(ea)
    End Sub

End Class

она появляется сразу перед появлением вертикальной полосы прокрутки и тут же исчезает, при последующем добавлении кнопки.

Есть несколько вариантов.

Ну во первых, наследование и размещение. Если нужен функционал одной из панелей нужно от нее и наследоваться. Допустим от FlowLayoutPanel, и тут же в нём размещать элементы, а не в наследованном разместить панель, в которую добавляем элементы.
Однако к скролингу это напрямую не относится. Что бы обуздать последний, нужно разобраться как работает AutoScroll и найти связанные события. Практические все события ScrollableControl наследуются от Control, а новое Scroll к AutoScroll не относится.

Возьмём к примеру ControllAdded и в нём проверяем доступность появления вертикального скроллинга (см. закомментированное в коде выше).
AutoScrool в этом случаи должен быть False, но в таком случаи обслуживание событий скроллинга ложится на наши плечи.

Ещё как вариант поиграться размерами элементов и панели, дабы горизонтальному скроллингу ну никак не было необходимости появляться.

Qwertiy
Доктор VB наук
Доктор VB наук
 
Сообщения: 2753
Зарегистрирован: 26.06.2011 (Вс) 21:26

Сообщение Qwertiy » 13.03.2012 (Вт) 17:23

Admiralisimys писал(а):Qwertiy возможно потому что она нужна.

У меня в этом проекте уже 3 способа получить контрол:
1. UserControl, на котором размещена FlowLayoutPanel с кнопкой;
2. Аналогичный код с наследованием от UserControl (без использования дизайнера);
3. Тестовый вариант, который я тут привёл.
Все работают одинаково. Пробовал выделять FlowLayoutPanel красным фоном и сужать до двух кнопок в ряду, писал перебор всех контролов с проверкой If Ctrl.Right > Pnl.ClientSize.Width Then... Ничто не показывает, что прокрутка там нужна. Тем не менее, она есть.

Ещё, в другом проекте есть подобный контрол с наследованием от TabPage (собственно, его и брал за основу), там подобных проблем не возникало.

Admiralisimys писал(а):она появляется сразу перед появлением вертикальной полосы прокрутки и тут же исчезает, при последующем добавлении кнопки.

Не понял.

Admiralisimys
Постоялец
Постоялец
 
Сообщения: 318
Зарегистрирован: 01.06.2009 (Пн) 10:26

Re:

Сообщение Admiralisimys » 13.03.2012 (Вт) 17:51

К примеру, поигравшись с размерами элементов управления
Код: Выделить всё
Imports System
Imports System.Drawing
Imports System.Windows.Forms

Class TestControl
    Inherits FlowLayoutPanel

    Public Sub New()
        BackgroundImageLayout = ImageLayout.Zoom
        AutoScroll = True
        Location = New Point(4, 4)
        Size = New Size(460, 323)
        MinimumSize = New Size(460, 323)
        MaximumSize = New Size(460, 323)

        Dim BtnNew As New Button()
        BtnNew.Text = "+"
        BtnNew.ForeColor = Color.Blue
        BtnNew.Width = 20 * Font.Height
        BtnNew.Height = 10 * Font.Height
        AddHandler BtnNew.Click, AddressOf BtnNew_Click

        Controls.Add(BtnNew)
    End Sub

    Private Sub BtnNew_Click(ByVal obj As Object, ByVal ea As EventArgs)
        Controls.Add(New CheckBox() With {.Size = DirectCast(obj, Button).Size, .Appearance = Windows.Forms.Appearance.Button})
    End Sub
End Class

Class TestTheTestControl
    Inherits Form

    <STAThread()> Shared Sub Main()
        Application.EnableVisualStyles()
        Application.Run(New TestTheTestControl())
    End Sub

    Protected Overrides Sub OnLoad(ByVal ea As EventArgs)
        Me.Controls.Add(New TestControl())
    End Sub
End Class

Горизонтальный скролл так и не появился. Кстати, раз уж не пользоваться дизайнером/мастером форм, тогда от абсолютных координат стоит уходить, используя тот же размер шрифта, что в коде выше с константными множителями.

Qwertiy писал(а):
Admiralisimys писал(а):она появляется сразу перед появлением вертикальной полосы прокрутки и тут же исчезает, при последующем добавлении кнопки.

Не понял.


Скрин ”видео”
TestControl_AutoScroll.gif
(227.04 Кб) Скачиваний: 179
и скриншот
LastFrame.png
по форме основанного на коде из второго поста.

Qwertiy
Доктор VB наук
Доктор VB наук
 
Сообщения: 2753
Зарегистрирован: 26.06.2011 (Вс) 21:26

Сообщение Qwertiy » 13.03.2012 (Вт) 19:58

Admiralisimys писал(а):она появляется сразу перед появлением вертикальной полосы прокрутки и тут же исчезает, при последующем добавлении кнопки.

Действительно, пропадает после добавления 11го элемента. А ещё, после 11го элемента пропадает низ :(
А где низ.png

Если написать
Код: Выделить всё
Public Class TestControl2
Inherits FlowLayoutPanel

Dim WithEvents BtnNew As New Button() With {.Text = "+", .ForeColor = Color.Blue, .Visible = True}

Public Sub New()
  With Me
    .BackgroundImageLayout = ImageLayout.Zoom
    .AutoScroll = True
    .Location = New Point(4, 4)
    .MinimumSize = New Size(460, 323)
    .MaximumSize = New Size(460, 323)
    AddHandler BtnNew.SizeChanged, Sub() If BtnNew.Height Then BtnNew.Font = New Font(BtnNew.Font.Name, BtnNew.Height >> 2)
    .Controls.Add(BtnNew)
    SetSizes()
  End With
End Sub

Private Sub SetSizes()
  Dim Width As Integer = (Me.ClientSize.Width - 20) \ 3, Height As Integer = (Me.ClientSize.Height - 20) \ 3

  For Each Ctrl As Control In Me.Controls
    With Ctrl
      .Width = Width
      .Height = Height
    End With
  Next Ctrl
End Sub

Protected Overrides Sub OnClientSizeChanged(ByVal e As System.EventArgs)
  SetSizes()
  MyBase.OnClientSizeChanged(e)
End Sub

Private Sub BtnNew_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles BtnNew.Click
  Me.Controls.Add(New CheckBox() With {.Size = BtnNew.Size, .Appearance = Windows.Forms.Appearance.Button})
End Sub

End Class
результат тот же.

Если кнопки сразу сделать такими, чтобы оставалось свободное пространоство для вертикальной прокрутки, то горизонтальная не появляется.

Так и не знаю, что сделать, чтобы получить то поведение, какое хотелось...

Admiralisimys писал(а):Кстати, раз уж не пользоваться дизайнером/мастером форм, тогда от абсолютных координат стоит уходить, используя тот же размер шрифта, что в коде выше с константными множителями.

У контрола достаточно специфическое назначение. Если точнее, то я использую массив UserControl'ов для реализации шагов мастера, причём, контрол может использоваться в нескольких последовательностях. Отсюда и вполне конкретные размеры.


Вернуться в Visual Basic .NET

Кто сейчас на конференции

Сейчас этот форум просматривают: Yandex-бот и гости: 35

    TopList