Qt 5.11 - Dot Net Example (ActiveQt)

डॉट नेट उदाहरण (ActiveQt)




qt

डॉट नेट उदाहरण (ActiveQt)

सामग्री:

Qt बनाम .NET

Qt एक C ++ लाइब्रेरी है और पारंपरिक, देशी बायनेरिज़ में संकलित की जाती है जो रनटाइम वातावरण द्वारा प्रदान किए गए प्रदर्शन का पूरा उपयोग करती है।

.NET की प्रमुख अवधारणाओं में से एक "मध्यवर्ती भाषा कोड" का विचार है - स्रोत कोड को बाईटेकोड प्रारूप में संकलित किया गया है, और रनटाइम में, कि बायटेकोड को एक आभासी मशीन में निष्पादित किया जाता है - सामान्य भाषा रनटाइम (सीएलआर)।

एक अन्य मुख्य अवधारणा प्रबंधित कोड की है । यह अनिवार्य रूप से मध्यवर्ती भाषा कोड है जो इस तरह से लिखा जाता है कि सीएलआर मेमोरी प्रबंधन का ध्यान रख सकता है, यानी सीएलआर स्वचालित कचरा संग्रह करेगा, इसलिए एप्लिकेशन कोड को अप्रयुक्त वस्तुओं के लिए मेमोरी को स्पष्ट रूप से मुक्त करने की आवश्यकता नहीं है।

C # और VB.NET के लिए MS कंपाइलर केवल प्रबंधित कोड का उत्पादन करेगा। इस तरह के कार्यक्रम सीधे सामान्य, मूल कार्यों या कक्षाओं को नहीं बुला सकते हैं।

दूसरी ओर .NET के लिए MS C ++ कंपाइलर, सामान्य और प्रबंधित कोड दोनों का उत्पादन कर सकता है। C ++ वर्ग लिखने के लिए जिसे प्रबंधित कोड में संकलित किया जा सकता है, डेवलपर को __gc कीवर्ड का उपयोग करके प्रबंधित किए जाने वाले वर्ग को फ़्लैग करना चाहिए, और कोड को केवल C ++ के सबसेट का उपयोग करने के लिए प्रतिबंधित करना चाहिए, जिसे "C ++ के लिए प्रबंधित एक्सटेंशन", या लघु के लिए MC ++ कहा जाता है। । लाभ यह है कि एमसी ++ कोड स्वतंत्र रूप से सामान्य सी ++ फ़ंक्शन और कक्षाओं को कॉल और उपयोग कर सकता है। और यह दूसरे तरीके से भी काम करता है: सामान्य C ++ कोड प्रबंधित फ़ंक्शंस को कॉल कर सकता है और प्रबंधित क्लासेस (जैसे संपूर्ण .NET फ्रेमवर्क क्लास लाइब्रेरी) का उपयोग कर सकता है, जिसमें C # या VB.NET में कार्यान्वित प्रबंधित फ़ंक्शंस और कक्षाएं शामिल हैं। प्रबंधित और सामान्य C ++ कोड को मिलाने की यह सुविधा .NET के साथ इंटरऑपरेबिलिटी को बहुत कम करती है, और Microsoft द्वारा इसे "इट जस्ट वर्क्स" (IJW) फीचर के रूप में संदर्भित किया जाता है।

यह दस्तावेज़ प्रबंधित C .NET कोड के साथ सामान्य C ++ कोड (जो Qt का उपयोग करता है) को एकीकृत करने के दो अलग-अलग तरीकों को दर्शाता है। सबसे पहले, मैनुअल तरीका प्रस्तुत किया गया है, जिसमें सामान्य Qt / C ++ वर्ग के आसपास एक पतली MC ++ आवरण वर्ग का उपयोग करना शामिल है। फिर, स्वचालित तरीका प्रस्तुत किया जाता है, जो जेनेरिक ब्रिज के रूप में ActiveQt ढांचे का उपयोग करता है। पहली विधि का लाभ यह है कि यह एप्लिकेशन डेवलपर को पूर्ण नियंत्रण देता है, जबकि दूसरी विधि में कम कोडिंग की आवश्यकता होती है और डेवलपर को प्रबंधित और सामान्य डेटा ऑब्जेक्ट्स के बीच के रूपांतरण से राहत देती है।

