Добавить обработчик событий для каждого элемента управления в форме во время выполнения VB6 - PullRequest
5 голосов
/ 25 марта 2011

У меня есть приложение VB6, где я хотел бы иметь согласованное поведение среди его элементов управления во всем приложении.Например, одним из вариантов поведения будет выделение текстового поля, когда оно получает фокус, и удаление выделения, когда он теряет фокус.Я бы хотел, чтобы это происходило с каждой формой.

Я пытаюсь создать одну подпроцедуру, которая может быть вызвана всеми формами при загрузке, чтобы такое поведение происходило.Таким образом, мне не нужно вручную кодировать каждое отдельное текстовое поле, чтобы выделить его.

Я пытался заставить VB6 присоединить обработчик событий к элементу управления во время выполнения, но он просто лает на меня.Я пришел из .Net фона, так что, возможно, я неправильно подхожу к VB6.Но как я могу получить это желаемое поведение без необходимости вручную кодировать его для каждого элемента управления?

Ответы [ 7 ]

3 голосов
/ 25 марта 2011

Вы также можете "Подкласс" ваши элементы управления TextBox, используя WithEvents.Преимущество здесь в том, что вы можете кодировать выделение и снятие выделения в одном месте без необходимости проходить и заменять все существующие элементы управления (как предлагает Скотт).

Недостатком является то, что вы должны добавить код к событию Form_Load всех ваших форм, чтобы «зарегистрировать» элементы управления в этой форме.Однако даже это не должно быть слишком плохо, если вы хотите применить технику к каждому контролю;в этом случае вам просто нужно написать функцию, которая перебирает коллекцию .Controls формы и регистрирует каждый элемент управления.Затем просто вызовите эту функцию в событии Form_Load каждой формы.

2 голосов
/ 26 марта 2011

Еще один способ добиться желаемого поведения - совсем не обрабатывать события текстового поля.Вместо этого установите элемент управления Timer с небольшим интервалом между тиками, скажем, 50 миллисекунд.В событии Tick установите флажок Me.ActiveControl, чтобы увидеть, сместился ли фокус, и соответственно выделите / отключите подсветку.Вам понадобится статическая переменная, чтобы запомнить, какой элемент управления имеет фокус.

Это хороший простой способ получить универсальный обработчик событий GotFocus / LostFocus в VB6.

2 голосов
/ 25 марта 2011

К сожалению, VB6 не поддерживает наследование реализации, и вы не можете наследовать TextBox и просто изменять или добавлять функциональность. Он также не поддерживает агрегацию COM, хотя я сомневаюсь, что спецификация элементов управления ActiveX также поддерживает это.

Осталось переопределить элемент управления с нуля или реализовать пользовательский элемент управления UserControl, который содержит исходный элемент управления и перенаправляет каждый метод, свойство или событие. Проблема с последним подходом состоит не в том, что в нем много бессмысленного кода, а в производительности пользовательских элементов управления VB6. Встроенные элементы управления работают очень быстро, и вы можете разместить сотни меток или текстовых полей, прежде чем заметить ухудшение качества.

Что я делаю в таких случаях, как ваш, - это реализовать класс-расширитель, который содержит ссылку на элемент управления textbox, подклассирует его и / или прослушивает и отвечает на вызванные события из элемента управления. Класс extender реализует желаемое / измененное поведение для события GetFocus или WM_GETFOCUS, что угодно. Затем для каждого текстового поля в форме инициализируется экземпляр расширителя со ссылкой на элемент управления. Все расширители хранятся в коллекции, которая может быть частью класса, расширяющего саму форму. Расширитель формы может обернуть создание и инициализацию расширений элемента управления (часть «Для каждого элемента управления»).

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

2 голосов
/ 25 марта 2011
1 голос
/ 25 марта 2011

Надлежащий способ сделать то, что вы просите, - это определить новый UserControl (MyAdvancedTextBox) и кодировать там свое предполагаемое поведение.Затем замените все текстовые поля на этот пользовательский элемент управления.Это большая работа, но это меньше работы, чем альтернатива:

