[solved] adding Qt to existing program



  • Hi -

    I've developed a small program in the Qt IDE. It's now to the point that I want to begin actually using Qt's GUI capabilities (if for no other reason than making debugging easier!) in the program.

    I've looked through the list of tutorials, both built into Creator and those online, but in this nearly overwhelming body of information, I can't find something that shows me what tools to use and how to get started displaying program values in a GUI. For right now, the GUI can be read-only.

    Can someone point me to a particular reference to get me started? If it just shows me how to display ONE variable, that'd be a good start.

    Thanks...



  • Try to create a new project in the QtCreator and choose a gui application. All needed files will create. The you can open the form and create a gui in the integrated designer. Now you have good base project. I hope I have understood you correct.



  • Start off simple and build up in complexity as you get more familiar with the widgets and other facilities at your disposal.

    Try making a trivial application that has a single window that shows a QLabel and a QLineEdit for example. To do this follow these simple steps:

    In qt-creator go to File->New File or Project...

    Choose Qt Gui Application and choose a name for it.

    Select the base class to be QWidget (leave the class name as Widget which is the default).

    The above will create you a simple project consisting of four files:

    • main.cpp
    • widget.h
    • widget.cpp
    • widget.ui

    We will edit the widget.ui file first so click on that and designer will switch to design mode and open up the file. You should see a blank widget. Now do this:

    Using the toolbox on the left, drag a Label onto the widget form

    Do similarly for a Line Edit and place it to the right of the Label. The exact position is not important.

    Click on the widget background so that both of your new widgets (the label and line edit) get deselected.

    In the toolbar at the top click on the "Lay out Horizontally" button or press Ctrl-H to add all widgets to a horizontal layout. The layout will take care of resizing your widgets for you if the parent widget's size changes.

    Double click on the Label and it will switch to edit mode. Change the text to "My name is:"

    Press Ctrl-S to save the form.

    Click on the Edit mode button in the left hand panel of creator to switch back to the text editor. You will probably see the raw xml content of the UI file at this point. Just close it we are done with it for now.

    Now open up the widget.h file and edit it so that it looks like this:

    @
    #ifndef WIDGET_H
    #define WIDGET_H

    #include <QWidget>

    namespace Ui {
    class Widget;
    }

    class Widget : public QWidget
    {
    Q_OBJECT

    public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

    void setName( const QString& name );
    QString name() const;
    

    private:
    Ui::Widget *ui;
    };

    #endif // WIDGET_H
    @

    Now edit the corresponding .cpp file to look like this:

    @
    #include "widget.h"
    #include "ui_widget.h"

    Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
    {
    ui->setupUi(this);
    }

    Widget::~Widget()
    {
    delete ui;
    }

    void Widget::setName( const QString& name )
    {
    ui->lineEdit->setText( name );
    }

    QString Widget::name() const
    {
    return ui->lineEdit->text();
    }
    @

    Finally edit main.cpp to this:

    @
    #include <QtGui/QApplication>
    #include "widget.h"

    int main(int argc, char *argv[])
    {
    QApplication a(argc, argv);
    Widget w;

    w.setName( "Slim Shady" );
    
    w.show();
    
    return a.exec&#40;&#41;;
    

    }
    @

    Now build and run the application. As you can see the main() function is very simple. All we do is create a QApplication and then a Widget (this is our custom widget that we layed out in designer and added custom behaviour to in code with the name() and setName() functions).

    We then call our custom setName function on the widget. This in turn gets a pointer to the QLineEdit widget that we placed on the form and calls the setText() function of QLineEdit.

    Finally we show the widget and enter the event loop by calling a.exec().

    Once you understand how this simple app works then you can start adding some more bells and whistles like signal/slot connections.

    Good luck!



  • Thanks for the detailed reply, Zap. I followed your detailed instructions and it worked like a charm.

    Now, I'd like to face the task of adding Qt functionality to an existing application. Since I can't do the "File->New File or Project…" command (since it's not new), I'm not sure how to go about this.

    Again, I'm willing to start small. If I could have a display like this widget program, but instead of the editable name field, I had a single numeric field that displayed the value of one integer variable in my program...I'd consider that a pretty good start. (Of course, the next thing I'll want to is have that variable display automatically updated whenever the variable changes; I bet that's a bit more work.)

    So...how can I do this? Should I just import the widget stuff into my existing program, or is there a semi-automated way to do it?

    Thanks again.



  • Can you provide us with some more details please. What you want to achieve sounds easy enough but I do not understand enough about your existing project.

    Is your project developed in qt-creator? Does it use qmake as the build system or something else (e.g. cmake)?

    Where does your updating data come from? Are you calculating it or getting it from a network connection etc?

    Do you have a QObject sub-class that performs the data updates (from whatever source)? If so then all we need to do is to add a signal to this class that gets emitted whenevr your variable changes. something like:

    @
    class MyClass : public QObject
    {
    Q_OBJECT
    public:
    MyClass() : m_data( 0.0 ) {}

    public slots:
    void calculateNewData()
    {
    // do soemthng useful here
    m_data = ...

        // Let the world know about our new data
        emit dataChanged( m_data )
    }
    

    signals:
    void dataChanged( double val );

    private:
    double m_data;
    };
    @

    Then in you custom widget/dialog add a QDoubleSpinBox widget instead of a line edit and then somewhere that knows about both the data class and your widget make a signal/slot connection:

    @
    connect( myData, SIGNAL( dataChanged( double ) ), widget, SLOT( setValue( double ) ) );
    @

    Now, whenever the MyClass object calls calculateNewData() it will get the new data and emit the signal valueChanged( double ) where the argument is the value of your new data. Since we have connected this signal up to a slot that updates the GUI, it will be updated to reflect the latest value.

    Of course you are not limited to passing single values in a signal if you have a lot of data changing. This is just an example so that you can see how signals/slots are used.

    You could of course go one step further and use a QTimer and another signal/slot connection to automatically call the calculateNewData() function on a regular basis.

    Good luck!



  • Is your project developed in qt-creator? Does it use qmake as the build system or something else (e.g. cmake)?

    Yes, and yes.

    Where does your updating data come from? Are you calculating it or getting it from a network connection etc?

    For now, let's restrict this to data that is internally calculated.

    Do you have a QObject sub-class that performs the data updates (from whatever source)? If so then all we need to do is to add a signal to this class that gets emitted whenever your variable changes. something like:

    No, I don't have any QObjects defined. This is currently a vanilla C++ program. Should I modify my program to create and use a QObject?



  • OK then let's modify last night's exampe to do something more along the lines of what you need.

    We'll start by adding in a simple class that generates some data in response to a function call. Go to File->New file or project...->C++ class. Enter a name for the class of Generator and choose QObject as the base class.

    Edit the files for this class to look like this:

    generator.h
    @
    #ifndef GENERATOR_H
    #define GENERATOR_H

    #include <QObject>

    class Generator : public QObject
    {
    Q_OBJECT
    public:
    explicit Generator( QObject* parent = 0 );

    public slots:
    void calculateNextValue();

    signals:
    void dataChanged( double value );

    private:
    int m_n;
    };

    #endif // GENERATOR_H
    @

    generator.cpp
    @
    #include "generator.h"

    Generator::Generator( QObject* parent ) :
    QObject( parent ),
    m_n( 0 )
    {
    }

    void Generator::calculateNextValue()
    {
    ++m_n;
    double value = m_n * m_n;
    emit dataChanged( value );
    }
    @

    As you can see this is a very simple class. Each time a call to calculateNextValue() is made it simply increments a counter and calculates the square if it. This value is then broadcast to the world via the dataChanged() signal which is declared in the header file in the "signals:" section.

    This is where you would integrate your existing calculation code.

    Now to get this to play nicely with our GUI. Since we are only going to be displaying read-only data I have simply deleted the line edit from our Widget using the design mode. I have then changed the Widget header file to look like this:

    @
    #ifndef WIDGET_H
    #define WIDGET_H

    #include <QWidget>

    namespace Ui {
    class Widget;
    }

    class Generator;

    class QTimer;

    class Widget : public QWidget
    {
    Q_OBJECT

    public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

    public slots:
    void setValue( double value );

    private:
    Ui::Widget ui;
    QTimer
    m_timer;
    Generator* m_generator;
    };
    @

    Here you can see I have replaced the old string-based function with a new slot called setValue() that accepts a double as an argument.

    I have also declared as member variables, pointers to a QTimer and an object of our new Generator class.

    The corresponding .cpp file now looks like this:

    @
    #include "widget.h"
    #include "ui_widget.h"

    #include "generator.h"

    #include <QTimer>

    Widget::Widget( QWidget* parent ) :
    QWidget( parent ),
    ui( new Ui::Widget ),
    m_timer( new QTimer( this ) ),
    m_generator( new Generator( this ) )
    {
    ui->setupUi( this );

    // Use a couple of connections to do something useful.
    
    // This one causes new data to be calculated once a second (once the timer is started)
    connect( m_timer, SIGNAL( timeout() ), m_generator, SLOT( calculateNextValue() ) );
    
    // This one causes the new data to update the GUI
    connect( m_generator, SIGNAL( dataChanged( double ) ), this, SLOT( setValue( double ) ) );
    
    // Start the timer off to kick things into motion
    m_timer->start( 1000 );
    

    }

    Widget::~Widget()
    {
    delete ui;
    }

    void Widget::setValue( double value )
    {
    QString s = QString( "The current value is %1" ).arg( value );
    ui->label->setText( s );
    }
    @

    In the constructor we create a QTimer and a Generator object. Note that we pass through "this" to the constructors. This has the effect of making these object schildren of our Widget object which in turn means that we do not need to worry about deleting them explicitly since QObject (and hence our Widget) class automatically deletes its QObject-based children when it is destroyed.

    Then in the constructor we use a couple of signal-slot connections to make our objects interact with each other.

    First of all we want our Generator object to calculate a new value at regular intervals of 1s say. To do this we connect the "timeout()" signal of the QTimer object to the "calculateNextValue()" slot of the Generator object.

    That gets our data calculated but it is not yet enough to make our GUI reflect it in the window. To do so we need a second signal. This time we connect the "dataChanged()" signal of the Generator object to the "setValue()" slot of the Widget class.

    Finally in the constructor we start the timer off such that it emits signals at intervals of 1000ms (1s).

    In the implementation of the Widget::setValue( double value ) function, we simply use QString::arg() to construct a suitable string for display and then tell the QLabel to show that string. Simple! ;-)

    Now when you build and run the app you should see a label showing the sequence of square numbers being updated at a rate of 1 per second.

    Does that help you get closer to what you wish to accomplish?

    I recommend that you have a read up on signals/slots in the Qt docs and also have a look at the tutorials/examples/demos that ship with Qt.

    Good luck!



  • Hey ZapB,

    Perhaps you could use the very clear descriptions you wrote above to make a very simple "Qt Ui Basics" Tutorial, or something like that?



  • Yeah I will try to do that. I'll make some screenshots as I go along too. Good idea.



  • Hey, Zap -

    Thanks a ton for this information. I will hopefully have a chance to play with it tomorrow, and I imagine I'll come back with some more questions.



  • No problem. I just noticed that I forgot to post the modified main.cpp. It is a simple modification though, just remove the call to w.setName(). The rest is the same.



  • OK, I've made the changes you outline above, and I tried to build. I'm getting a curious error (probably not germane to this thread): "the build directory needs to be at the same level as the root directory." I did move the files, but I thought I kept the directory structures intact. Any idea what this is?

    Once I get this built, I'll step through it and re-read your explanations above.

    EDIT: don't sweat this; I just nuked the project files and re-generated them. I think it's OK now. Time to start watching this work.



  • OK...I have a few questions. Hopefully, the answers to these will also be of use in preparing your introductory tutorial.

    I notice we had a few choices when we selected widget for our base class. What is a good working definition of a widget (for Qt purposes), and why did we choose it for this example?

    I don't really understand the syntax of widget.cpp, line 30. It appears you're making a new variable called s, but what does the first pair of parens contain? Is this some kind of compound function call?

    what controls the position and format of the output in the GUI window?

    if I wanted to add a pause button, how would I go about that? (this question is mostly out of curiosity, so don't spend a lot of time on it.)

    can you explain the return a.exec(); in main.cpp? It seems like this is where the program spends all of its time, and I think I need to know more about this if I'm going to successfully decouple my main program from its auxiliary GUI.

    Thanks!



  • [quote author="mzimmers" date="1300743352"]# I notice we had a few choices when we selected widget for our base class. What is a good working definition of a widget (for Qt purposes), and why did we choose it for this example?
    [/quote]

    A widget is just a collection of GUI elements, together with its internal logic (eg. the code that increases the value if you click on the up-arrow of a spin box widget). A widget can be displayed as a single toplevel window (like in the hello world examples) or can be embedded in other widgets to construct more complex user interfaces.

    Dialoges, MainWindows and the like are more specialized widgets. A dialog, for example, is intended to be shown as its own top level window, but not to be embedded into another user interface. The same holds for main windows which contain a menu bar, a tool bar and other goodies by default.

    To start with a widget in an example is just for simplicity :-)

    [quote author="mzimmers" date="1300743352"]# I don't really understand the syntax of widget.cpp, line 30. It appears you're making a new variable called s, but what does the first pair of parens contain? Is this some kind of compound function call?
    [/quote]

    You mean this on line 35:

    @
    QString s = QString( "The current value is %1" ).arg( value );
    @

    <pre>QString( "The current value is %1" )</pre> is the constructor of a new QString object. It's the call for a value of the object (= allocation on the stack), in contrast to creating an object on the heap with new xxx. Subsequently you call method arg() on that newly created object. The resulting string is eventually assigned to variable s.

    [quote author="mzimmers" date="1300743352"]# what controls the position and format of the output in the GUI window?
    [/quote]

    The position of a new toplevel window is usually the center of the screen (or the centered over the parent window if, for example, a QDialog has a parent). The size is calculated by the layout and respects the size of the parts of the widget (sizeHint etc.)

    [quote author="mzimmers" date="1300743352"]# if I wanted to add a pause button, how would I go about that? (this question is mostly out of curiosity, so don't spend a lot of time on it.)
    [/quote]

    You would add the button in Qt Designer (or the designer component of Qt Creator). It depends on the actual layout of your existing UI if you just drop the button on the right place or if you have to break the layout and re-layout things afterwards. Just play around, you'll get a feeling for this very soon. It lasts longer to describe it textually :-)

    [quote author="mzimmers" date="1300743352"]# can you explain the return a.exec(); in main.cpp? It seems like this is where the program spends all of its time, and I think I need to know more about this if I'm going to successfully decouple my main program from its auxiliary GUI.

    Thanks![/quote]

    Every Qt GUI application has a so called event loop. It is responsible to receive all the events from the user (mouse moves and clicks, keyboard and all this) and to activate the appropriate actions on the application's GUI elements. exec() is just the method that starts the event loop. It only returns, when the event loops is stopped, which usually only happens when your program terminates.



  • [quote author="mzimmers" date="1300743352"]

    I notice we had a few choices when we selected widget for our base class. What is a good working definition of a widget (for Qt purposes), and why did we choose it for this example?

    [/quote]

    QWidget is the base class of graphical elements of GUI applications. Technically you can also use other approaches but they are for later examples (QGraphicsView or QML if you want to read up on them).

    I chose QWidget here for simplicity so as not to muddy the waters with other facilities provided by QDialog or QMainWindow. QWidget keeps it as simple as it gets.

    [quote author="mzimmers" date="1300743352"]

    I don't really understand the syntax of widget.cpp, line 30. It appears you're making a new variable called s, but what does the first pair of parens contain? Is this some kind of compound function call?

    [/quote]

    As you say it creates a variable called "s". This is assigned a value constructed on the right hand side of the "=" operator. The construction uses the QString::arg() function. This allows you to specify a template string with placeholders "%1, %2, etc) which are then substituded fo the values in the .arg() function. So this line just substitutes in your computed value.

    [quote author="mzimmers" date="1300743352"]

    what controls the position and format of the output in the GUI window?

    [/quote]

    The position of th elabel within the window is determined by the layout that we assigned ot the form in design mode. The position of the window is determined by the window manager since we did not explicitly specify a position.

    The format of the string is determined by the way we constructed the variable "s" (see above).

    [quote author="mzimmers" date="1300743352"]

    if I wanted to add a pause button, how would I go about that? (this question is mostly out of curiosity, so don't spend a lot of time on it.)

    [/quote]

    As Volker said add a push button in design mode. Then make a connection from the QPushButton's "clicked()" signal to a slot in your Generator object that toggles the running of the timer.

    [quote author="mzimmers" date="1300743352"]

    can you explain the return a.exec(); in main.cpp? It seems like this is where the program spends all of its time, and I think I need to know more about this if I'm going to successfully decouple my main program from its auxiliary GUI.

    [/quote]

    Volkr has already explained this. This is where GUI programming differs from simple functional programming. In GUI's events are handled by the event loop which is encapsulated by the a.exec() call. No event loop would mean that nothing happens - including painting your GUI, generation of the timer events that drive your calculation etc.



  • OK, I'm back. (Had to chase down some bugs for a couple of days.)

    So, regarding this "event loop" -- it seems to be a member function of QWidget, right? I'm curious...what throttles it? I assume it doesn't just run open loop.

    Also...what happens to my main()? In my main, besides initializing some variables, I have a loop that calls a function. Does this functionality become a function that is passed to the event loop by a connect()?

    Let's say I just want to imbed my current program into a Qt application. For right now, I don't even need to create a GUI; I just want to get my program logic contained within the Qt constructs. Do I create a loop function, and use a connect() call to access it?

    And...what's the best source of online documentation for this? The help stuff in Creator seems to have some dead links.

    Thanks.



  • It's always the same answer: It depends :-)

    If it is a program without GUI components and if you do not use signal/slot connections within the existing code, it is very likely that you do not need an event loop.

    It would be helpful if you could describe what you want to do by embedding the existing code into a Qt application environment.

    Some reading about events and the event loop is in:

    Signals/slots need a running event loop to work reliably.

    PS: If you stumble over dead links, please open a bug report, so that the Trolls can fix them for the next release.



  • Hi Volker,

    one correction regarding signals/slots:

    Afaik, they also work without an event loop, if you only use direct connections. This means in fact a syncronous execution of everything, nothing asynchronous, no user input (only via command line).



  • It would be helpful if you could describe what you want to do by embedding the existing code into a Qt application environment.

    I thought it might be a good first step, to help me understand the control flow of a Qt application, and where application code is supposed to "live," without actually getting into the nuts and bolts of the GUI yet. The long term plan is definitely to have an event loop.



  • [quote author="mzimmers" date="1301086103"]OK, I'm back. (Had to chase down some bugs for a couple of days.)
    [/quote]

    I'm back too now. Been offline whilst decorating...

    [quote author="mzimmers" date="1301086103"]
    So, regarding this "event loop" -- it seems to be a member function of QWidget, right? I'm curious...what throttles it? I assume it doesn't just run open loop.
    [/quote]

    exec() is a function of QCoreApplication (plus a few other classes QEventLoop, QDialog etc). The purpose of the event loop is to notice "events" (keypresses, mouse moves, window system damage events, network socket or file descriptor events) and translate these into events that can be handled within your Qt application. You normally do this by either overriding a virtual function such as QWidget::resizeEvent( QResizeEvent* e ) or by connecting to a convenient signal from a Qt class such as QIODevice::readyRead(). It depends upon what you are trying to do.

    [quote author="mzimmers" date="1301086103"]
    Also...what happens to my main()? In my main, besides initializing some variables, I have a loop that calls a function. Does this functionality become a function that is passed to the event loop by a connect()?
    [/quote]

    Not normally. There are a few approaches you can take. If the work can easily be split into small packages then you can simply use a timer to do a little bit of work at a time. A similar approach is to not use a timer bu tinstead call QCoreApplication::processEvents() every so often in your loop. Both of these approaches allow control to return to the event loop so that your GUI does not appear to freeze. Remember, whilst the main thread is busy doing your calculations it is not available to paint the screen or handle any other types of events.

    If you work is not easily broken up, or if you want to take advantage of multiple cores or processors then you should take a look at QThread or QtConcurrent. These allow you to move your heavy work to a separate thread (or threads) of execution, leaving the main thread free to update the GUI and handle other events in the event loop. Come back with more questions if you need help with this.

    [quote author="mzimmers" date="1301086103"]
    Let's say I just want to imbed my current program into a Qt application. For right now, I don't even need to create a GUI; I just want to get my program logic contained within the Qt constructs. Do I create a loop function, and use a connect() call to access it?
    [/quote]

    Take a look at the above options and this "Qt Quarterly article":http://doc.qt.nokia.com/qq/qq27-responsive-guis.html.

    [quote author="mzimmers" date="1301086103"]
    And...what's the best source of online documentation for this? The help stuff in Creator seems to have some dead links.
    [/quote]

    The "online documentation":http://doc.qt.nokia.com/latest/.

    Good luck!



  • exec() is a function of QCoreApplication (plus a few other classes QEventLoop, QDialog etc). The purpose of the event loop is to notice “events” (keypresses, mouse moves, window system damage events, network socket or file descriptor events) and translate these into events that can be handled within your Qt application. You normally do this by either overriding a virtual function such as QWidget::resizeEvent( QResizeEvent* e ) or by connecting to a convenient signal from a Qt class such as QIODevice::readyRead(). It depends upon what you are trying to do.

    OK, my main program is pretty simple. It initializes a few variables, and then goes into a loop. The loop will probably be infinite in production mode, but each instance should complete in well under a second.

    Let's say that I'd like to build a GUI for this that displays two values after each loop iteration. I'd probably put a minor delay in, just to prevent the GUI from updating so rapidly that it's hard to read. So...how do I go about this? Each variable needs its own widget, right? With most of the stuff that you have in widget.cpp above?

    Thanks.

    EDIT:

    Also...I've been looking through the online docs, and don't find an entry for emit. I also don't find an entry for dataChanged() which looks right for how you're using it. I DID find an entry for emitDataChanged(). Is the code you used pre 4.7?



  • [quote author="mzimmers" date="1301337361"]
    OK, my main program is pretty simple. It initializes a few variables, and then goes into a loop. The loop will probably be infinite in production mode, but each instance should complete in well under a second.

    Let's say that I'd like to build a GUI for this that displays two values after each loop iteration. I'd probably put a minor delay in, just to prevent the GUI from updating so rapidly that it's hard to read. So...how do I go about this? Each variable needs its own widget, right? With most of the stuff that you have in widget.cpp above?
    [/quote]

    As a first pass, I would try simply putting your existing code into the Generator class that we made earlier. In the calculateNextValue() function would be a good place. Refactor it so that this function only contains the body of your loop. We alreayd have this function being called in response to a timer.

    You can build up in complexity from there using one of the techniques that I described earlier. From what you have described, putting your infinite loop into a worker thread could well be the best approach. Then you can just emit your calculated values in a signal after a certain amount of time has elapsed (you can use QTime::start() and QTime::elapsed() to measure this).

    The way in which you display the results of your calculations is entirely up to you. If you just have a pair of doubles, then using a couple of QLabels would be a reasonable approach. If you had 1000 doubles then I would look at using something else, a QTableView for e.g.

    If you would like some more help in getting any of this to work then feel free to come back with more questions and we'll do what we can to help you. It doesn't sound like it will be particularly complicated.

    [quote author="mzimmers" date="1301337361"]
    EDIT:

    Also...I've been looking through the online docs, and don't find an entry for emit. I also don't find an entry for dataChanged() which looks right for how you're using it. I DID find an entry for emitDataChanged(). Is the code you used pre 4.7?[/quote]

    The "emit" keyword is just a macro that expands to nothing. It is just semantic sugar to make you think that a signal really is broadcast. In reality, the moc implements the body of the signal function for you.

    As for our signal, dataChanged(), this is just a signal that we invented for our custom Widget class so you will not find anything about it in the Qt docs.



  • OK, I'm going to start on this in a bit. My goal is to get something working today.

    Newbie question: what does refactoring do?



  • Refactoring just means modifying your existing code so that it works in a different context or is organised differently. In this case moving your loop code and adjusting it as described above.



  • OK, thanks. So, if I:

    bring generator and widget files into my existing project

    take all my stuff out of my main and put it into generator

    replace my main with the one you posted

    do the refactor thingie

    Is that on the right track?



  • OK, I've changed my approach slightly. I decided to create a class to contain all the stuff for my main routine. I've called this class Soc, and its only data members are an object of another class (Filter), and some control variables.

    Now I'm having some trouble getting the Soc constructor right. The Soc constructor needs to pass an argument to the Filter constructor. The problem is, Soc (like generator) inherits its constructor from the QObject class. As such, it isn't prepared to take any additional parameters (like the argument I want to pass).

    How can I form the Soc constructor so that I can pass an argument to the Filter constructor? Or, is there a better way of doing this?

    Thanks.

    EDIT:

    I think I resolved this problem by adding the Filter initialization to the Soc parameter initialization (did I word that correctly?):

    @#include "Soc.h"
    const int resetValue = 55;

    using namespace std;

    Soc::Soc(QObject *parent) :
    QObject(parent), filter(resetValue)
    {
    }
    @

    Now, I'm getting a symbol not found error:

    bq. Undefined symbols:
    "Soc::getCoeffs(int*, int*)", referenced from:
    Soc::runOneCycle() in Soc.o
    Soc::qt_metacall(QMetaObject::Call, int, void**)in moc_Soc.o
    ld: symbol(s) not found
    collect2: ld returned 1 exit status

    Is this somehow related to the fact that the calling routine (I've named it Soc::runOneCycle()) is defined as a public slot, and not an "ordinary" member function?

    EDIT 2:

    Aargh. Please ignore previous lame question. My fault for trying to work too fast. I'll come back when I have something legit.



  • OK...I've cleared the decks of my dumb mistakes (I think). I believe that I have now correctly implemented a class Soc, which contains a routine called runOneCycle() that replaces most of the functionality in my original main(). I now need to "hook it up" so it gets called. I guess the next step is to implement a version of the widget software that Zap posted above. Right now, I'd be happy if it ran 100 times, and showed the results of two variables after each running. (I have lots of plans for enhancing this, but this will do for now.)

    I won't need a timer (yet), so we can eliminate that part of the code. So...do I need just one connect statement? Or, do I need two, since I'm planning on displaying the values of two variables with the Soc class?

    Thanks...I think I'm slowly getting closer...



  • Are you able to post your code? If yes then please do, if not then we'll have to work with examples still. Not a problem either way...



  • I can post some extracts, which would hopefully be good enough. I removed some irrelevant stuff for brevity.

    Here's Soc.h:

    @#ifndef SOC_H
    #define SOC_H

    #include <QObject>
    #include <iostream>
    #include <fstream>
    #include <iomanip>
    #include "DemodShaperFilter.h"

    class Soc : public QObject
    {
    Q_OBJECT
    private:
    Filter filter; // Soc contains one filter for now.
    /*

    • clocks and resets.
      /
      bool clockEnable;
      bool clockState;
      // bool systemReset;
      bool filterReset;
      /
    • arguments to drive the filter processing.
      */

    int shaperCoeffI[NBR_CELLS];
    int shaperCoeffQ[NBR_CELLS];
    int combGainI;
    int combGainQ;
    int shaperOutI, shaperOutQ;

    public:
    explicit Soc(QObject *parent = 0);
    int getCoeffs(int *aI, int *aQ);

    signals:
    void dataChanged (double value);
    public slots:
    void runOneCycle();
    };
    #endif // SOC_H
    @

    And here's the .cpp file:

    @#include "Soc.h"
    const int resetValue = 55;

    //Soc::Soc(QObject *parent) :
    // QObject(parent)
    Soc::Soc(QObject *parent) :
    QObject(parent), filter(resetValue)
    {
    }

    void Soc::runOneCycle()
    {
    static int i=0;
    int rc;
    /*

    • test a single filter.
      */

    // temporarily use simple variables for comb stuff.

    combGainI = i;
    combGainQ = i*2;
    i++;

    systemClock.setClock(HIGH);
    filter.cycle(combGainI, // run the high cycle.
    shaperCoeffI,
    combGainQ,
    shaperCoeffQ,
    shaperOutI,
    shaperOutQ,
    clockEnable,
    filterReset);

    return;
    }
    @



  • So...I've added the widget files from the example above to my program, and changed m_generator to a Soc variable called (creatively enough) soc. The program runs, and produces the correct output (as displayed on the console), but I'm not getting anything in my GUI window.

    I believe I need to modify this line of code in widget.cpp:

    @ connect (soc, SIGNAL(dataChanged(double)), this, SLOT(setValue(double)));
    @

    I imagine I'd have to modify the doubles to ints, but...I need to tell it to look at my two variables. Do I:

    1. need two connect statements for this?
    2. replace "this" with soc.member-name?

    I guess I should also modify setValue to accept an int instead of a double, too.

    Thanks.



  • Thje connect is correct. But I fI look at your last code, where do you emit the signal?



  • Oops.

    I guess I need a emit dataChanged() call, don't I?

    So, my question now is...what do I put in as a parameter for this call? I guess this is the missing link to my understanding of how these signals work. (It also looks like I missed changing a double to int in the Soc.h file.)

    Thanks.



  • Hi,

    you have to put a double in, as specified in the header.
    Which one, I can't tell you, that's depending on your application.
    Typically, the value you want to notify :-)



  • So, I use a double in the call even if the variable I want to display is an int? What exactly does that double represent: I thought it was the variable I wanted to display...

    EDIT: I just put the dataChanged() call into my code, and it seems to work. Now, if I want to do this for two variables, what all do I have to duplicate? Obviously, I'll need two calls to dataChanged(), but what else do I have to do?

    Thanks.



  • Think a bit, how the Qt widgets to it.

    Look at QSpineBox:

    • it has a signal valueChanged(int) and sends the changed value.

    Look at QDoubleSpineBox:

    • it has a signal valueChanged(double) and sends the changed value.

    Look at QComboBox:

    • void activated ( int index )
    • void activated ( const QString & text )
      both signals are emitted, with different content.

    The client can connect to the signal he wants and has to interpret the values.

    You can do a dataChanged() signal and leave it to the client to query all values and check which ones are changed, or do a dataChanged1() and dataChanged2() so the client knows, which value but has to query the new value. or you do

    • dataChanged1(int)
    • dataChanged2(int)
      and deliver the new values to the client.

    But I would rename dataChanged1(int) to some senseful names.



  • Which values are you trying to have displayed and what are their types? If you are emitting a single double then the signal, slot and connect are fine.

    If you want to display 2 doubles then you need to modify:

    • The dataChanged() signal to have two double arguments ie

    @void dataChanged( double val1, double val2 );@

    • The Widget::setValue() function to accept a corresponding pair of doubles:

    @void setValue( double val1, double val2 );@

    • The connect to use the new signal/slot signatures:

    @connect (soc, SIGNAL(dataChanged(double,double)), this, SLOT(setValue(double,double)));@

    Then finally you actually need to emit your signal from your calculation function.

    If instead you are using int's then simply replace double for int in the above.



  • Thanks for the explanation, Gerolf...that does help.

    Zap: I wish to display two ints. I understand now that I have to replace the doubles with ints. Now that I'm displaying two variables (ints), what is the syntax for forming the output string? I tried this:
    @ QString s = QString("shaperOutI is %1. shaperOutQ is %2.").arg(shaperOutI, shaperOutQ);
    @
    But that gives no output at all. Do I need two separate strings? What if I wanted the output on separate lines?

    Thanks. I'll have some more questions when I finish waking up.



  • use this:

    @
    QString s = QString("shaperOutI is %1. shaperOutQ is %2.").arg(shaperOutI).arg(shaperOutQ);
    @



  • Gerolf has already shown you how to format the string. If you want it split over two lines then you need to include a "\n" in your string:

    @QString s = QString("shaperOutI is %1.\nshaperOutQ is %2.").arg(shaperOutI).arg(shaperOutQ);@

    You may need to set the wordWrap property of the QLabel to true too - I can't recall offhand.



  • Oh, this is OUTSTANDING. Thanks so much to everyone for their help in this thread. It may not seem like much to anyone else, but this is a major step forward for me.

    A final question about all this: can someone explain this line:

    @QString s = QString("shaperOutI is %1. shaperOutQ is 2.").arg(shaperOutI).arg(shaperOutQ);@

    What's going on with the consecutive .arg calls?

    I've got a ton of other questions now, but they're not apropos of this particular thread, so...I'll bundle them into a new thread. This one, I think we can mark solved (except I don't remember how to do that).

    Thanks again!


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.