अधीर पाठक, जो तुरंत एक QAxWidget2 और एक कस्टम Qt विजेट ( QAxWidget2 ) को .NET GUI अनुप्रयोग में चलाना देखना चाहता है, को QAxWidget2 के उदाहरण निर्देशिका में संदर्भित किया जाता है। इसमें विजुअल स्टूडियो .NET (2003 नहीं) के साथ बनाए गए C # और VB.NET दोनों का उपयोग करके इस वॉकथ्रू का परिणाम है। लोड examples/dotnet/walkthrough/csharp.csproj , examples/dotnet/walkthrough/vb.vbproj examples/dotnet/walkthrough/csharp.csproj examples/dotnet/walkthrough/vb.vbproj या examples/dotnet/wrapper/wrapper.sln examples/dotnet/walkthrough/vb.vbproj examples/dotnet/wrapper/wrapper.sln । आईडीई में प्रवेश करें और समाधान चलाएं।

टिप्पणी: आप ध्यान देंगे कि उत्पन्न कोड में निम्नलिखित लाइन पर टिप्पणी की गई है:

' VB is case insensitive, but our C++ controls are not.
' Me.resetButton.enabled = True

जब भी आप संवाद बदलते हैं, तो यह पंक्ति बिना किसी टिप्पणी के पुनर्जीवित हो जाती है, जिस स्थिति में आपको परियोजना को चलाने में सक्षम होने के लिए फिर से टिप्पणी करनी होगी। यह Visual Studio.NET के मूल संस्करण में एक बग है, और 2003 संस्करण में तय किया गया है।

Walkthrough: MC ++ और IJW के साथ .NET इंटरॉप

MC ++ में लिखे गए पतले रैपर वर्गों को प्रदान करके प्रबंधित C। NET कोड से सामान्य C ++ वर्ग और कार्यों का उपयोग किया जा सकता है। आवरण वर्ग सामान्य C ++ फ़ंक्शंस या विधियों को कॉल अग्रेषित करने और पैरामीटर डेटा को आवश्यकतानुसार परिवर्तित करने का ध्यान रखेगा। चूँकि आवरण वर्ग एक प्रबंधित वर्ग है, इसलिए इसे किसी भी प्रबंधित .NET अनुप्रयोग में आगे की हलचल के बिना उपयोग किया जा सकता है, चाहे वह C #, VB.NET, MC ++ या अन्य प्रबंधित प्रोग्रामिंग भाषा में लिखा गया हो।

class Worker : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString statusString READ statusString WRITE setStatusString)
public:
    Worker();

    QString statusString() const;

public slots:
    void setStatusString(const QString &string);

signals:
    void statusStringChanged(const QString &string);

private:
    QString status;
};

Qt वर्ग के पास Qt उपयोगकर्ताओं के लिए कुछ भी असामान्य नहीं है, और यहां तक ​​कि Q_PROPERTY जैसे Qt विशिष्टताओं, slots और signals को सीधे C ++ के साथ लागू किया जाता है, वे इस वर्ग को किसी भी C ++ कंपाइलर के साथ संकलित करते समय कोई परेशानी नहीं पैदा करते हैं।

class Worker;

// .NET class
public __gc class netWorker
{
public:
    netWorker();
    ~netWorker();

    __property String *get_StatusString();
    __property void set_StatusString(String *string);

    __event void statusStringChanged(String *args);

private:
    Worker *workerObject;
};

.NET रैपर क्लास उन कीवर्ड का उपयोग करता है जो यह इंगित करने के लिए MC ++ का हिस्सा हैं कि क्लास प्रबंधित / कचरा एकत्र किया गया है ( __gc ), और वह StatusString भाषाओं में एक संपत्ति के रूप में सुलभ होनी चाहिए जो इस अवधारणा ( __property ) का समर्थन __property । हम Qt वर्ग में संबंधित सिग्नल के समतुल्य एक ईवेंट फ़ंक्शन statusStringChanged(String*) ( __event ) की __event करते हैं।