Вручную определите обработчик событий в коде для каждого текстового поля (или управляющего массива текстового поля) и передайте обработчик события самому себеобщая подпрограмма модуля, которая выполняет вашу общую логику обработки.

События VB6 намного более примитивны, чем .NET.

0 голосов
/ 21 июля 2016

Советы хорошие.Однако приведенный пример очень ограничен.У меня проблема с событиями для динамических элементов управления.Я должен создать флажок, текстовое поле, переключатели и поле со списком по нажатию кнопки.Я могу успешно создавать динамические элементы управления. НО Я не могу зафиксировать действия каждого из этих элементов управления, такие как изменение статуса флажка или параметров радио или изменения в раскрывающемся тексте ...

Добавление кода для справки:Ожидание:
1. Я должен иметь возможность зафиксировать изменение строки в флажке
2. Я должен иметь возможность зафиксировать изменения в комбинированном окне

Статические элементы управления:
1. Форма: frmcharacteristics
2. Кнопка: cmdAddCharacteristics
3. SSTab: tabDisplay

Код в Module1:

Public SR_NO As Long
Public Top_Position As Long

код в frmCharacterisitcs

Option Explicit
Dim WithEvents Ch_Delete_Row As CheckBox
Dim WithEvents Ch_SR_NO As Label
Dim WithEvents Ch_Name As TextBox
Dim WithEvents Ch_Type As ComboBox

Dim WithEvents Extended_Control As VBControlExtender


Private Sub cmdAddCharacteristics_Click()

    Module1.SR_NO = Module1.SR_NO + 1
    Set Ch_Delete_Row = frmCharacteristics.Controls.Add("VB.CheckBox", "Ch_Delete_Row" & (Module1.SR_NO), tabDisplay)
    Ch_Delete_Row.Visible = True
    Ch_Delete_Row.Top = Module1.Top_Position + 100
    Ch_Delete_Row.Width = 1000
    Ch_Delete_Row.Left = 500
    Ch_Delete_Row.Caption = ""
    Ch_Delete_Row.Height = 315
    'MsgBox Ch_Delete_Row.Name

    Set Ch_SR_NO = frmCharacteristics.Controls.Add("VB.Label", "Ch_SR_NO" & (Module1.SR_NO), tabDisplay)
    Ch_SR_NO.Visible = True
    Ch_SR_NO.Top = Module1.Top_Position + 200
    Ch_SR_NO.Width = 750
    Ch_SR_NO.Left = Ch_Delete_Row.Left + Ch_Delete_Row.Width + 400
    Ch_SR_NO.Caption = Module1.SR_NO
    Ch_SR_NO.Height = 315

    Set Ch_Name = frmCharacteristics.Controls.Add("VB.TextBox", "Ch_Name" & (Module1.SR_NO), tabDisplay)
    Ch_Name.Visible = True
    Ch_Name.Top = Module1.Top_Position + 100
    Ch_Name.Width = 2000
    Ch_Name.Left = Ch_SR_NO.Left + Ch_SR_NO.Width + 200
    Ch_Name.Text = ""
    Ch_Name.Height = 315

    Set Ch_Type = frmCharacteristics.Controls.Add("VB.ComboBox", "Ch_Type" & (Module1.SR_NO), tabDisplay)
    Ch_Type.Visible = True
    Ch_Type.Top = Module1.Top_Position + 100
    Ch_Type.Width = 1500
    Ch_Type.Left = Ch_Name.Left + Ch_Name.Width + 50
    Ch_Type.Text = ""
    'Ch_Type.Height = 315
    Ch_Type.AddItem "Service"
    Ch_Type.AddItem "Special"
    Ch_Type.AddItem "Option"

    Module1.Top_Position = Module1.Top_Position + 400
End Sub

Private Sub Form_Load()
    Module1.SR_NO = 0
    Dim Test_Line As Control
    Set Test_Line = frmCharacteristics.Controls.Add("VB.Line", "LINE", frmCharacteristics)
    Test_Line.Visible = True
    Test_Line.X1 = 100
    Test_Line.Y1 = 600
    Test_Line.X2 = frmCharacteristics.Width
    Test_Line.Y2 = 600
    Top_Position = Test_Line.Y1
    frmCharacteristics.Show
    tabDisplay.Width = frmCharacteristics.Width - 1000
    tabDisplay.Height = frmCharacteristics.Height - 1500
    tabDisplay.Left = frmCharacteristics.Left + 200
    Call set_labels
