How usable is Qt without its preprocessing step?

后端 未结 12 788
自闭症患者
自闭症患者 2021-02-02 05:21

I think it\'s unreasonable for a library to require preprocessing of my source code with a special tool. That said, several people have recommended the Qt library to me for cros

相关标签:
12条回答
  • 2021-02-02 05:52

    I have a solution, that is not super-clean and not 100% satisfactory, but that allows to connect Qt signals to your own code without having to use the MOC compiler (I had exactly the same constraint as in the question, i.e. not able to run the MOC compiler in the building process of my application).

    To be able to capture Qt signals without using MOC, I am using the following tricks:

    (1) get the definition of QMetaCallEvent (copy it from ): In Qt 5.x, you will have something like:

    class QMetaCallEvent : public QEvent {
    public:
        inline int id() const {
            return method_offset_ + method_relative_;
        }
    
        virtual void placeMetaCall(QObject *object);
    
    private:
        QMetaCallEvent();
        void* slotObj_;
        const QObject *sender_;
        int signalId_;
        int nargs_;
        int *types_;
        void **args_;
        void *semaphore_;
        void *callFunction_;
        ushort method_offset_;
        ushort method_relative_;
    };
    

    (2) In your widget class that needs to capture Qt signals, you will inherit from a Qt widget (say QButton), and define the following function:

    // Inspired by QObject::connect() in src/corelib/kernel/qobject.cpp
    bool connect_sender(
        const QObject* sender, const char* signal, int method_index
    ) {
    
            // We need to generate MetaCall events (since QObject::event()
            //   is the only virtual function we can overload)
            // (note that the other connection types do not generate events).
            Qt::ConnectionType type = Qt::QueuedConnection ;
    
            if(sender == 0 || signal == 0) {
                std::cerr << "null sender or signal" << std::endl ;
                return false ;
            }
    
            QByteArray tmp_signal_name;
            const QMetaObject *smeta = sender->metaObject();
            ++signal; //skip code
            int signal_index = smeta->indexOfSignal(signal);
            if (signal_index < 0) {
                // check for normalized signatures
                tmp_signal_name = 
                    QMetaObject::normalizedSignature(signal).prepend(*(signal - 1));
                signal = tmp_signal_name.constData() + 1;
                signal_index = smeta->indexOfSignal(signal);
                if (signal_index < 0) {
                    std::cerr << "Signal \'" << signal << "\' not found" 
                              << std::endl ;
                    return false;
                }
            }
    
            int *types = 0;
    
            QMetaObject::connect(
                sender, signal_index, this, method_index, type, types
            ) ;
    
            return true ;
        }
    

    (3) overload the event() function:

    bool event(QEvent* e) {
        if(e->type() == QEvent::MetaCall) {
            QMetaCallEvent* ev = static_cast<QMetaCallEvent*>(e);
            switch(ev->id()) {
                // insert your handling code here
            }  
            return true;
        }
        return QObject::event(e) ;
    }
    

    Now, if you call connect_sender(qobject, signal_name, method_index), this will call event() each time the signal is fired, with the specified method_index retrieved in ev->id().

    Important note: I have been using this trick in my application for several years, it works quite well, but it is not very clean. One of the consequences is that whenever the definition of QMetaCallEvent changes, you need to edit your declaration accordingly (unfortunately it is not exposed in the header files of Qt).

    0 讨论(0)
  • 2021-02-02 05:55

    You can use Qt without the moc, but then you lose certain functions, especially those that make Qt interesting in the first place (such as most of the GUI stuff, signals and slots, and string translation). But it's still a nice general purpose library, even without moc.

    0 讨论(0)
  • 2021-02-02 06:01

    I really can't think of anything so unique and useful with Qt without using QObjects. I wish they worked their way around that pre-compilation step.

    0 讨论(0)
  • 2021-02-02 06:04

    Qt doesn't require the use of moc just to use it, it requires that usage if you create a subclass of QObject, and to declare signals and slots in your custom classes.

    It's not unreasonable, moc provides features that C++ doesn't have, signals/slots, introspection, etc.

    So, to do something minimally advanced, you WILL have to use the moc preprocessor. You either love it, or hate it.

    0 讨论(0)
  • 2021-02-02 06:04

    It's completely usable now. The maintainer of moc has made an alternative with slightly more verbose syntax than ordinary Qt, but it uses standard C++14 so there's no extra step.

    It's called 'Verdigris'

    (as an aside, moc isn't really a preprocessing step so much as a code generator. The code you write is valid C++, and moc doesn't change any of it. It just generates extra C++ code for you.)

    0 讨论(0)
  • 2021-02-02 06:04

    If you just need to connect to signals coming from Qt objects, a hack solution is to utilize existing QT objects that have public or protected virtual slots that match the signature of the signal you want to connect to. You can subclass the QT object and re-implement the virtual slot as a proxy to perform whatever action you need to when the QT signal is emitted. E.g.,

    class SignalProxy : public QWidget
    {
    public:
      SignalProxy() {}
    
      void setVisible( bool isVisible )
      {
         // Do whatever you want to do when the signal is emitted.
      }
    };
    
    
    // code to connect the signal, e.g., to a QWebView object
    SignalProxy proxy;
    QWebView webview;
    QObject::connect( &webview, SIGNAL(loadFinished(bool)),
            &proxy, SLOT(setVisible(bool)) );
    

    It's not pretty but it gets the job done. If you were really intent on doing without the MOC you could probably locate existing Qt objects to use as proxies for just about any signal signature you need, e.g., the QAbstract... classes have lots of virtual slots, and you could hide all that nastiness in a library that provides a boost signals or tr1::function<> style API for connecting to QT signals.

    Calling slots on QT objects is less of a concern than receiving signals, since you can generally invoke the slot method directly.

    0 讨论(0)
提交回复
热议问题