इससे पहले कि हम रैपर क्लास को लागू करना शुरू कर सकें, हमें Qt के डेटाटिप्स (और अपने खुद के) को .NET डेटाटिप्स में बदलने का एक तरीका चाहिए, जैसे QString ऑब्जेक्ट्स को String* ऑब्जेक्ट में बदलना होगा।

सामान्य सी ++ कोड में प्रबंधित वस्तुओं पर काम करते समय, सीएलआर के कचरा संग्रह के कारण थोड़ी अतिरिक्त देखभाल की जानी चाहिए। एक सामान्य सूचक चर नहीं होना चाहिए

एक प्रबंधित वस्तु को संदर्भित करने के लिए उपयोग किया जाता है। कारण यह है कि कचरा संग्रह किसी भी समय में किक कर सकता है और ऑब्जेक्ट को ढेर पर किसी अन्य स्थान पर स्थानांतरित कर सकता है, जो आपको एक अवैध शटर के साथ छोड़ देगा।

हालांकि, दो तरीके प्रदान किए जाते हैं जो इस समस्या को आसानी से हल करते हैं। सबसे पहले एक पिन किए गए पॉइंटर का उपयोग करना है, यानी __pin कीवर्ड के साथ पॉइंटर चर घोषित करना है। यह गारंटी देता है कि इंगित की गई वस्तु को कचरा कलेक्टर द्वारा स्थानांतरित नहीं किया जाएगा। यह अनुशंसा की जाती है कि इस पद्धति का उपयोग लंबे समय तक प्रबंधित वस्तुओं के संदर्भ में रखने के लिए नहीं किया जाए, क्योंकि यह कचरा कलेक्टर की दक्षता में कमी करेगा। दूसरा तरीका gcroot स्मार्टपॉइंट टेम्पलेट प्रकार का उपयोग करना है। यह आपको प्रबंधित ऑब्जेक्ट्स के लिए सुरक्षित पॉइंटर्स बनाने देता है। उदाहरण के प्रकार gcroot<String> का एक चर gcroot<String> हमेशा String ऑब्जेक्ट को इंगित करेगा, भले ही इसे कचरा संग्राहक द्वारा स्थानांतरित किया गया हो, और इसे सामान्य पॉइंटर की तरह ही उपयोग किया जा सकता है।

#include <QString>

#using <mscorlib.dll>
#include <vcclr.h>

using namespace System;

String *QStringToString(const QString &qstring)
{
    return new String((const wchar_t *)qstring.utf16());
}

QString StringToQString(String *string)
{
    const wchar_t __pin *chars = PtrToStringChars(string);
    return QString::fromWCharArray(chars);
}

तब कनवर्टर फ़ंक्शन को मूल C ++ वर्ग में फ़ंक्शन को कॉल करने के लिए रैपर क्लास कार्यान्वयन में उपयोग किया जा सकता है।

#include "networker.h"
#include "worker.h"
#include "tools.h"

netWorker::netWorker()
{
    workerObject = new Worker();
}

netWorker::~netWorker()
{
    delete workerObject;
}

कंस्ट्रक्टर और विध्वंसक बस C ++ ऑपरेटरों का उपयोग करके लिपटे हुए Qt ऑब्जेक्ट को बनाते और नष्ट करते हैं new और delete

String *netWorker::get_StatusString()
{
    return QStringToString(workerObject->statusString());
}

नेटवर्कर वर्ग प्रतिनिधि नेट कोड से नेटिव कोड पर कॉल करता है। यद्यपि उन दो दुनियाओं के बीच संक्रमण का अर्थ है प्रत्येक फ़ंक्शन कॉल के लिए एक छोटा प्रदर्शन हिट, और प्रकार रूपांतरण के लिए, यह नगण्य होना चाहिए क्योंकि हम वैसे भी सीएलआर के भीतर चलने वाले हैं।

void netWorker::set_StatusString(String *string)
{
    workerObject->setStatusString(StringToQString(string));
    __raise statusStringChanged(string);
}

प्रॉपर्टी सेटर __raise कीवर्ड का उपयोग करके इवेंट को फायर करने से पहले देशी Qt वर्ग को कॉल करता है।

