Сам контроль VB6 UDTs

Позвольте мне ответить на мой вопрос!

Похоже, что использование ListElement в ListModel - это особенность языка .

Как указано в в Руководстве по ListElement :

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

blockquote>

В соответствии с этим, оказывается, что синтаксис ListElement {roleName: roleValue} в ListModel не будет определять экземпляр типа ListElement, но будет элементом List или список пункт из ListModel.

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

QML:

import QtQuick 2.12
import QtQuick.Window 2.12

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")
    ListModel {
        objectName: "model"
        ListElement {
            objectName: "element"
            name: "abc"
        }
    }
}

CPP:

#include 
#include 
#include 
#include 
int main(int argc, char* argv[])
{

    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    if (engine.rootObjects().isEmpty())
        return -1;

    for(const auto &rootObject:engine.rootObjects())
    {
        auto model = rootObject->findChild("model");
        qDebug() << model;
        qDebug() << rootObject->findChild("element");

        if(model)
        {
            qDebug() << model->roleNames();
        }
    }

    return app.exec();
}

Выходные сообщения:

QML debugging is enabled. Only use this in a safe environment.
QQmlListModel(0x26c4e7c1500, name = "model")
QObject(0x0)
QHash((1, "objectName")(0, "name"))

Видели? ListModel создает объект с именем model. Принимая во внимание, что ListElement не создал объект с именем element, но сделал две роли для объекта модели.

18
задан DaveInCaz 26 November 2018 в 12:39
поделиться

3 ответа

Вопреки тому, что сказали другие, возможно получить информацию о типах во время выполнения для UDT's в VB6 (хотя это не встроенная функция языка). Microsoft Библиотека Информационного объекта TypeLib (tlbinf32.dll) позволяет Вам программно осматривать информацию о типе COM во времени выполнения. У Вас должен уже быть этот компонент, если Вам установили Visual Studio: для добавления его к существующему проекту VB6 перейдите в [1 149] Проект-> Ссылки и проверьте, что запись маркировала "TypeLib Information". Обратите внимание, что необходимо будет распределить и зарегистрировать tlbinf32.dll в программе установки приложения.

можно осмотреть экземпляры UDT с помощью компонента информации о TypeLib во времени выполнения, пока UDT's объявляется Public и определяется в Public класс. Это необходимо, чтобы заставить VB6 генерировать COM-совместимую информацию о типе для Вашего UDT's (который может затем быть перечислен с различными классами в компоненте информации о TypeLib). Самый легкий способ отвечать этому требованию состоял бы в том, чтобы поместить весь Ваш UDT's в общественность UserTypes класс, который будет скомпилирован в DLL ActiveX или ActiveX EXE.

Сводка рабочего примера

Этот пример содержит три части:

  • Часть 1 : Создание проекта DLL ActiveX, который будет содержать все общедоступные объявления UDT
  • Часть 2 : Создание примера PrintUDT метод, чтобы продемонстрировать, как можно перечислить поля экземпляра UDT
  • Часть 3 : Создание пользовательского класса итератора, который позволяет Вам легко, выполняет итерации через поля любого общедоступного UDT и получает имена полей и значения.
<час>

рабочий пример

Часть 1: ActiveX DLL

Как я уже упомянул, необходимо сделать UDT's доступным для общественности для перечисления их использующий компонент информации о TypeLib. Единственный способ выполнить это состоит в том, чтобы поместить Ваш UDT's в общедоступный класс в DLL ActiveX или ActiveX проект EXE. Другие проекты в Вашем приложении, которое должно получить доступ к Вашему UDT's, затем сошлются на этот новый компонент.

Для следования наряду с этим примером запустите путем создания нового ActiveX проект DLL и назовите его UDTLibrary.

Затем, переименовывают Class1 модуль класса (это добавляется по умолчанию IDE) к [1 113], и добавьте два пользовательских типа к классу, Person и Animal:

' UserTypes.cls '

Option Explicit

Public Type Person
    FirstName As String
    LastName As String
    BirthDate As Date
End Type

Public Type Animal
    Genus As String
    Species As String
    NumberOfLegs As Long
End Type

Список 1: UserTypes.cls действия как контейнер для нашего UDT's

Затем, изменяются свойство Instancing для UserTypes класс к "2-PublicNotCreatable". Нет никакой причины ни для кого инстанцировать UserTypes класс непосредственно, потому что он просто действует как общедоступный контейнер для нашего UDT's.

