GUI-based Qt applications

Returning to the Qt-based example project from Chapter 8, Example - Linux-Based Infotainment System, we can now compare its main function to the preceding command-line-only version to see what changes once we add a GUI to the project:

#include "mainwindow.h" 
#include <QApplication> 
 
int main(int argc, char *argv[]) { 
    QApplication a(argc, argv); 
    MainWindow w; 
    w.show(); 
     
    return a.exec(); 
} 

The most obvious change here is that we use QApplication instead of QCoreApplication. The other big change is that we do not use a completely custom class, but one that derives from QMainWindow:

#include <QMainWindow> 
 
#include <QAudioRecorder> 
#include <QAudioProbe> 
#include <QMediaPlayer> 
 
 
namespace Ui { 
    class MainWindow; 
} 
 
class MainWindow : public QMainWindow { 
    Q_OBJECT 
     
public: 
    explicit MainWindow(QWidget *parent = nullptr); 
    ~MainWindow(); 
     
public slots: 
    void playBluetooth(); 
    void stopBluetooth(); 
    void playOnlineStream(); 
    void stopOnlineStream(); 
    void playLocalFile(); 
    void stopLocalFile(); 
    void recordMessage(); 
    void playMessage(); 
     
    void errorString(QString err); 
     
    void quit(); 
     
private: 
    Ui::MainWindow *ui; 
     
    QMediaPlayer* player; 
    QAudioRecorder* audioRecorder; 
    QAudioProbe* audioProbe; 
     
    qint64 silence; 
     
private slots: 
    void processBuffer(QAudioBuffer); 
}; 

Here, we can see that the MainWindow class indeed derives from QMainWindow, which also gives it its show() method. Of note is the MainWindow instance being declared in the UI namespace. This is connected to the auto-generated code that is created when we run the qmake tool on the UI file, as we will see in a moment. Next is the constructor:

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

The first thing of note here is how we inflate the GUI from the UI description file. This file is usually created by visually laying out the GUI with the Qt Designer tool, which is part of the Qt Creator IDE. This UI file contains a description of each widget's properties, along with the layout applied to them, and so on.

It's also possible to programmatically create these widgets and add them to layouts, of course. This gets quite tedious for larger layouts, however. Generally, you create a single UI file for the main window, and an additional one for each sub window and dialog. These can then be inflated into a window or dialog in a similar fashion:

    connect(ui->actionQuit, SIGNAL(triggered()), this, SLOT(quit())); 

Menu actions in the GUI are connected to internal slots by specifying the specific signal on the menu action (QAction instance). We can see here that they are in the ui object, which is found in the auto-generated source code for the UI file, as we mentioned earlier:

    connect(ui->playBluetoothButton, SIGNAL(pressed), this, SLOT(playBluetooth)); 
    connect(ui->stopBluetoothButton, SIGNAL(pressed), this, SLOT(stopBluetooth)); 
    connect(ui->playLocalAudioButton, SIGNAL(pressed), this, SLOT(playLocalFile)); 
    connect(ui->stopLocalAudioButton, SIGNAL(pressed), this, SLOT(stopLocalFile)); 
    connect(ui->playOnlineStreamButton, SIGNAL(pressed), this, SLOT(playOnlineStream)); 
    connect(ui->stopOnlineStreamButton, SIGNAL(pressed), this, SLOT(stopOnlineStream)); 
    connect(ui->recordMessageButton, SIGNAL(pressed), this, SLOT(recordMessage)); 
    connect(ui->playBackMessage, SIGNAL(pressed), this, SLOT(playMessage)); 

Button widgets in the GUI are connected in a similar manner, though they of course emit a different signal on account of them being a different type of widget:

    silence = 0; 
     
    // Create the audio interface instances. 
    player = new QMediaPlayer(this); 
    audioRecorder = new QAudioRecorder(this); 
    audioProbe = new QAudioProbe(this); 
     
    // Configure the audio recorder. 
    QAudioEncoderSettings audioSettings; 
    audioSettings.setCodec("audio/amr"); 
    audioSettings.setQuality(QMultimedia::HighQuality);     
    audioRecorder->setEncodingSettings(audioSettings);     
    audioRecorder->setOutputLocation(QUrl::fromLocalFile("message/last_message.amr")); 
     
    // Configure audio probe. 
    connect(audioProbe, SIGNAL(audioBufferProbed(QAudioBuffer)), this, SLOT(processBuffer(QAudioBuffer))); 
    audioProbe→setSource(audioRecorder); 

We're free to do anything we would do in any other constructor, including setting defaults and creating instances of classes we will need later on:

    QThread* thread = new QThread; 
    VoiceInput* vi = new VoiceInput(); 
    vi->moveToThread(thread); 
    connect(thread, SIGNAL(started()), vi, SLOT(run())); 
    connect(vi, SIGNAL(finished()), thread, SLOT(quit())); 
    connect(vi, SIGNAL(finished()), vi, SLOT(deleteLater())); 
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); 
     
    connect(vi, SIGNAL(error(QString)), this, SLOT(errorString(QString))); 
    connect(vi, SIGNAL(playBluetooth), this, SLOT(playBluetooth)); 
    connect(vi, SIGNAL(stopBluetooth), this, SLOT(stopBluetooth)); 
    connect(vi, SIGNAL(playLocal), this, SLOT(playLocalFile)); 
    connect(vi, SIGNAL(stopLocal), this, SLOT(stopLocalFile)); 
    connect(vi, SIGNAL(playRemote), this, SLOT(playOnlineStream)); 
    connect(vi, SIGNAL(stopRemote), this, SLOT(stopOnlineStream)); 
    connect(vi, SIGNAL(recordMessage), this, SLOT(recordMessage)); 
    connect(vi, SIGNAL(playMessage), this, SLOT(playMessage)); 
     
    thread->start(); 
} 

One crucial thing to remember here is that this class runs on the UI thread, meaning that we should not do anything intensive in here. That's why we move such class instances off to their own thread, as shown here:

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

In the constructor, we delete the UI and all associated elements.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.5.239