इस रैपर क्लास को अब .NET कोड में इस्तेमाल किया जा सकता है, जैसे कि C ++, C #, विजुअल बेसिक या .NET के लिए उपलब्ध किसी अन्य प्रोग्रामिंग लैंग्वेज का उपयोग करना।

using System;

namespace WrapperApp
{
        class App
        {
                void Run()
                {
                        netWorker worker = new netWorker();

                        worker.statusStringChanged += new netWorker.__Delegate_statusStringChanged(onStatusStringChanged);

                        System.Console.Out.WriteLine(worker.StatusString);

                        System.Console.Out.WriteLine("Working cycle begins...");
                        worker.StatusString = "Working";
                        worker.StatusString = "Lunch Break";
                        worker.StatusString = "Working";
                        worker.StatusString = "Idle";
                        System.Console.Out.WriteLine("Working cycle ends...");
                }

                private void onStatusStringChanged(string str)
                {
                        System.Console.Out.WriteLine(str);
                }

                [STAThread]
                static void Main(string[] args)
                {
                        App app = new App();
                        app.Run();
                }
        }
}

वॉकथ्रू: .NET / COM इंटरॉप ActiveQt के साथ

सौभाग्य से .NET COM ऑब्जेक्ट, रनटाइम कॉल करने योग्य आवरण (RCW) के लिए एक सामान्य आवरण प्रदान करता है। यह RCW COM ऑब्जेक्ट के लिए एक प्रॉक्सी है और CLR द्वारा उत्पन्न होता है जब .NET फ्रेमवर्क क्लाइंट किसी COM ऑब्जेक्ट को सक्रिय करता है। यह .NET फ्रेमवर्क प्रोजेक्ट में COM ऑब्जेक्ट्स का पुन: उपयोग करने के लिए एक सामान्य तरीका प्रदान करता है।

COM ऑब्जेक्ट में एक QObject क्लास बनाना QObject साथ आसानी से प्राप्त किया ActiveQt और QAxServer उदाहरणों (जैसे, Simple उदाहरण) में प्रदर्शित होता है। वॉकथ्रू उन उदाहरणों में लागू क्यूटी वर्गों का उपयोग करेगा, इसलिए पहली बात यह सुनिश्चित करना है कि उन उदाहरणों को सही तरीके से बनाया गया है, उदाहरण के लिए इंटरनेट एक्सप्लोरर में प्रदर्शन पृष्ठों को खोलने के लिए यह सत्यापित करने के लिए कि नियंत्रण कार्यात्मक हैं।

एक परियोजना शुरू करना

Visual Studio.NET प्रारंभ करें, और Windows अनुप्रयोग लिखने के लिए एक नया C # प्रोजेक्ट बनाएँ। यह आपको विजुअल स्टूडियो के संवाद संपादक में एक खाली फॉर्म के साथ प्रस्तुत करेगा। आपको टूलबॉक्स देखना चाहिए, जो आपको विभिन्न श्रेणियों में उपलब्ध नियंत्रणों और वस्तुओं के साथ प्रस्तुत करता है। यदि आप टूलबॉक्स पर राइट-क्लिक करते हैं तो यह आपको नए टैब जोड़ने की अनुमति देता है। हम टैब "क्यूटी" जोड़ देंगे।

आयात क्यूटी विजेट

श्रेणी में केवल डिफ़ॉल्ट रूप से एक पॉइंटर टूल होता है, और हमें उन क्यूटी वस्तुओं को जोड़ना होता है जिन्हें हम अपने फॉर्म में उपयोग करना चाहते हैं। खाली जगह पर राइट-क्लिक करें, और "कस्टमाइज़" चुनें। यह एक डायलॉग खोलता है जिसमें दो टैब हैं, "COM कंपोनेंट्स" और ".NET फ्रेमवर्क कंपोनेंट्स"। हमने ActiveQt को COM ऑब्जेक्ट में लपेटने के लिए ActiveQt का उपयोग किया है, इसलिए हम "COM Components" पेज का चयन करते हैं, और उन कक्षाओं की तलाश करते हैं जिनका हम उपयोग करना चाहते हैं, जैसे "QPushButton" और "QAxWidget2"।