End Sub


Sub set_labels()

    Dim Label_SR_NO As Control
    Dim Label_Name As Control
    Dim Label_Delete_Row As Control
    Dim Label_Type As Control

    Set Label_Delete_Row = frmCharacteristics.Controls.Add("VB.Label", "Label_Delete_Row" & (Module1.SR_NO), tabDisplay)
    Label_Delete_Row.Visible = True
    Label_Delete_Row.Top = Module1.Top_Position + 100
    Label_Delete_Row.Width = 1000
    Label_Delete_Row.Left = 300
    Label_Delete_Row.Caption = "Delete(Y/N)"
    Label_Delete_Row.Height = 315

    Set Label_SR_NO = frmCharacteristics.Controls.Add("VB.Label", "Label_SR_NO" & (Module1.SR_NO), tabDisplay)
    Label_SR_NO.Visible = True
    Label_SR_NO.Top = Module1.Top_Position + 100
    Label_SR_NO.Width = 750
    Label_SR_NO.Left = Label_Delete_Row.Left + Label_Delete_Row.Width + 400
    Label_SR_NO.Caption = "SR_NO"
    Label_SR_NO.Height = 315

    Set Label_Name = frmCharacteristics.Controls.Add("VB.Label", "Label_Name" & (Module1.SR_NO), tabDisplay)
    Label_Name.Visible = True
    Label_Name.Top = Module1.Top_Position + 100
    Label_Name.Width = 2000
    Label_Name.Left = Label_SR_NO.Left + Label_SR_NO.Width + 400
    Label_Name.Caption = "Characteristics Name"
    Label_Name.Height = 315

    Set Label_Type = frmCharacteristics.Controls.Add("VB.Label", "Label_Type" & (Module1.SR_NO), tabDisplay)
    Label_Type.Visible = True
    Label_Type.Top = Module1.Top_Position + 100
    Label_Type.Width = 1500
    Label_Type.Left = Label_Name.Left + Label_Name.Width + 50
    Label_Type.Caption = "Charac. Type"
    Label_Type.Height = 315

    Module1.Top_Position = Module1.Top_Position + 400
End Sub
0 голосов
/ 06 декабря 2013

Я сам с идеей Extender, благодаря подсказке с этого сайта. Я нашел собственное решение:

Класс clsTextBoxExtender Определение:

Public WithEvents Control As TextBox

Private Sub Control_GotFocus()
    Control.SelStart = 0
    Control.SelLength = Len(Control.Text)
End Sub

Private Sub Control_LostFocus()
    Control.SelLength = 0
End Sub

Модуль Module1 Определение:

Public Sub InitialiseTextBoxExtenders(ByRef myForm As Form, ByRef extenderCollection As Collection)
    Dim formControl As Control
    Dim oTBXExtender As clsTextBoxExtender
    For Each formControl In myForm.Controls
        If TypeOf formControl Is TextBox Then
            Set oTBXExtender = New clsTextBoxExtender
            Set oTBXExtender.Control = formControl
            extenderCollection.Add oTBXExtender
        End If
     Next
End Sub

Форма Form1 Определение:

Private textBoxExtenderCollection As New Collection

Private Sub Form1_Load()
    Module1.InitialiseTextBoxExtenders Me, textBoxExtenderCollection
End Sub

'No longer required
'Private Sub TextBox1_GotFocus()
'    TextBox1.SelStart = 0
'    TextBox1.SelLength = Len(TextBox1.Text)
'End Sub

Таким образом, для каждой новой формы все, что вам нужно сделать, это объявить коллекцию и вызвать код инициализатора в событии загрузки формы. Простой!

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

Также обратите внимание, что если вы объявите одно и то же событие в своей форме для контроля, ваше событие и событие extender будут срабатывать одно за другим. Однако я не знаю какой-либо документации по этому вопросу, поскольку из моих экспериментов событие extender идет последним.

...