Наконец, удостоверьтесь Project Startup Object (под [1 151] Проект-> Свойства ), установлен на к" (Ни одному)", и скомпилируйте проект. У Вас должен теперь быть новый файл, названный UDTLibrary.dll.

Часть 2: Перечисление информация о Типе UDT

Теперь пора продемонстрировать, как мы можем пользоваться Библиотекой объектов TypeLib для реализации PrintUDT метод.

Первый, запустите путем создания нового Стандарта проект EXE и назовите его вообще, Вам нравится. Добавьте ссылку на файл UDTLibrary.dll, который был создан в части 1. Так как я просто хочу продемонстрировать, как это работает, мы будем использовать окно Immediate для тестирования кода, который мы напишем.

Создают новый Модуль, называют его UDTUtils и добавляют следующий код к нему:

'UDTUtils.bas'
Option Explicit    

Public Sub PrintUDT(ByVal someUDT As Variant)

    ' Make sure we have a UDT and not something else... '
    If VarType(someUDT) <> vbUserDefinedType Then
        Err.Raise 5, , "Parameter passed to PrintUDT is not an instance of a user-defined type."
    End If

    ' Get the type information for the UDT '
    ' (in COM parlance, a VB6 UDT is also known as VT_RECORD, Record, or struct...) '

    Dim ri As RecordInfo
    Set ri = TLI.TypeInfoFromRecordVariant(someUDT)

    'If something went wrong, ri will be Nothing'

    If ri Is Nothing Then
        Err.Raise 5, , "Error retrieving RecordInfo for type '" & TypeName(someUDT) & "'"
    Else

        ' Iterate through each field (member) of the UDT '
        ' and print the out the field name and value     '

        Dim member As MemberInfo
        For Each member In ri.Members

            'TLI.RecordField allows us to get/set UDT fields:                 '
            '                                                                 '
            ' * to get a fied: myVar = TLI.RecordField(someUDT, fieldName)    '
            ' * to set a field TLI.RecordField(someUDT, fieldName) = newValue ' 
            '                                                                 '
            Dim memberVal As Variant
            memberVal = TLI.RecordField(someUDT, member.Name)

            Debug.Print member.Name & " : " & memberVal

        Next

    End If

End Sub

Public Sub TestPrintUDT()

    'Create a person instance and print it out...'

    Dim p As Person

    p.FirstName = "John"
    p.LastName = "Doe"
    p.BirthDate = #1/1/1950#

    PrintUDT p

    'Create an animal instance and print it out...'

    Dim a As Animal

    a.Genus = "Canus"
    a.Species = "Familiaris"
    a.NumberOfLegs = 4

    PrintUDT a

End Sub

Список 2: пример PrintUDT метод и простой метод тестирования

Часть 3: Создание его Объектно-ориентированный

вышеупомянутые примеры обеспечивают "быструю и грязную" демонстрацию того, как пользоваться Библиотекой Информационного объекта TypeLib для перечисления полей UDT. В реальном сценарии я, вероятно, создал бы UDTMemberIterator класс, который позволит Вам более легко выполнять итерации через поля UDT, наряду со служебной функцией в модуле, который создает UDTMemberIterator для приведенного примера UDT. Это позволило бы Вам делать что-то как следующее в Вашем коде, который намного ближе к псевдокоду, который Вы отправили в своем вопросе:

Dim member As UDTMember 'UDTMember wraps a TLI.MemberInfo instance'

For Each member In UDTMemberIteratorFor(someUDT)
   Debug.Print member.Name & " : " & member.Value
Next

Это на самом деле не слишком трудно, чтобы сделать это, и мы можем снова использовать большую часть кода от PrintUDT стандартная программа, созданная в части 2.

Сначала, создать новый проект ActiveX и назвать его UDTTypeInformation или что-то подобное.

Затем, удостоверяются, что Объект Запуска для нового проекта не установлен на" (Ни один)".

первое, что нужно сделать состоит в том, чтобы создать простой класс обертки, который скроет детали TLI.MemberInfo класс из кода вызова и поможет получить название и значение поля UDT. Я назвал этот класс UDTMember. свойство Instancing для этого класса должно быть PublicNotCreatable.

'UDTMember.cls'
Option Explicit

Private m_value As Variant
Private m_name As String

Public Property Get Value() As Variant
    Value = m_value
End Property

'Declared Friend because calling code should not be able to modify the value'
Friend Property Let Value(rhs As Variant)
    m_value = rhs