जब हम उन विजेट्स का चयन करते हैं और डायलॉग को बंद करते हैं तो दो विजेट अब टूलबॉक्स से उपलब्ध होंगे जैसे कि उनके नाम के साथ ग्रे वर्ग

क्यूटी विजेट का उपयोग करना

अब हम QAxWidget2 के एक उदाहरण और एक QPushButton को प्रपत्र में जोड़ सकते हैं। दृश्य स्टूडियो स्वचालित रूप से ऑब्जेक्ट सर्वर के लिए RCW उत्पन्न करेगा। QAxWidget2 का उदाहरण निचले दाएं कोने में QPushButton के साथ प्रपत्र के अधिकांश ऊपरी भाग को लेता है।

विजुअल स्टूडियो के संपत्ति संपादक में हम अपने नियंत्रणों के गुणों को संशोधित कर सकते हैं - QWidget API को उजागर करता है और इसमें कई गुण होते हैं, जबकि QAxWidget2 में "विविध" श्रेणी में अपनी संपत्ति "LineWidth" के अलावा केवल Visual Studio मानक गुण होते हैं। । ऑब्जेक्ट्स को "axQPushButton1" और "axQAxWidget21" नाम दिया गया है, और विशेष रूप से अंतिम नाम थोड़ा भ्रमित करने वाला है क्योंकि हम ऑब्जेक्ट्स को "रीसेटबटन" और "सर्कलवेटगेट" नाम देते हैं।

हम Qt गुणों को भी बदल सकते हैं, उदाहरण के लिए resetButton के "टेक्स्ट" प्रॉपर्टी को "रीसेट" में सेट करें, और सर्कलवेट की "लाइनविदथ" संपत्ति को 5. हम लेआउट सिस्टम में उन वस्तुओं को भी डाल सकते हैं जो विज़ुअल स्टूडियो के डायलॉग एडिटर हैं। प्रदान करता है, उदाहरण के लिए circleWidget के एंकर को "लेफ्ट, टॉप, राइट, बॉटम" और resetButton के एंकर को "बॉटम, राइट" पर सेट करके।

अब हम प्रोजेक्ट को संकलित और शुरू कर सकते हैं, जो हमारे दो क्यूटी विजेट्स के साथ एक यूजर इंटरफेस खोलेगा। यदि हम संवाद का आकार बदल सकते हैं, तो विजेट उचित रूप से आकार देगा।

हैंडलिंग क्यूटी सिग्नल

अब हम विजेट्स के लिए ईवेंट हैंडलर लागू करेंगे। circleWidget का चयन करें और संपत्ति संपादक में "ईवेंट" पृष्ठ का चयन करें। विजेट घटनाओं को उजागर करता है क्योंकि QAxWidget2 वर्ग की "StockEvents" विशेषता इसकी वर्ग परिभाषा में निर्धारित है। हम प्रत्येक क्लिक के लिए लाइन चौड़ाई बढ़ाने के लिए circleClicked लिए इवेंट हैंडलर circleClicked को लागू करते हैं:

                private void circleClicked(object sender, System.EventArgs e)
                {
                        this.circleWidget.lineWidth++;
                }

सामान्य तौर पर हम प्रपत्र में विजेट पर डबल क्लिक करके एक डिफ़ॉल्ट ईवेंट हैंडलर को लागू कर सकते हैं, लेकिन हमारे विजेट के लिए डिफ़ॉल्ट ईवेंट अभी परिभाषित नहीं हैं।

हम QPushButton द्वारा उत्सर्जित clicked सिग्नल के लिए एक इवेंट हैंडलर भी लागू करेंगे। ईवेंट हैंडलर resetLineWidth जोड़ें पर clicked ईवेंट में जोड़ें, और उत्पन्न फ़ंक्शन को कार्यान्वित करें:

                private void resetLineWidth(object sender, System.EventArgs e)
                {
                        this.circleWidget.lineWidth = 1;
                        this.resetButton.setFocus();
                }

