diff options
Diffstat (limited to 'src/activeqt/doc/src/examples/dotnet.qdoc')
-rw-r--r-- | src/activeqt/doc/src/examples/dotnet.qdoc | 308 |
1 files changed, 0 insertions, 308 deletions
diff --git a/src/activeqt/doc/src/examples/dotnet.qdoc b/src/activeqt/doc/src/examples/dotnet.qdoc deleted file mode 100644 index 7f4451d..0000000 --- a/src/activeqt/doc/src/examples/dotnet.qdoc +++ /dev/null @@ -1,308 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only - -/*! - \page activeqt-dotnet.html - \title Dot Net Example (ActiveQt) - - \brief The Dot Net example demonstrates how Qt objects can be used in a - .NET environment, and how .NET objects can be used in a Qt - environment. - - Contents: - - \tableofcontents - - \section1 Qt vs. .NET - - Qt is a C++ library and is compiled into traditional, native - binaries that make full use of the performance provided by the - runtime environment. - - One of the key concepts of .NET is the idea of "intermediate language - code" - the source code is compiled into a bytecode format, and at - runtime, that bytecode is executed in a virtual machine - the \e - {Common Language Runtime} (CLR). - - Another key concept is that of \e {managed code}. This is essentially - intermediate language code written in such a way that the CLR can take - care of the memory management, i.e. the CLR will do automatic garbage - collection, so the application code does not need to explicitly free - the memory for unused objects. - - The MS compilers for C# and VB.NET will only produce managed - code. Such programs cannot directly call normal, native functions - or classes. \footnote The .NET framework provides Platform Invocation - Services - P/Invoke - that enable managed code to call native C (not - C++) functions located in DLLs directly. The resulting application - then becomes partially unmanaged.\endfootnote - - The MS C++ compiler for .NET on the other hand, can produce both - normal and managed code. To write a C++ class that can be compiled - into managed code, the developer must flag the class as managed using - the \c __gc keyword, and restrict the code to only use the subset of - C++ known as "Managed Extensions for C++", or MC++ for short. The - advantage is that MC++ code can freely call and use normal C++ - functions and classes. And it also works the other way around: normal - C++ code can call managed functions and use managed classes (e.g. the - entire .NET framework class library), including managed functions and - classes implemented in C# or VB.NET. This feature of mixing managed - and normal C++ code immensely eases the interoperability with .NET, - and is by Microsoft referred to as the "It Just Works" (IJW) feature. - - This document demonstrates two different ways of integrating normal - C++ code (that uses Qt) with managed .NET code. First, the manual way - is presented, which includes using a thin MC++ wrapper class around - the normal Qt/C++ class. Then, the automated way is presented, which - utilizes the ActiveQt framework as a generic bridge. The advantage of - the first method is that it gives the application developer full - control, while the second method requires less coding and relieves the - developer of dealing with the conversion between managed and normal - data objects. - - The impatient reader, who right away wants to see a QPushButton - and a custom Qt widget (\l{activeqt/multiple}{QAxWidget2}) run in - a .NET GUI application is referred to the example directory of - ActiveQt. It contains the result of this walkthrough using both - C# and VB.NET, created with Visual Studio .NET (not 2003). - Load \c {examples/dotnet/walkthrough/csharp.csproj}, - \c {examples/dotnet/walkthrough/vb.vbproj} - or \c {examples/dotnet/wrapper/wrapper.sln} into the IDE and run - the solution. - - \b{Remark:} You will notice that in the generated code the following line is - commented out: - - \snippet doc_src_examples_activeqt_dotnet.qdoc 0 - - This line is regenerated without comment whenever you change the - dialog, in which case you have to comment it out again to be able - to run the project. This is a bug in the original version of - Visual Studio.NET, and is fixed in the 2003 edition. - - \section1 Walkthrough: .NET Interop with MC++ and IJW - - Normal C++ classes and functions can be used from managed .NET code by - providing thin wrapper classes written in MC++. The wrapper class will - take care of forwarding the calls to the normal C++ functions or - methods, and converting parameter data as necessary. Since the wrapper - class is a managed class, it can be used without further ado in any - managed .NET application, whether written in C#, VB.NET, MC++ or other - managed programming language. - - \snippet activeqt/dotnet/wrapper/lib/worker.h 0 - - The Qt class has nothing unusual for Qt users, and as even the Qt - specialities like \c Q_PROPERTY, \c slots and \c signals are - implemented with straight C++ they don't cause any trouble when - compiling this class with any C++ compiler. - - \snippet activeqt/dotnet/wrapper/lib/networker.h 0 - - The .NET wrapper class uses keywords that are part of MC++ to indicate - that the class is managed/garbage collected (\c {__gc}), and that \c - StatusString should be accessible as a property in languages that - support this concept (\c {__property}). We also declare an event - function \c statusStringChanged(String*) (\c {__event}), the - equivalent of the respective signal in the Qt class. - - Before we can start implementing the wrapper class we need a way to - convert Qt's datatypes (and potentionally your own) into .NET - datatypes, e.g. \c QString objects need to be converted into objects - of type \c {String*}. - - When operating on managed objects in normal C++ code, a little extra - care must be taken because of the CLR's garbage collection. A normal - pointer variable should not \footnote Indeed, the compiler will in - many cases disallow it. \endfootnote be used to refer to a managed - object. The reason is that the garbage collection can kick in at any - time and move the object to another place on the heap, leaving you - with an invalid pointer. - - However, two methods are provided that solves this problem easily. The - first is to use a \e pinned pointer, i.e. declare the pointer variable - with the \c __pin keyword. This guarantees that the object pointed to - will not be moved by the garbage collector. It is recommended that - this method not be used to keep a references to managed objects for a - long time, since it will decrease the efficiency of the garbage - collector. The second way is to use the \c gcroot smartpointer - template type. This lets you create safe pointers to managed - objects. E.g. a variable of type \c gcroot<String> will always point - to the String object, even if it has been moved by the garbage - collector, and it can be used just like a normal pointer. - - \snippet activeqt/dotnet/wrapper/lib/tools.cpp 0 - \codeline - \snippet activeqt/dotnet/wrapper/lib/tools.cpp 1 - - The convertor functions can then be used in the wrapper class - implementation to call the functions in the native C++ class. - - \snippet activeqt/dotnet/wrapper/lib/networker.cpp 0 - \codeline - \snippet activeqt/dotnet/wrapper/lib/networker.cpp 1 - - The constructor and destructor simply create and destroy the Qt - object wrapped using the C++ operators \c new and \c delete. - - \snippet activeqt/dotnet/wrapper/lib/networker.cpp 2 - - The netWorker class delegates calls from the .NET code to the native - code. Although the transition between those two worlds implies a small - performance hit for each function call, and for the type conversion, - this should be negligible since we are anyway going to run within the - CLR. - - \snippet activeqt/dotnet/wrapper/lib/networker.cpp 3 - - The property setter calls the native Qt class before firing the - event using the \c __raise keyword. - - This wrapper class can now be used in .NET code, e.g. using C++, C#, - Visual Basic or any other programming language available for .NET. - - \snippet activeqt/dotnet/wrapper/main.cs 0 - \snippet activeqt/dotnet/wrapper/main.cs 1 - \snippet activeqt/dotnet/wrapper/main.cs 2 - \snippet activeqt/dotnet/wrapper/main.cs 3 - - \section1 Walkthrough: .NET/COM Interop with ActiveQt - - Fortunately .NET provides a generic wrapper for COM objects, the - \e {Runtime Callable Wrapper} (RCW). This RCW is a proxy for the - COM object and is generated by the CLR when a .NET Framework client - activates a COM object. This provides a generic way to reuse COM - objects in a .NET Framework project. - - Making a QObject class into a COM object is easily achieved with - ActiveQt and demonstrated in the QAxServer examples (e.g., the - \l{activeqt/simple}{Simple} example). The walkthrough will use - the Qt classes implemented in those examples, so the first thing - to do is to make sure that those examples have been built - correctly, e.g. by opening the - \l{qaxserver-demo-multiple.html}{demonstration pages} in Internet - Explorer to verify that the controls are functional. - - \section2 Starting a Project - - Start Visual Studio.NET, and create a new C# project for writing a - Windows application. This will present you with an empty form in - Visual Studio's dialog editor. You should see the toolbox, which - presents you with a number of available controls and objects in - different categories. If you right-click on the toolbox it allows - you to add new tabs. We will add the tab "Qt". - - \section2 Importing Qt Widgets - - The category only has a pointer tool by default, and we have to add - the Qt objects we want to use in our form. Right-click on the empty - space, and select "Customize". This opens a dialog that has two - tabs, "COM Components" and ".NET Framework Components". We used - ActiveQt to wrap \l {QWidget}s into COM objects, so we select the "COM - Components" page, and look for the classes we want to use, e.g. - "QPushButton" and "QAxWidget2". - - When we select those widgets and close the dialog the two widgets - will now be available from the toolbox as grey squares with their - name next to it \footnote Icons could be added by modifying the - way the controls register themselves. \endfootnote. - - \section2 Using Qt Widgets - - We can now add an instance of QAxWidget2 and a QPushButton to - the form. Visual Studio will automatically generate the RCW for the - object servers. The QAxWidget2 instance takes most of the upper - part of the form, with the QPushButton in the lower right corner. - - In the property editor of Visual Studio we can modify the properties - of our controls - QPushButton exposes the \c QWidget API and has many - properties, while QAxWidget2 has only the Visual Studio standard - properties in addition to its own property "lineWidth" in the - "Miscellaneous" category. The objects are named "axQPushButton1" and - "axQAxWidget21", and since especially the last name is a bit - confusing we rename the objects to "resetButton" and "circleWidget". - - We can also change the Qt properties, e.g. set the "text" property - of the \c resetButton to "Reset", and the "lineWidth" property of the - \c circleWidget to 5. We can also put those objects into the layout - system that Visual Studio's dialog editor provides, e.g. by setting - the anchors of the \c circleWidget to "Left, Top, Right, Bottom", and - the anchors of the \c resetButton to "Bottom, Right". - - Now we can compile and start the project, which will open a user - interface with our two Qt widgets. If we can resize the dialog, - the widgets will resize appropriately. - - \section2 Handling Qt Signals - - We will now implement event handlers for the widgets. Select the - \c circleWidget and select the "Events" page in the property - editor. The widget exposes events because the QAxWidget2 class has - the "StockEvents" attribute set in its class definition. We implement - the event handler \c circleClicked for the \c ClickEvent to increase - the line width by one for every click: - - \snippet activeqt/dotnet/walkthrough/Form1.cs 0 - - In general we can implement a default event handler by double - clicking on the widget in the form, but the default events for - our widgets are right now not defined. - - We will also implement an event handler for the \c clicked signal - emitted by QPushButton. Add the event handler \c resetLineWidth to - the \c clicked event, and implement the generated function: - - \snippet activeqt/dotnet/walkthrough/Form1.cs 1 - - We reset the property to 1, and also call the \c setFocus() slot - to simulate the user style on Windows, where a button grabs focus - when you click it (so that you can click it again with the spacebar). - - If we now compile and run the project we can click on the circle - widget to increase its line width, and press the reset button to - set the line width back to 1. - - \section1 Summary - - Using ActiveQt as a universal interoperability bridge between the - .NET world and the native world of Qt is very easy, and makes it - often unnecessary to implement a lot of handwritten wrapper classes. - Instead, the QAxFactory implementation in the otherwise completely - cross-platform Qt project provides the glue that .NET needs to to - generate the RCW. - - If this is not sufficient we can implement our own wrapper classes - thanks to the C++ extensions provided by Microsoft. - - \section2 Limitations - - All the limitations when using ActiveQt are implied when using this - technique to interoperate with .NET, e.g. the datatypes we can use - in the APIs can only be those supported by ActiveQt and COM. However, - since this includes subclasses of QObject and QWidget we can wrap - any of our datatypes into a QObject subclass to make its API - available to .NET. - - When using the "IJW" method, in principle the only limitation is the - time required to write the wrapper classes and data type conversion - functions. - - \section2 Performance Considerations - - Every call from CLR bytecode to native code implies a small - performance hit, and necessary type conversions introduce an - additional delay with every layer that exists between the two - frameworks. Consequently every approach to mix .NET and native - code should try to minimize the communication necessary between - the different worlds. - - As ActiveQt introduces three layers at once - the RCW, COM and finally - ActiveQt itself - the performance penalty when using the generic - Qt/ActiveQt/COM/RCW/.NET bridge is larger than when using a - hand-crafted IJW-wrapper class. The execution speed however is still - sufficient for connecting to and modifying interactive elements in a - user interface, and as soon as the benefit of using Qt and C++ to - implement and compile performance critical algorithms into native code - kicks in, ActiveQt becomes a valid choice for making even non-visual - parts of your application accessible to .NET. -*/ |