End Property

Public Property Get Name() As String
    Name = m_name
End Property

'Declared Friend because calling code should not be able to modify the value'
Friend Property Let Name(ByVal rhs As String)
    m_name = rhs
End Property

Список 3: UDTMember класс

обертки Теперь мы должны создать класс итератора, UDTMemberIterator, который позволит нам использовать VB's For Each...In синтаксис для итерации полей экземпляра UDT. Instancing свойство для этого класса должно быть установлено на [1 135] (мы определим служебный метод позже, который создаст экземпляры от имени кода вызова).

РЕДАКТИРОВАНИЕ: (2/15/09) я убрал код немного больше.

'UDTMemberIterator.cls'

Option Explicit

Private m_members As Collection ' Collection of UDTMember objects '


' Meant to be called only by Utils.UDTMemberIteratorFor '
'                                                       '
' Sets up the iterator by reading the type info for     '
' the passed-in UDT instance and wrapping the fields in '
' UDTMember objects                                     '

Friend Sub Initialize(ByVal someUDT As Variant)

    Set m_members = GetWrappedMembersForUDT(someUDT)

End Sub

Public Function Count() As Long

    Count = m_members.Count

End Function

' This is the default method for this class [See Tools->Procedure Attributes]   '
'                                                                               '
Public Function Item(Index As Variant) As UDTMember

    Set Item = GetWrappedUDTMember(m_members.Item(Index))

End Function

' This function returns the enumerator for this                                     '
' collection in order to support For...Each syntax.                                 '
' Its procedure ID is (-4) and marked "Hidden" [See Tools->Procedure Attributes]    '
'                                                                                   '
Public Function NewEnum() As stdole.IUnknown

    Set NewEnum = m_members.[_NewEnum]

End Function

' Returns a collection of UDTMember objects, where each element                 '
' holds the name and current value of one field from the passed-in UDT          '
'                                                                               '
Private Function GetWrappedMembersForUDT(ByVal someUDT As Variant) As Collection

    Dim collWrappedMembers As New Collection
    Dim ri As RecordInfo
    Dim member As MemberInfo
    Dim memberVal As Variant
    Dim wrappedMember As UDTMember

    ' Try to get type information for the UDT... '

    If VarType(someUDT) <> vbUserDefinedType Then
        Fail "Parameter passed to GetWrappedMembersForUDT is not an instance of a user-defined type."
    End If

    Set ri = tli.TypeInfoFromRecordVariant(someUDT)

    If ri Is Nothing Then
        Fail "Error retrieving RecordInfo for type '" & TypeName(someUDT) & "'"
    End If

    ' Wrap each UDT member in a UDTMember object... '

    For Each member In ri.Members

        Set wrappedMember = CreateWrappedUDTMember(someUDT, member)
        collWrappedMembers.Add wrappedMember, member.Name

    Next

    Set GetWrappedMembersForUDT = collWrappedMembers

End Function

' Creates a UDTMember instance from a UDT instance and a MemberInfo object  '
'                                                                           '
Private Function CreateWrappedUDTMember(ByVal someUDT As Variant, ByVal member As MemberInfo) As UDTMember

    Dim wrappedMember As UDTMember
    Set wrappedMember = New UDTMember

    With wrappedMember
        .Name = member.Name
        .Value = tli.RecordField(someUDT, member.Name)
    End With

    Set CreateWrappedUDTMember = wrappedMember

End Function

' Just a convenience method
'
Private Function Fail(ByVal message As String)

    Err.Raise 5, TypeName(Me), message

End Function

Список 4: UDTMemberIterator класс.

Примечание, что для создания этого класса повторяемым так, чтобы For Each мог использоваться с ним, необходимо будет установить определенные Атрибуты Процедуры на Item и _NewEnum методы (как отмечено в комментариях к коду). Можно изменить Атрибуты Процедуры из Меню Инструментов (Инструменты-> Атрибуты Процедуры).

Наконец, нам нужна служебная функция (UDTMemberIteratorFor в самом первом примере кода в этом разделе), который создаст UDTMemberIterator для экземпляра UDT, которого мы можем затем выполнить итерации с [1 142]. Создайте новый модуль, названный Utils, и добавьте следующий код:

'Utils.bas'

Option Explicit