हम संपत्ति को 1 पर रीसेट करते हैं, और विंडोज पर उपयोगकर्ता शैली को अनुकरण करने के लिए setFocus() स्लॉट को भी कहते हैं, जहां एक बटन पकड़ता है जब आप इसे क्लिक करते हैं (ताकि आप इसे फिर से स्पेसबार के साथ क्लिक कर सकें)।

यदि हम अब प्रोजेक्ट संकलित करते हैं और चलाते हैं तो हम उसकी लाइन चौड़ाई बढ़ाने के लिए सर्कल विजेट पर क्लिक कर सकते हैं, और लाइन चौड़ाई 1 पर सेट करने के लिए रीसेट बटन दबा सकते हैं।

सारांश

.NET दुनिया और Qt की मूल दुनिया के बीच एक सार्वभौमिक अंतर- ActiveQt पुल के रूप में ActiveQt का उपयोग करना बहुत आसान है, और यह बहुत सारे हस्तलिखित आवरण वर्गों को लागू करने के लिए अक्सर अनावश्यक बनाता है। इसके बजाय, अन्यथा पूरी तरह से क्रॉस-प्लेटफॉर्म Qt प्रोजेक्ट में QAxFactory कार्यान्वयन गोंद प्रदान करता है। .NET को RCW उत्पन्न करने की आवश्यकता है।

यदि यह पर्याप्त नहीं है, तो हम Microsoft द्वारा प्रदत्त C ++ एक्सटेंशन के लिए अपने स्वयं के रैपर कक्षाओं को लागू कर सकते हैं।

सीमाएं

ActiveQt का उपयोग करते समय सभी सीमाएं निहित हैं। इस तकनीक का उपयोग करते समय .NET के साथ ActiveQt का उपयोग ActiveQt जाता है, उदाहरण के लिए हम जिस एपीआई में उपयोग कर सकते हैं, वह केवल ActiveQt और COM द्वारा समर्थित हो सकता है। हालाँकि, क्योंकि इसमें QObject और QWidget उपवर्ग शामिल हैं। हम अपने किसी भी डेटाटाइप को QObject उपवर्ग में लपेट कर उसका API .NET को उपलब्ध करा सकते हैं। इसका सकारात्मक पक्ष प्रभाव यह है कि Qt स्क्रिप्ट का उपयोग करने के लिए Qt अनुप्रयोगों को स्वचालित करने के लिए और सामान्य रूप से COM क्लाइंट के लिए समान API स्वचालित रूप से उपलब्ध है।

"IJW" विधि का उपयोग करते समय, सिद्धांत रूप में केवल आवरण वर्गों और डेटा प्रकार रूपांतरण कार्यों को लिखने के लिए आवश्यक समय सीमा होती है।

प्रदर्शन के विचार

सीएलआर बाइटकोड से देशी कोड के हर कॉल का अर्थ है एक छोटा प्रदर्शन हिट, और आवश्यक प्रकार के रूपांतरण दो परतों के बीच मौजूद हर परत के साथ एक अतिरिक्त देरी का परिचय देते हैं। नतीजतन मिक्स .NET और देशी कोड के लिए हर दृष्टिकोण को विभिन्न दुनिया के बीच आवश्यक संचार को कम करने की कोशिश करनी चाहिए।

ActiveQt साथ तीन परतों को प्रस्तुत करता है - RCW, COM और अंत में ActiveQt - जेनेरिक Qt / ActiveQt /COM/RCW/.NET ब्रिज का उपयोग करते समय प्रदर्शन का दंड हाथ से तैयार किए गए JJ-आवरण वर्ग का उपयोग करते समय की तुलना में बड़ा होता है। निष्पादन की गति हालांकि उपयोगकर्ता इंटरफ़ेस में इंटरैक्टिव तत्वों को जोड़ने और संशोधित करने के लिए अभी भी पर्याप्त है, और जैसे ही Qt और C ++ का उपयोग करने का लाभ लागू होता है और प्रदर्शन महत्वपूर्ण एल्गोरिदम को देशी कोड किक्स में लागू करने और संकलित करने के लिए, ActiveQt बनाने के लिए एक वैध विकल्प बन जाता है। यहां तक ​​कि आपके एप्लिकेशन के गैर-विज़ुअल भागों को .NET तक पहुँचा जा सकता है।