Results 1 to 6 of 6

Thread: Implementing signals / slots

  1. #1
    Join Date
    Aug 2020
    Posts
    18
    Qt products
    Qt5

    Default Implementing signals / slots

    My ultimate goal is to have application controlling bluetooth equipped device - amateur radio.
    I have working standard main window template with tab widget.
    I have successfully cloned and have working qtconncetivinty / btsanner example.


    I need help putting these together, especially how to add btscanner class to the main class.

    Basically how to physically add / modify btscaner application to main application - as a class.

    Here is my standard main code

    Qt Code:
    1. #include "mainwindow.h"
    2. #include <QApplication>
    3.  
    4. int main(int argc, char *argv[])
    5. {
    6. QApplication a(argc, argv);
    7. MainWindow w;
    8.  
    9. w.show();
    10.  
    11. return a.exec();
    12. }
    To copy to clipboard, switch view to plain text mode 


    Here is btsanner main
    Qt Code:
    1. #include "device.h"
    2.  
    3. #include <QApplication>
    4.  
    5. int main(int argc, char *argv[])
    6. {
    7. QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    8.  
    9. QApplication app(argc, argv);
    10.  
    11. DeviceDiscoveryDialog d;
    12. QObject::connect(&d, SIGNAL(accepted()), &app, SLOT(quit()));
    13. d.show();
    14.  
    15. app.exec();
    16.  
    17. return 0;
    18. }
    To copy to clipboard, switch view to plain text mode 

    Points of misunderstanding
    1. what is the purpose of this line ?
    QApplication::setAttribute(Qt::AA_EnableHighDpiSca ling);
    2. do I have to implement it when btscanner QDilog is added to main -> tab ?

    3. I have limited understanding of "connect" - I know how to implement it in simple ui control.
    I do understand how most of the btscanner slot/signals works.

    4. What is the purpose of this line of code AND how to implement it - in main window or tab ?
    QObject::connect(&d, SIGNAL(accepted()), &app, SLOT(quit()));

    My guess it allows to process "quit" button and quits entire btscanner application.

    I be happy to add additional info if needed.

    Many thanks for help.

  2. #2
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,689
    Thanks
    257
    Thanked 750 Times in 740 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: Implementing signals / slots

    Points of misunderstanding
    1. what is the purpose of this line ?
    QApplication::setAttribute(Qt::AA_EnableHighDpiSca ling);
    It is unnecessary. All it does is to tell Qt to use the full capability of high DPI (dots per inch) monitors (like 4K monitors) when scaling pixmaps to fit their windows.

    2. do I have to implement it when btscanner QDilog is added to main -> tab ?
    This is a two part question actually. No, you do not need to enable the high dpi scaling, but you can leave that line there with no harm if you want.

    The second part of the question is adding the DeviceDiscoveryDialog to the main window's tab widget. This probably will not work. Dialogs are meant to be stand-alone top level windows, not embedded inside a window owned by another window. So you can't just drop it down there and expect it to work properly.

    . I have limited understanding of "connect" - I know how to implement it in simple ui control.
    I do understand how most of the btscanner slot/signals works.

    4. What is the purpose of this line of code AND how to implement it - in main window or tab ?
    QObject::connect(&d, SIGNAL(accepted()), &app, SLOT(quit()));

    My guess it allows to process "quit" button and quits entire btscanner application.
    I suggest you read the section of Qt's documentation on signals and slots, which has an extensive description of how the process works. Google can tell you where that section is if you ask it about "Qt signals and slots".

    That particular connect() call does say that when the user clicks the "OK" button on the DeviceDiscoveryDialog widget (and the widget emits the "accepted() signal as a result), the application should quit. Another reason why you can't just drop the dialog into another app without modification.

    Personally, I think you might be a in little bit over your head in this thing. However, the Qt btscanner app has complete source code and everything is implemented in just two QDialog-based classes, DeviceDiscoveryDialog and ServiceDiscoveryDialog.

    So, starting with this source code, the first thing you do is to change DeviceDiscoveryDialog so that it inherits from QWidget instead of QDialog. This will enable you to add it to a tab in your MainWindow class.

    Next, remove the connect() with the accepted() signal. QWidget does not have such a signal, only QDialog. You will have to implement a QMenu item on your main window to exit the program instead.

    You should not have to change the ServiceDiscoveryDialog class. This is meant to pop up as a dialog whenever an item is selected from the device list.

    So simply changing the DeviceDiscoveryDialog class to a QWidget-based class and adding it to your tab widget should get you started with a semi-working app.

    Qt Code:
    1. // device.h
    2.  
    3. #include <QWidget> // <<<
    4.  
    5. QT_FORWARD_DECLARE_CLASS(QBluetoothDeviceDiscoveryAgent)
    6. QT_FORWARD_DECLARE_CLASS(QBluetoothDeviceInfo)
    7.  
    8. QT_USE_NAMESPACE
    9.  
    10. class DeviceDiscoveryWidget : public QWidget // <<<
    11.  
    12. // all the rest is the same
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. // device .cpp
    2.  
    3. DeviceDiscoveryWidget::DeviceDiscoveryWidget(QWidget *parent) // <<<
    4. : QWidget(parent), localDevice(new QBluetoothLocalDevice), // <<<
    5. ui(new Ui_DeviceDiscovery)
    6. {
    7.  
    8. // all the rest is the same
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. // device.ui
    2.  
    3. <?xml version="1.0" encoding="UTF-8"?>
    4. <ui version="4.0">
    5. <class>DeviceDiscovery</class>
    6. <widget class="QWidget" name="DeviceDiscovery">
    7. <property name="geometry">
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. // MainWindow constructor:
    2.  
    3. DeviceDiscoveryWidget * ddw = new DeviceDiscoveryWidget(); // Note the name change.
    4. tabWidget->addTab( ddw, "Device Discovery" );
    To copy to clipboard, switch view to plain text mode 

    You can edit "device.ui" using an ordinary text editor to change the QDialog to QWidget in the 4th line.

    Your main.cpp file (where you create you MainWindow) does not change at all.

    At some point you will probably want to make the DeviceDiscoveryWidget pointer a member of your MainWindow class, because it is likely that you will want to add signals or other features to the class, and you'll need to be able to access from your MainWindow class.
    Last edited by d_stranz; 28th August 2020 at 17:40.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  3. #3
    Join Date
    Aug 2020
    Posts
    18
    Qt products
    Qt5

    Default Re: Implementing signals / slots

    Thanks.
    I did not realize that QDialog should not be used the way I am using it.
    Changing the class to QWidget is a great idea, appreciate that.
    Appreciate all your help.

    Yes, ever since i started playing around with bluetooth I am WAY , WAY over my head.

    There is always some quirk with bluetooth.
    For example - btscanner works fine, BUT once the nearby device is discovered and subsequently removed -
    btsanner will continue to "detect " it. (It looks as the "detection" is retrieved from some data source, not actual "bluez" operation.)

    The "pairing" attempt brings up a "progress" dialog . That is OK, but it is NOT btscanner dialogue - but OS bluetooth manger's.

  4. #4
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,689
    Thanks
    257
    Thanked 750 Times in 740 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: Implementing signals / slots

    Well, I don't know anything about bluetooth technology, but I can put together Qt UI apps.

    It might be a good start for you to understand how the btscanner example works and to make changes to it, but if you really want to build your own app, you probably will have to learn how the example works in detail and extract and adapt the parts you want. What I showed was essentially nothing more than enabling the dialog-based app to run as a widget instead.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  5. #5
    Join Date
    Aug 2020
    Posts
    18
    Qt products
    Qt5

    Default Re: Implementing signals / slots

    Follow-up questions, if I may ask.
    I am still not clear on relations between code ( header / cpp files) and associated x.ui.

    The btscanner builds some files and I like to just copy / modify the existing DeviceDiscoveryDialog to DeviceDiscoveryWidget.
    Got that partially working.

    If I copy device.ui to deviceWidget.ui how do I associate that with DeviceDiscoveryWidget ?

    I am going to test modify my MainWindow constructor to add new tab , BUT
    in general

    is it better to create / add tab form in QtDesigner instead ?

    I did try to copy entire form design and it sort of works , after the widgets are manually moved as desired.
    I think mixing form GUI and code is not the best idea.


    One more , but this may be to early to ask.
    The btscanner constructor has several "connect" function and it generally works.
    Signal / slot is not limited to one "connection".
    So if I add another connection using Edit signal / slot - which takes precedence ?
    Assuming of course they are logically OK.


    Added after 40 minutes:


    If I copy device.ui to deviceWidget.ui how do I associate that with DeviceDiscoveryWidget ?

    Silly - just let QtCreator build the relations using SAME file name .
    Last edited by anneranch; 29th August 2020 at 00:37.

  6. #6
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,689
    Thanks
    257
    Thanked 750 Times in 740 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: Implementing signals / slots

    is it better to create / add tab form in QtDesigner instead ?
    My preference is to use QtDesigner for simple widgets - a QDialog or a QWidget with display or edit controls only. Anything more complicated (like tabs, stack widgets, etc.) I build in C++ code. I do not use QtDesigner to add slot connections; I make them in code using connect() statements. I also do not use the "automatic" slot connection feature of the MOC compiler: If you declare a slot for a QPushButton's clicked() signal as "on_buttonName_clicked()", MOC will add code to automatically connect the button's "clicked" signal to that slot. If you later add a connect() manually, then the slot will be called twice for every click, giving you no end of headaches as you try to figure out why.

    So if I add another connection using Edit signal / slot - which takes precedence ?
    Every signal / slot connection is unique. When a QObject-based class instance "emits" the signal, all slots that are connected to it will be called in the order in which they were connected. More than one slot can be connected to the same object instance's signal. The same slot may be connected to different signals from the same or different objects. The same signal / slot pair can be connected more than once, which means the slot will be called that many times for the same signal (not something you usually want to happen).

    If I copy device.ui to deviceWidget.ui how do I associate that with DeviceDiscoveryWidget ?
    The UIC (UI compiler) compiles the filename.ui file into ui_filenamei.h . This file declares a class with the same name as the class defined in the UI file, with "Ui_" prefixed to it. Look in the device.ui file, you will see an element "<class>DeviceDiscovery</class>". The UIC takes this name and creates a class named "Ui_DeviceDiscovery" in the ui_device.h file. This class has a setupUi() method.

    For the DeviceDiscoverDialog class, you can see that "ui_device.h" is #included at the top of "device.h" and you can see a pointer variable Ui_DeviceDiscovery * ui" declared in the dialog class. In the DeviceDiscoveryDialog constructor, this variable is initialized with "ui( new Ui_DeviceDiscovery )" and later in the body of the constructor, this variable is used to execute the Ui class' "setupUi()" method. This builds the user interface that is shown at runtime.

    So this is the association you asked about. The UIC compiles the *.ui files and generates ui*.h files containing class definitions named after whatever class was declared in the ui file. This ui_filename.h file is #included in the header file for the QWidget-based class that uses that user interface, and a variable of the Ui_class type is declared in the QWidget class. Usually this is done by your development environment (eg. QtCreator) when you execute an "Add new Qt GUI class" operation.

    By convention, the user interface files are all named the same "device.h", device.cpp", "device.ui" just to eliminate confusion. But you can actually name them anything you want, as long as you #include the right files in the right places.

    One more wrinkle:

    There is also a MOC compiler (Meta Object Compiler). Any class that is derived from QObject (in other words, any class that implements signals and slots) must contain the Q_OBJECT macro at the top of the class definition. When you add a new QObject-based class using QtCreator (or Visual Studio with the Qt plugin) it automatically adds build instructions to run the MOC on your filename.h file. When you build your project, MOC runs on filename.h creating a moc_filename.cpp file, and adds that cpp file to the build also. The moc_filename.cpp class contains boilerplate code that implements any custom signals you have declared, as well as code to implement any automatic signal / slot connections. This .cpp file if compiled along with your own cpp files and linked together to form the entire executable.

    So, in the case of the DeviceDiscoveryDialog class, there are ultimately 5 files:

    - three files you create (device.h, device.cpp, and device.ui)
    - one file generated by UIC (ui_device.h)
    - one file generated by MOC (moc_device.cpp)

    If you poke around in your build directories, you should see all of these files. If you are curious, you can open these generated files in your source code editor to see what the boilerplate code looks like, but if you change it your changes will be erased the next time the file is generated.

    You use your C++ IDE to edit the ,cpp and .h files, QtDesigner to edit the .ui file, and the last two are created automatically each time the project is rebuilt.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

Similar Threads

  1. Replies: 2
    Last Post: 18th April 2013, 13:15
  2. Qt signals slots again
    By bmpix in forum Newbie
    Replies: 4
    Last Post: 6th December 2011, 20:54
  3. about signals and slots
    By Sandip in forum Qt Programming
    Replies: 9
    Last Post: 15th July 2008, 17:02
  4. Signals and Slots
    By merry in forum Qt Programming
    Replies: 4
    Last Post: 22nd February 2007, 09:11
  5. Signals and Slots in dll
    By ankurjain in forum Qt Programming
    Replies: 8
    Last Post: 29th March 2006, 09:12

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.