' Returns a UDTMemberIterator for the given UDT    '
'                                                  '
' Example Usage:                                   '
'                                                  '
' Dim member As UDTMember                          '
'                                                  '        
' For Each member In UDTMemberIteratorFor(someUDT) '
'    Debug.Print member.Name & ":" & member.Value  '
' Next                                             '
Public Function UDTMemberIteratorFor(ByVal udt As Variant) As UDTMemberIterator

    Dim iterator As New UDTMemberIterator
    iterator.Initialize udt

    Set UDTMemberIteratorFor = iterator

End Function

Список 5: UDTMemberIteratorFor служебная функция.

Наконец, скомпилируйте проект и создайте новый проект проверить его.

В Вашем тестовом проекте, добавьте ссылку на недавно созданный UDTTypeInformation.dll и эти UDTLibrary.dll созданный в части 1 и испытайте следующий код в новом модуле:

'Module1.bas'

Option Explicit

Public Sub TestUDTMemberIterator()

    Dim member As UDTMember

    Dim p As Person

    p.FirstName = "John"
    p.LastName = "Doe"
    p.BirthDate = #1/1/1950#

    For Each member In UDTMemberIteratorFor(p)
        Debug.Print member.Name & " : " & member.Value
    Next

    Dim a As Animal

    a.Genus = "Canus"
    a.Species = "Canine"
    a.NumberOfLegs = 4

    For Each member In UDTMemberIteratorFor(a)
        Debug.Print member.Name & " : " & member.Value
    Next

End Sub

Список 6: Проверение UDTMemberIterator класс.

40
ответ дан 30 November 2019 в 06:59
поделиться

Если Вы изменяете все свои Типы на Классы. У Вас есть опции. Большая ловушка изменения от типа до класса - то, что необходимо использовать новое ключевое слово. Каждый раз там объявление переменной типа добавляют новый.

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

, Тест Класса имеет следующий

Public Key As String
Public Data As String

, можно затем сделать следующий

Private Sub Command1_Click()
    Dim T As New Test 'This is NOT A MISTAKE read on as to why I did this.
    T.Key = "Key"
    T.Data = "One"
    DoTest T
End Sub

Private Sub DoTest(V As Variant)
    On Error Resume Next
    Print V.Key
    Print V.Data
    Print V.DoesNotExist
    If Err.Number = 438 Then Print "Does Not Exist"
    Print CallByName(V, "Key", VbGet)
    Print CallByName(V, "Data", VbGet)
    Print CallByName(V, "DoesNotExist", VbGet)
    If Err.Number = 438 Then Print "Does Not Exist"
End Sub

, При попытке использовать поле, которое не существует затем, ошибка 438 будет повышена. CallByName позволяет Вам использовать строки для вызова поля и методов класса.

то, Что делает VB6, когда Вы объявляете Тусклый как Новые, довольно интересно и значительно минимизирует ошибки в этом преобразовании. Вы видите, что это

Dim T as New Test

не рассматривают точно то же как [1 112]

Dim T as Test
Set T = new Test

, Например, это будет работать

Dim T as New Test
T.Key = "A Key"
Set T = Nothing
T.Key = "A New Key"

, Это даст ошибку

Dim T as Test
Set T = New Test
T.Key = "A Key"
Set T = Nothing
T.Key = "A New Key"

, причина этого состоит в том, что в первом примере VB6 отмечает T так, чтобы каждый раз, когда к участнику получили доступ, это проверяет, является ли T ничем. Если это будет это, то автоматически создаст новый экземпляр Тестового Класса и затем присвоит переменную.

Во втором примере VB не добавляет это поведение.

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

1
ответ дан 30 November 2019 в 06:59
поделиться

@Dan,

Это похоже на Вашу попытку использовать RTTI UDT. Я не думаю, что можно действительно получить ту информацию, не зная о UDT перед временем выполнения. Получить Вас запустило попытку:

UDTs
Понимания из-за не наличия этой отражательной возможности. Я создал бы свой собственный RTTI к моему UDTs.

, Чтобы дать Вам базовую линию. Попробуйте это:

Type test
    RTTI as String
    a as Long
    b as Long 
    c as Long
    d as Integer
end type

можно записать утилиту, которая откроет каждый исходный файл и добавит RTTI с названием типа к UDT. Вероятно, было бы лучше для помещения всего UDTs в общий файл.

RTTI был бы чем-то вроде этого:

"String:Long:Long:Long:Integer"

Используя память UDT можно извлечь значения.

1
ответ дан 30 November 2019 в 06:59
поделиться