Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Mobile and Embedded
  4. Running application in Android reduced functionalities for QList

Running application in Android reduced functionalities for QList

Scheduled Pinned Locked Moved Unsolved Mobile and Embedded
24 Posts 6 Posters 2.1k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    AdrianLV
    wrote on last edited by
    #1

    Hello there,

    I am creating an application that will search for bluetooth devices and then connect to one sensor of mine and display the sensor data. I have my main widget, and the search of the devices happens in a second widget. I built my application first with MSVC2019 and in my Computer(Windows 11) it can do everything (I have the Qt6.7 version).

    Now, I tried to run it in my Android device(With Clang arm64-v8a), but there are some features that are not working as they were in the desktop app. I also tried setting a list in the MainWidget, but I have the same problems. The main one is the QList:

    • When I press on my button, nothing happens, it should be clearing the list and adding a new item.
    • I simply can not select any items.
    • My layout makes everything go to the left after opening the widget

    I am sure it will be something really basic. But I am blocked and have absolutely no idea what to do. I tried to repaint the widget, to process the events and to update. None of these work.

    Any help would be really helpful. I tried submitting the files, but it is not allowing me. So I will just put the full code under.

    Thank you for your time.
    Adrian Lopez

    P.s. I get the following warning (:-1: warning: Warning: SDK processing. This version only understands SDK XML versions up to 3 but an SDK XML file of version 4 was encountered. This can happen if you use versions of Android Studio and the command-line tools that were released at different times.)

    mainwindow.h:

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <QFile>
    #include <QTextStream>
    #include "scanwindow.h"
    #include <QtCharts/QChart>
    #include <QtCharts/QLineSeries>
    #include <QtCharts/QValueAxis>
    #include <QtCharts/QChartView>
    
    #define MISC_BIT(n) (1U << (n))
    #define MISC_GENMASK(h, l) (((~0U) - (1U << (l)) + 1) & (~0U >> (31 - (h))))
    
    #define MISC_BIT64(n) (1ULL << (n))
    #define MISC_GENMASK64(h, l) (((~0ULL) - (1ULL << (l)) + 1) & (~0ULL >> (63 - (h))))
    
    
    const int32_t scaleFactorDiv = 1000000000;
    const int64_t scaleFactorMult = 38245;
    const uint32_t NegAccMask = MISC_GENMASK(31, 20);
    const uint64_t NegAccMask64 = MISC_GENMASK64(63,20);
    
    QT_BEGIN_NAMESPACE
    namespace Ui {
    class MainWindow;
    }
    QT_END_NAMESPACE
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    
    private slots:
        //void on_actionSave_as_txt_triggered();
        void on_actionSearch_triggered();
        void on_actionDisconnect_triggered();
        void on_actionOpen_triggered();
        void plotDataFromOpenFile(const QString &fileName);
        void plotThreeAxes(QGraphicsView* graphicsView, const QVector<double>& arrayX, const QVector <double>& arrayY, const QVector <double>& arrayZ, bool isRecording, double timeTotal);
        void updateChartVisibility(QLineSeries* series, bool checked, bool isRecording);
        void on_actionShow_X_Axis_Open_changed();
        void on_actionShow_Y_Axis_Open_changed();
        void on_actionShow_Z_Axis_Open_changed();
        void on_actionShow_All_Open_changed();
        void check3Open();
        void on_actionShow_All_Recording_changed();
        void on_actionShow_X_Axis_Recording_changed();
        void on_actionShow_Y_Axis_Recording_changed();
        void on_actionShow_Z_Axis_Recording_changed();
        void check3Recording();
        void updateAxisRange(QValueAxis* axis, QVector<QLineSeries*> seriesList, bool isRecording);
        void on_actionRawValuesOpen_changed();
        void on_actionMs2Open_changed();
        int64_t divS64Rem(int64_t dividend, int32_t divisor, int32_t *remainder);
        int64_t convertToMs2(int64_t rawValue);
        double fullConvertion(int64_t value);
        void onMainWindowResize(QResizeEvent* event);
        void setMinMaxVals(double& minValue, double& maxValue, bool isRecording);
    
    
        void on_actionRawValuesRecording_changed();
    
        void on_actionMs2Recording_changed();
    
        void on_actionStop_recording_triggered();
    
    public slots:
        void handleDeviceSelected(const QBluetoothDeviceInfo &device);
        void onDeviceConnected();
        void onDeviceDisconnected();
        void onServiceDiscovered(const QBluetoothUuid &newService);
        void onServiceStateChanged(QLowEnergyService::ServiceState s);
        void onCharacteristicChanged(const QLowEnergyCharacteristic &ch, const QByteArray &value);
        void handleCharacteristicValueChanged(const QString &value);
        void handleMtuUpdated(int mtu);
        void handleConnectionUpdated(const QLowEnergyConnectionParameters &params);
        void writeLastValues();
        void closeFile();
    
    private:
        Ui::MainWindow *ui;
        QString currentFile;
        ScanWindow *scanWindow;
        QLowEnergyController *controller = nullptr;
        QBluetoothDeviceInfo selectedDevice;
        QBluetoothUuid deviceUUID = QBluetoothUuid("eb056941-14b2-48f9-83ac-e39842e15855");
        QBluetoothUuid characteristicUUID = QBluetoothUuid("eb056942-14b2-48f9-83ac-e39842e15855");
        QLowEnergyService *currentService;
        QLowEnergyCharacteristic currentCharacteristic;
        QVector<double> xDataReadingRaw;
        QVector<double> yDataReadingRaw;
        QVector<double> zDataReadingRaw;
        QVector<double> xDataReadingMs2;
        QVector<double> yDataReadingMs2;
        QVector<double> zDataReadingMs2;
        QVector<double> xDataOpenRaw;
        QVector<double> yDataOpenRaw;
        QVector<double> zDataOpenRaw;
        QVector<double> xDataOpenMs2;
        QVector<double> yDataOpenMs2;
        QVector<double> zDataOpenMs2;
        QFile *dataFile = nullptr;
        QFile *openedFile = nullptr;
        QLineSeries* seriesXOpen = nullptr;
        QLineSeries* seriesYOpen = nullptr;
        QLineSeries* seriesZOpen = nullptr;
        QLineSeries* seriesXRecording = nullptr;
        QLineSeries* seriesYRecording = nullptr;
        QLineSeries* seriesZRecording = nullptr;
        QChart* chartOpen;
        const int32_t scaleFactorDiv = 1000000000;
        int32_t remainder = 0;
        QElapsedTimer timer;
        double totalTimeOpen = 0;
    
    };
    #endif // MAINWINDOW_H
    
    

    mainwindow.cpp

    #include "mainwindow.h"
    #include "./ui_mainwindow.h"
    
    #include "scanwindow.h"
    #include <QFileDialog>
    #include <QMessageBox>
    #include <QThread>
    
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        scanWindow = new ScanWindow(this);
        QRect mGeometry = this->geometry();
        QRect sGeometry = this->geometry();
    
        int moveX = mGeometry.x() + (mGeometry.width() - sGeometry.width())/2;
        int moveY = mGeometry.y() + (mGeometry.height() - sGeometry.height())/2;
    
        scanWindow->move(moveX,moveY);
    
        scanWindow->hide();
    
        QString folderPath = QDir::currentPath() + "/patientsFolder";
        QDir().mkpath(folderPath);
    
        connect(scanWindow, &ScanWindow::deviceSelected, this, &MainWindow::handleDeviceSelected);
        connect(scanWindow, &ScanWindow::characteristicValueChanged, this, &MainWindow::handleCharacteristicValueChanged);
        //connect(this, &QMainWindow::resizeEvent, this, &MainWindow::onMainWindowResize);
    }
    
    MainWindow::~MainWindow()
    {
        if (controller) {
            controller->disconnectFromDevice();
            delete controller;
        }
        if(dataFile && dataFile->isOpen()){
            dataFile->close();
            delete dataFile;
        }
    
        delete ui;
    
    }
    
    /*void MainWindow::on_actionSave_as_txt_triggered()
    {
        QString fileName;
    
        if(currentFile.isEmpty()){
            fileName = QFileDialog::getSaveFileName(this, "Save");
            currentFile = fileName;
        }else{
            fileName = currentFile;
        }
        QFile file(fileName);
        if(!file.open(QIODevice::WriteOnly | QFile::Text)){
            QMessageBox::warning(this, "Warning", "Can not save file "+file.errorString());
            return;
        }
    
        setWindowTitle(fileName);
        QTextStream out(&file);
        //QString text = ui->textEdit->toPlainText();
        //out << text;
        file.close();
    }*/
    
    void MainWindow::on_actionSearch_triggered()
    {
        scanWindow->show();
    }
    
    void MainWindow::handleDeviceSelected(const QBluetoothDeviceInfo &device)
    {
        selectedDevice = device;
    
        if(controller) {
            delete controller;
        }
    
        controller = QLowEnergyController::createCentral(selectedDevice, this);
    
        connect(controller, &QLowEnergyController::connected, this, &MainWindow::onDeviceConnected);
        connect(controller, &QLowEnergyController::disconnected, this, &MainWindow::onDeviceDisconnected);
        connect(controller, &QLowEnergyController::serviceDiscovered, this, &MainWindow::onServiceDiscovered);
        connect(controller, &QLowEnergyController::mtuChanged, this, &MainWindow::handleMtuUpdated);
        connect(controller, &QLowEnergyController::connectionUpdated, this, &MainWindow::handleConnectionUpdated);
    
    
        controller->connectToDevice();
    }
    
    void MainWindow::onDeviceConnected()
    {
        qDebug() << "Device connected successfully";
        QMessageBox::information(this, "Connected", "This device is connected");
        scanWindow->hide();
    
        QString fileName = QFileDialog::getSaveFileName(this, tr("Save As"),tr("patientsFolder/untitled.txt"), tr("Text files (*.txt);;CSV files (*.csv)"));
        dataFile = new QFile(fileName);
    
        if (!dataFile->open(QIODevice::WriteOnly | QIODevice::Text)) {
            qDebug() << "Could not open file";
            delete dataFile;
            dataFile = nullptr;
            return;
        } else {
            qDebug() << "File opened for writing";
        }
    
        controller->discoverServices();
    }
    
    void MainWindow::onDeviceDisconnected()
    {
        qDebug() << "Device disconnected";
        QMessageBox::warning(this, "Disconnected", "This device has been disconnected");
        closeFile();
    }
    
    void MainWindow::closeFile(){
        if(dataFile && dataFile->isOpen()){
            dataFile->close();
        }
    }
    
    void MainWindow::onServiceDiscovered(const QBluetoothUuid &newService)
    {
        if (newService == deviceUUID) {
            QLowEnergyService *service = controller->createServiceObject(newService);
            if (service) {
                connect(service, &QLowEnergyService::stateChanged, this, &MainWindow::onServiceStateChanged);
                connect(service, &QLowEnergyService::characteristicChanged, this, &MainWindow::onCharacteristicChanged);
                service->discoverDetails();
            }
        }
    }
    
    void MainWindow::onServiceStateChanged(QLowEnergyService::ServiceState s)
    {
        if (s == QLowEnergyService::RemoteServiceDiscovered) {
            QLowEnergyService *service = qobject_cast<QLowEnergyService *>(sender());
            const QList<QLowEnergyCharacteristic> characteristics = service->characteristics();
    
            for (const QLowEnergyCharacteristic &ch : characteristics) {
                if (ch.uuid() == characteristicUUID) { // Replace with your characteristic UUID
                    if (ch.properties() & QLowEnergyCharacteristic::Notify) {
                        QLowEnergyDescriptor notificationDesc = ch.descriptor(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
                        if (notificationDesc.isValid()) {
                            service->writeDescriptor(notificationDesc, QByteArray::fromHex("0100"));
                            currentService = service;
                            currentCharacteristic = ch;
                            timer.start();
                        }
                    }
                }
                qDebug() << "Service UUID: " << service->serviceUuid().toString();
                qDebug() << "Characteristic UUID: " << ch.uuid().toString();
                qDebug() << "Name: " << ch.name();
            }
        }
    }
    
    void MainWindow::onCharacteristicChanged(const QLowEnergyCharacteristic &ch, const QByteArray &value)
    {
            //qDebug() << "Characteristic value changed:" << ch.uuid().toString();
        if(dataFile->isOpen()){
            if (value.size() != 60 * sizeof(uint32_t)) {
                qDebug() << "Data not complete";
                return;
            }
            const uint32_t *data = reinterpret_cast<const uint32_t*>(value.constData());
    
            QVector<uint32_t> uint32Data;
    
            xDataReadingRaw.clear();
            yDataReadingRaw.clear();
            zDataReadingRaw.clear();
            xDataReadingMs2.clear();
            yDataReadingMs2.clear();
            zDataReadingMs2.clear();
    
            QByteArray dataArray;
            QDataStream dataStream(&dataArray, QIODevice::WriteOnly);
            QTextStream stream(dataFile);
    
            for (int i = 0; i < 60; ++i) {
                uint32Data.append(data[i]);
            }
    
            for (int i = 0; i < 60; i += 3) {
                xDataReadingRaw.append(data[i]);
                xDataReadingMs2.append(fullConvertion(static_cast<int64_t>(data[i])));
    
                yDataReadingRaw.append(data[i+1]);
                yDataReadingMs2.append(fullConvertion(static_cast<int64_t>(data[i+1])));
    
                zDataReadingRaw.append(data[i+2]);
                zDataReadingMs2.append(fullConvertion(static_cast<int64_t>(data[i+2])));
    
                dataStream << data[i] << data[i + 1] << data[i + 2];
                stream << QString::number(data[i]) << ", " << QString::number(data[i + 1]) << ", " << QString::number(data[i + 2]) << ";\n";
            }
    
            /*if(ui->actionRawValuesRecording->isChecked()){
                plotThreeAxes(ui->graphicsViewReading,xDataReadingRaw,yDataReadingRaw,zDataReadingRaw, 1,-1);
            }else{
                if(ui->actionMs2Recording->isChecked()){
                    plotThreeAxes(ui->graphicsViewReading,xDataReadingMs2,yDataReadingMs2,zDataReadingMs2, 1,-1);
                }
            }*/
        }
    
    }
    
    void MainWindow::handleCharacteristicValueChanged(const QString &value)
    {
        /*ui->textEdit->append(value); // Assuming there is a QTextEdit named textEdit in your UI*/
    }
    
    void MainWindow::writeLastValues(){
        if(dataFile && dataFile->isOpen()){
            qDebug() << "Time: " << (timer.elapsed()/1000.0);
            QByteArray dataArray;
            QDataStream dataStream(&dataArray, QIODevice::WriteOnly);
            QTextStream stream(dataFile);
            dataStream << (timer.elapsed()/1000.0);
            stream << (timer.elapsed()/1000.0) << ";\n";
        }
    }
    
    void MainWindow::on_actionDisconnect_triggered()
    {
        writeLastValues();
        if(controller){
            controller->disconnectFromDevice();
        }
    }
    
    void MainWindow::on_actionOpen_triggered()
    {
        try{
           QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), tr("patientsFolder/"), tr("Text Files (*.txt);;CSV Files (*.csv)"));
            if(!fileName.isEmpty()){
               plotDataFromOpenFile(fileName);
           }
        } catch (const std::exception &e){
            qDebug() << "Exception caught: " << e.what();
        }
    
    }
    
    double MainWindow::fullConvertion(int64_t value)
    {
        int64_t converted = convertToMs2(value);
        int64_t xQuot = divS64Rem(converted, scaleFactorDiv, &remainder);
        return static_cast<double>(xQuot) + static_cast<double>(remainder) / scaleFactorDiv;
    }
    
    void MainWindow::onMainWindowResize(QResizeEvent *event)
    {
        ui->graphicsViewOpened->setMinimumHeight(event->size().height()/2);
        ui->graphicsViewOpened->setMinimumWidth(event->size().width());
    }
    
    void MainWindow::setMinMaxVals(double& minValue, double& maxValue, bool isRecording)
    {
        if(isRecording){
            if(ui->actionMs2Recording->isChecked()){
                minValue -= 1;
                maxValue +=1;
            }else{
                minValue -= 1000;
                maxValue +=1000;
            }
        }else{
            if(ui->actionMs2Open->isChecked()){
                minValue -= 1;
                maxValue +=1;
            }else{
                minValue -= 1000;
                maxValue +=1000;
            }
        }
    }
    
    void MainWindow::plotDataFromOpenFile(const QString &fileName)
    {
        openedFile = new QFile(fileName);
        if(!openedFile->open(QIODevice::ReadOnly | QIODevice::Text)){
            QMessageBox::warning(this, "Warning", "Could not open file: "+openedFile->errorString());
        }
        xDataOpenRaw.clear();
        yDataOpenRaw.clear();
        zDataOpenRaw.clear();
        xDataOpenMs2.clear();
        yDataOpenMs2.clear();
        zDataOpenMs2.clear();
    
        QTextStream in(openedFile);
        while(!in.atEnd()){
            QString line = in.readLine();
            line = line.left(line.length() - 1);
            QStringList values = line.split(',');
            if(values.size() == 3){
                bool ok;
    
                xDataOpenRaw.append(values[0].trimmed().toDouble());
                xDataOpenMs2.append(fullConvertion(values[0].toLongLong(&ok)));
    
                yDataOpenRaw.append(values[1].trimmed().toDouble());
                yDataOpenMs2.append(fullConvertion(values[1].toLongLong(&ok)));
    
                zDataOpenRaw.append(values[2].trimmed().toDouble());
                zDataOpenMs2.append(fullConvertion(values[2].toLongLong(&ok)));
            }else{
                totalTimeOpen = values[0].toDouble();
            }
        }
        openedFile->close();
        if(totalTimeOpen == 0.0){
            totalTimeOpen = -1;
        }
    
        if(ui->actionRawValuesOpen->isChecked()){
            plotThreeAxes(ui->graphicsViewOpened,xDataOpenRaw,yDataOpenRaw,zDataOpenRaw, 0,totalTimeOpen);
        }else{
            if(ui->actionMs2Open->isChecked()){
                plotThreeAxes(ui->graphicsViewOpened,xDataOpenMs2,yDataOpenMs2,zDataOpenMs2, 0, totalTimeOpen);
            }
        }
    }
    
    void MainWindow::plotThreeAxes(QGraphicsView* graphicsView, const QVector<double>& arrayX, const QVector <double>& arrayY, const QVector <double>& arrayZ, bool isRecording, double timeTotal){
        int sizeX = arrayX.size();
        int sizeY = arrayY.size();
        int sizeZ = arrayZ.size();
        if( sizeX != sizeY || sizeX != sizeZ || sizeY != sizeZ){
            QMessageBox::warning(this, "Warning", "Axis arrays differ in size => X: "+QString::number(sizeX)+", Y: "+QString::number(sizeY)+", Z: "+QString::number(sizeZ));
        }
        chartOpen = new QChart();
        chartOpen->setTitle("Thumb Acceleration");
    
        seriesXOpen = new QLineSeries();
        seriesYOpen = new QLineSeries();
        seriesZOpen = new QLineSeries();
    
        seriesXOpen->setName("X axis");
        seriesYOpen->setName("Y axis");
        seriesZOpen->setName("Z axis");
    
        double samplingFreq = 0.0;
        double samplingPeriod = 0.0;
    
        if(timeTotal != -1){
            samplingFreq = arrayX.size() / timeTotal;
            samplingPeriod = 1.0 / samplingFreq;
        }else{
            samplingFreq = 20000.0 / 3;
            samplingPeriod = 1.0 / samplingFreq;
        }
    
        double time = 0;
        for(int i = 0; i<arrayX.size(); i++){
            time = i * samplingPeriod;
            *seriesXOpen << QPointF(time,arrayX[i]);
            *seriesYOpen << QPointF(time,arrayY[i]);
            *seriesZOpen << QPointF(time,arrayZ[i]);
        }
    
        chartOpen->addSeries(seriesXOpen);
        chartOpen->addSeries(seriesYOpen);
        chartOpen->addSeries(seriesZOpen);
    
        QValueAxis *chartXAxis = new QValueAxis();
        QValueAxis *chartYAxis = new QValueAxis();
    
        chartXAxis->setTitleText("Time (s)");
        chartOpen->addAxis(chartXAxis, Qt::AlignBottom);
    
        if(ui->actionMs2Open->isChecked()){
            chartYAxis->setTitleText("Acceleration (m/s^2)");
        }else{
            chartYAxis->setTitleText("Acceleration (raw)");
        }
    
        chartOpen->addAxis(chartYAxis, Qt::AlignLeft);
    
        seriesXOpen->attachAxis(chartXAxis);
        seriesXOpen->attachAxis(chartYAxis);
        if(isRecording){
            updateChartVisibility(seriesXOpen,ui->actionShow_X_Axis_Recording->isChecked(), 1);
        }else{
            updateChartVisibility(seriesXOpen,ui->actionShow_X_Axis_Open->isChecked(), 0);
        }
    
        seriesYOpen->attachAxis(chartXAxis);
        seriesYOpen->attachAxis(chartYAxis);
        if(isRecording){
            updateChartVisibility(seriesYOpen,ui->actionShow_Y_Axis_Recording->isChecked(), 1);
        }else{
            updateChartVisibility(seriesYOpen,ui->actionShow_Y_Axis_Open->isChecked(), 0);
        }
    
        seriesZOpen->attachAxis(chartXAxis);
        seriesZOpen->attachAxis(chartYAxis);
        if(isRecording){
            updateChartVisibility(seriesZOpen,ui->actionShow_Z_Axis_Recording->isChecked(), 1);
        }else{
            updateChartVisibility(seriesZOpen,ui->actionShow_Z_Axis_Open->isChecked(), 0);
        }
    
        double minValue = std::min({ *std::min_element(arrayX.begin(), arrayX.end()),
                                    *std::min_element(arrayY.begin(), arrayY.end()),
                                    *std::min_element(arrayZ.begin(), arrayZ.end()) });
        double maxValue = std::max({ *std::max_element(arrayX.begin(), arrayX.end()),
                                    *std::max_element(arrayY.begin(), arrayY.end()),
                                    *std::max_element(arrayZ.begin(), arrayZ.end()) });
        setMinMaxVals(minValue, maxValue, isRecording);
        chartYAxis->setRange(minValue, maxValue);
    
        QChartView* chartView = new QChartView(chartOpen);
        chartView->setMinimumSize(ui->centralwidget->width() - 10,ui->centralwidget->height()/2);
        //chartView->setSi
        //chartView->setMinimumSize(700, 400);
        QGraphicsScene* scene = new QGraphicsScene();
        scene->addWidget(chartView);
    
        graphicsView->setScene(scene);
    }
    
    void MainWindow::updateChartVisibility(QLineSeries* series, bool checked, bool isRecording)
    {
        QVector<QLineSeries*> seriesList;
    
        if(isRecording){
            if(seriesXRecording && ui->actionShow_X_Axis_Recording->isChecked()){
                    seriesList.append(seriesXRecording);
                }
            if(seriesYRecording && ui->actionShow_Y_Axis_Recording->isChecked()){
                seriesList.append(seriesYRecording);
            }
            if(seriesZRecording && ui->actionShow_Z_Axis_Recording->isChecked()){
                seriesList.append(seriesZRecording);
            }
    
        } else{
            if(seriesXOpen && ui->actionShow_X_Axis_Open->isChecked()){
                seriesList.append(seriesXOpen);
            }
            if(seriesYOpen && ui->actionShow_Y_Axis_Open->isChecked()){
                seriesList.append(seriesYOpen);
            }
            if(seriesZOpen && ui->actionShow_Z_Axis_Open->isChecked()){
                seriesList.append(seriesZOpen);
            }
        }
    
    
        QList<QAbstractAxis*> axes = chartOpen->axes(Qt::Vertical);
        if(!axes.isEmpty()){
            QValueAxis *yAxis = qobject_cast<QValueAxis*>(axes.first());
            updateAxisRange(yAxis,seriesList,isRecording);
        }
    
        if(checked){
            series->setVisible(true);
        }else{
            series->setVisible(false);
        }
    }
    
    void MainWindow::on_actionShow_All_Open_changed()
    {
        if(ui->actionShow_All_Open->isChecked()){
            ui->actionShow_X_Axis_Open->setChecked(true);
            ui->actionShow_Y_Axis_Open->setChecked(true);
            ui->actionShow_Z_Axis_Open->setChecked(true);
        }
    }
    
    void MainWindow::check3Open(){
        if(ui->actionShow_X_Axis_Open->isChecked() &&
            ui->actionShow_Y_Axis_Open->isChecked() &&
            ui->actionShow_Z_Axis_Open->isChecked()){
                ui->actionShow_All_Open->setChecked(true);
        }
    }
    
    void MainWindow::on_actionShow_X_Axis_Open_changed()
    {
        if(!ui->actionShow_X_Axis_Open->isChecked()){
            ui->actionShow_All_Open->setChecked(false);
        }else{
            check3Open();
        }
        if(seriesXOpen){
            updateChartVisibility(seriesXOpen,ui->actionShow_X_Axis_Open->isChecked(), 0);
        }
    
    }
    
    void MainWindow::on_actionShow_Y_Axis_Open_changed()
    {
        if(!ui->actionShow_Y_Axis_Open->isChecked()){
            ui->actionShow_All_Open->setChecked(false);
        }else{
            check3Open();
        }
    
        if(seriesYOpen){
            updateChartVisibility(seriesYOpen,ui->actionShow_Y_Axis_Open->isChecked(), 0);
        }
    }
    
    void MainWindow::on_actionShow_Z_Axis_Open_changed()
    {
        if(!ui->actionShow_Z_Axis_Open->isChecked()){
            ui->actionShow_All_Open->setChecked(false);
        }else{
            check3Open();
        }
    
        if(seriesZOpen){
            updateChartVisibility(seriesZOpen,ui->actionShow_Z_Axis_Open->isChecked(), 0);
        }
    }
    
    void MainWindow::on_actionShow_All_Recording_changed()
    {
        if(ui->actionShow_All_Recording->isChecked()){
            ui->actionShow_X_Axis_Recording->setChecked(true);
            ui->actionShow_Y_Axis_Recording->setChecked(true);
            ui->actionShow_Z_Axis_Recording->setChecked(true);
        }
    }
    
    void MainWindow::check3Recording(){
        if(ui->actionShow_X_Axis_Recording->isChecked() &&
            ui->actionShow_Y_Axis_Recording->isChecked() &&
            ui->actionShow_Z_Axis_Recording->isChecked()){
            ui->actionShow_All_Recording->setChecked(true);
        }
    }
    
    void MainWindow::on_actionShow_X_Axis_Recording_changed()
    {
        if(!ui->actionShow_X_Axis_Recording->isChecked()){
            ui->actionShow_All_Recording->setChecked(false);
        }else{
            check3Recording();
        }
    
        if(seriesXRecording){
            updateChartVisibility(seriesXRecording,ui->actionShow_X_Axis_Recording->isChecked(), 1);
        }
    }
    
    void MainWindow::on_actionShow_Y_Axis_Recording_changed()
    {
        if(!ui->actionShow_Y_Axis_Recording->isChecked()){
            ui->actionShow_All_Recording->setChecked(false);
        }else{
            check3Recording();
        }
    
        if(seriesYRecording){
            updateChartVisibility(seriesYRecording,ui->actionShow_Y_Axis_Recording->isChecked(), 1);
        }
    }
    
    void MainWindow::on_actionShow_Z_Axis_Recording_changed()
    {
        if(!ui->actionShow_Z_Axis_Recording->isChecked()){
            ui->actionShow_All_Recording->setChecked(false);
        }else{
            check3Recording();
        }
    
        if(seriesZRecording){
            updateChartVisibility(seriesZRecording,ui->actionShow_Z_Axis_Recording->isChecked(), 1);
        }
    }
    
    void MainWindow::updateAxisRange(QValueAxis* axis, QVector<QLineSeries*> seriesList, bool isRecording)
    {
        double minValue = std::numeric_limits<double>::max();
        double maxValue = std::numeric_limits<double>::min();
        bool hasData = false;
        QPointF point;
    
        if(!seriesList.isEmpty()){
            for (QLineSeries* series : seriesList) {
                if(series){
                    for (int i = 0; i < series->count(); i++) {
                        point = series->at(i);
                        hasData = true;
                        minValue = std::min(minValue, point.y());
                        maxValue = std::max(maxValue, point.y());
                    }
                }
            }
        }
        if(hasData){
            setMinMaxVals(minValue, maxValue, isRecording);
            axis->setRange(minValue, maxValue);
        } else{
            axis->setRange(0, 1);
        }
    
    }
    
    void MainWindow::on_actionRawValuesOpen_changed()
    {
        if(ui->actionRawValuesOpen->isChecked()){
            ui->actionMs2Open->setChecked(false);
            if(!xDataOpenRaw.isEmpty()){
                plotThreeAxes(ui->graphicsViewOpened,xDataOpenRaw,yDataOpenRaw,zDataOpenRaw,0,totalTimeOpen);
            }
        }else{
            ui->actionMs2Open->setChecked(true);
        }
    }
    
    void MainWindow::on_actionMs2Open_changed()
    {
        if(ui->actionMs2Open->isChecked()){
            ui->actionRawValuesOpen->setChecked(false);
            if(!xDataOpenMs2.isEmpty()){
                plotThreeAxes(ui->graphicsViewOpened,xDataOpenMs2,yDataOpenMs2,zDataOpenMs2,0,totalTimeOpen);
            }
    
        }else{
            ui->actionRawValuesOpen->setChecked(true);
        }
    }
    
    int64_t MainWindow::divS64Rem(int64_t dividend, int32_t divisor, int32_t *remainder)
    {
        if(divisor == 0){
            *remainder = 0;
            return 0;
        }
        *remainder = dividend % divisor;
        return dividend / divisor;
    }
    
    int64_t MainWindow::convertToMs2(int64_t rawValue)
    {
        int64_t accelData;
        if((rawValue & MISC_BIT64(19)) == MISC_BIT64(19)){
            accelData = rawValue | NegAccMask64;
        } else{
            accelData = rawValue;
        }
        return static_cast<double>(accelData) * scaleFactorMult;
    }
    
    void MainWindow::on_actionRawValuesRecording_changed()
    {
        if(ui->actionRawValuesRecording->isChecked()){
            ui->actionMs2Recording->setChecked(false);
        }else{
    
        }
    }
    
    void MainWindow::on_actionMs2Recording_changed()
    {
        if(ui->actionMs2Recording->isChecked()){
            ui->actionRawValuesRecording->setChecked(false);
        }else{
    
        }
    }
    
    void MainWindow::handleMtuUpdated(int mtu)
    {
        qDebug() << "MTU updated:" << mtu;
    }
    
    void MainWindow::handleConnectionUpdated(const QLowEnergyConnectionParameters &params)
    {
        qDebug() << "Connection updated: minimum interval:" << params.minimumInterval()
                 << "Maximum Interval: " << params.maximumInterval()
                 << "Latency:" << params.latency()
                 << "Timeout:" << params.supervisionTimeout();
    }
    
    void MainWindow::on_actionStop_recording_triggered()
    {
        if (currentService && currentCharacteristic.isValid()) {
            QLowEnergyDescriptor notificationDesc = currentCharacteristic.descriptor(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
            if (notificationDesc.isValid()) {
    
                currentService->writeDescriptor(notificationDesc, QByteArray::fromHex("0000"));
                writeLastValues();
                QThread::msleep(100);
                closeFile();
            }
        }
    }
    
    
    

    scanwindow.h

    #ifndef SCANWINDOW_H
    #define SCANWINDOW_H
    
    #include <QMainWindow>
    #include <QBluetoothDeviceDiscoveryAgent>
    #include <QBluetoothDeviceInfo>
    #include <QLowEnergyController>
    #include <QListWidgetItem>
    
    namespace Ui {
    class ScanWindow;
    }
    
    class ScanWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit ScanWindow(QWidget *parent = nullptr);
        ~ScanWindow();
    
    private slots:
        void on_startScanButton_clicked();
        void deviceDiscovered(const QBluetoothDeviceInfo &device);
        void on_deviceList_itemClicked(QListWidgetItem *item);
        void on_connectButton_clicked();
    
        void on_clearButton_clicked();
    
    signals:
        void characteristicValueChanged(const QString &value);
        void deviceSelected(const QBluetoothDeviceInfo &device);
    
    private:
        Ui::ScanWindow *ui;
        QBluetoothDeviceDiscoveryAgent *discoveryAgent;
        QBluetoothDeviceInfo selectedDevice;
        QList<QLowEnergyService*> services;
    };
    
    #endif // SCANWINDOW_H
    
    

    scanwindow.cpp

    #include "scanwindow.h"
    #include "ui_scanwindow.h"
    #include <QMessageBox>
    #include <QPermissions>
    #include <QCoreApplication>
    
    ScanWindow::ScanWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::ScanWindow)
        , discoveryAgent(new QBluetoothDeviceDiscoveryAgent(this))
    {
        ui->setupUi(this);
    
        ui->connectButton->setDisabled(true);
    
        connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, this, &ScanWindow::deviceDiscovered);
    }
    
    ScanWindow::~ScanWindow()
    {
    
        qDeleteAll(services);
        services.clear();
    
        delete ui;
    
    }
    
    void ScanWindow::on_startScanButton_clicked()
    {
        ui->deviceList->clear();
    
    #if QT_CONFIG(permissions)
        QBluetoothPermission permission;
        permission.setCommunicationModes(QBluetoothPermission::Access);
    
        switch (qApp->checkPermission((permission))) {
        case Qt::PermissionStatus::Undetermined:
            qDebug() << "Undetermined";
            qApp->requestPermission(permission, this,  &ScanWindow::on_startScanButton_clicked);
        break;
        case Qt::PermissionStatus::Denied:
            qDebug() << "Denied";
        break;
        case Qt::PermissionStatus::Granted:
            qDebug() << "Granted";
        break;
    
        }
    #endif
    
        discoveryAgent->setLowEnergyDiscoveryTimeout(15000);
        discoveryAgent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
    }
    
    void ScanWindow::deviceDiscovered(const QBluetoothDeviceInfo &device){
    
        if (device.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration) {
            qDebug() << "Added";
            QString label = device.name();
            QListWidgetItem *item = new QListWidgetItem(label, ui->deviceList);
            item->setData(Qt::UserRole,QVariant::fromValue(device));
        }
    
    }
    
    void ScanWindow::on_deviceList_itemClicked(QListWidgetItem *item) {
        QBluetoothDeviceInfo device = item->data(Qt::UserRole).value<QBluetoothDeviceInfo>();
    
        selectedDevice = device;
    
        ui->connectButton->setEnabled(true);
    
        qDebug() << "Selected device:" << device.name() << device.address().toString();
    }
    
    void ScanWindow::on_connectButton_clicked()
    {
        if(!selectedDevice.isValid()){
            qDebug() << "No device selected or device info is invalid";
            return;
        }
    
        emit deviceSelected(selectedDevice);
    }
    
    
    
    void ScanWindow::on_clearButton_clicked()
    {
        ui->deviceList2->clear();
        new QListWidgetItem(tr("Oak2"), ui->deviceList2);
        ui->deviceList2->repaint();
        ui->deviceList2->updateGeometry();
        ui->deviceList2->update();
        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
    }
    
    
    
    M jsulmJ 2 Replies Last reply
    0
    • A AdrianLV

      Hello there,

      I am creating an application that will search for bluetooth devices and then connect to one sensor of mine and display the sensor data. I have my main widget, and the search of the devices happens in a second widget. I built my application first with MSVC2019 and in my Computer(Windows 11) it can do everything (I have the Qt6.7 version).

      Now, I tried to run it in my Android device(With Clang arm64-v8a), but there are some features that are not working as they were in the desktop app. I also tried setting a list in the MainWidget, but I have the same problems. The main one is the QList:

      • When I press on my button, nothing happens, it should be clearing the list and adding a new item.
      • I simply can not select any items.
      • My layout makes everything go to the left after opening the widget

      I am sure it will be something really basic. But I am blocked and have absolutely no idea what to do. I tried to repaint the widget, to process the events and to update. None of these work.

      Any help would be really helpful. I tried submitting the files, but it is not allowing me. So I will just put the full code under.

      Thank you for your time.
      Adrian Lopez

      P.s. I get the following warning (:-1: warning: Warning: SDK processing. This version only understands SDK XML versions up to 3 but an SDK XML file of version 4 was encountered. This can happen if you use versions of Android Studio and the command-line tools that were released at different times.)

      mainwindow.h:

      #ifndef MAINWINDOW_H
      #define MAINWINDOW_H
      
      #include <QMainWindow>
      #include <QFile>
      #include <QTextStream>
      #include "scanwindow.h"
      #include <QtCharts/QChart>
      #include <QtCharts/QLineSeries>
      #include <QtCharts/QValueAxis>
      #include <QtCharts/QChartView>
      
      #define MISC_BIT(n) (1U << (n))
      #define MISC_GENMASK(h, l) (((~0U) - (1U << (l)) + 1) & (~0U >> (31 - (h))))
      
      #define MISC_BIT64(n) (1ULL << (n))
      #define MISC_GENMASK64(h, l) (((~0ULL) - (1ULL << (l)) + 1) & (~0ULL >> (63 - (h))))
      
      
      const int32_t scaleFactorDiv = 1000000000;
      const int64_t scaleFactorMult = 38245;
      const uint32_t NegAccMask = MISC_GENMASK(31, 20);
      const uint64_t NegAccMask64 = MISC_GENMASK64(63,20);
      
      QT_BEGIN_NAMESPACE
      namespace Ui {
      class MainWindow;
      }
      QT_END_NAMESPACE
      
      class MainWindow : public QMainWindow
      {
          Q_OBJECT
      
      public:
          MainWindow(QWidget *parent = nullptr);
          ~MainWindow();
      
      private slots:
          //void on_actionSave_as_txt_triggered();
          void on_actionSearch_triggered();
          void on_actionDisconnect_triggered();
          void on_actionOpen_triggered();
          void plotDataFromOpenFile(const QString &fileName);
          void plotThreeAxes(QGraphicsView* graphicsView, const QVector<double>& arrayX, const QVector <double>& arrayY, const QVector <double>& arrayZ, bool isRecording, double timeTotal);
          void updateChartVisibility(QLineSeries* series, bool checked, bool isRecording);
          void on_actionShow_X_Axis_Open_changed();
          void on_actionShow_Y_Axis_Open_changed();
          void on_actionShow_Z_Axis_Open_changed();
          void on_actionShow_All_Open_changed();
          void check3Open();
          void on_actionShow_All_Recording_changed();
          void on_actionShow_X_Axis_Recording_changed();
          void on_actionShow_Y_Axis_Recording_changed();
          void on_actionShow_Z_Axis_Recording_changed();
          void check3Recording();
          void updateAxisRange(QValueAxis* axis, QVector<QLineSeries*> seriesList, bool isRecording);
          void on_actionRawValuesOpen_changed();
          void on_actionMs2Open_changed();
          int64_t divS64Rem(int64_t dividend, int32_t divisor, int32_t *remainder);
          int64_t convertToMs2(int64_t rawValue);
          double fullConvertion(int64_t value);
          void onMainWindowResize(QResizeEvent* event);
          void setMinMaxVals(double& minValue, double& maxValue, bool isRecording);
      
      
          void on_actionRawValuesRecording_changed();
      
          void on_actionMs2Recording_changed();
      
          void on_actionStop_recording_triggered();
      
      public slots:
          void handleDeviceSelected(const QBluetoothDeviceInfo &device);
          void onDeviceConnected();
          void onDeviceDisconnected();
          void onServiceDiscovered(const QBluetoothUuid &newService);
          void onServiceStateChanged(QLowEnergyService::ServiceState s);
          void onCharacteristicChanged(const QLowEnergyCharacteristic &ch, const QByteArray &value);
          void handleCharacteristicValueChanged(const QString &value);
          void handleMtuUpdated(int mtu);
          void handleConnectionUpdated(const QLowEnergyConnectionParameters &params);
          void writeLastValues();
          void closeFile();
      
      private:
          Ui::MainWindow *ui;
          QString currentFile;
          ScanWindow *scanWindow;
          QLowEnergyController *controller = nullptr;
          QBluetoothDeviceInfo selectedDevice;
          QBluetoothUuid deviceUUID = QBluetoothUuid("eb056941-14b2-48f9-83ac-e39842e15855");
          QBluetoothUuid characteristicUUID = QBluetoothUuid("eb056942-14b2-48f9-83ac-e39842e15855");
          QLowEnergyService *currentService;
          QLowEnergyCharacteristic currentCharacteristic;
          QVector<double> xDataReadingRaw;
          QVector<double> yDataReadingRaw;
          QVector<double> zDataReadingRaw;
          QVector<double> xDataReadingMs2;
          QVector<double> yDataReadingMs2;
          QVector<double> zDataReadingMs2;
          QVector<double> xDataOpenRaw;
          QVector<double> yDataOpenRaw;
          QVector<double> zDataOpenRaw;
          QVector<double> xDataOpenMs2;
          QVector<double> yDataOpenMs2;
          QVector<double> zDataOpenMs2;
          QFile *dataFile = nullptr;
          QFile *openedFile = nullptr;
          QLineSeries* seriesXOpen = nullptr;
          QLineSeries* seriesYOpen = nullptr;
          QLineSeries* seriesZOpen = nullptr;
          QLineSeries* seriesXRecording = nullptr;
          QLineSeries* seriesYRecording = nullptr;
          QLineSeries* seriesZRecording = nullptr;
          QChart* chartOpen;
          const int32_t scaleFactorDiv = 1000000000;
          int32_t remainder = 0;
          QElapsedTimer timer;
          double totalTimeOpen = 0;
      
      };
      #endif // MAINWINDOW_H
      
      

      mainwindow.cpp

      #include "mainwindow.h"
      #include "./ui_mainwindow.h"
      
      #include "scanwindow.h"
      #include <QFileDialog>
      #include <QMessageBox>
      #include <QThread>
      
      MainWindow::MainWindow(QWidget *parent)
          : QMainWindow(parent)
          , ui(new Ui::MainWindow)
      {
          ui->setupUi(this);
      
          scanWindow = new ScanWindow(this);
          QRect mGeometry = this->geometry();
          QRect sGeometry = this->geometry();
      
          int moveX = mGeometry.x() + (mGeometry.width() - sGeometry.width())/2;
          int moveY = mGeometry.y() + (mGeometry.height() - sGeometry.height())/2;
      
          scanWindow->move(moveX,moveY);
      
          scanWindow->hide();
      
          QString folderPath = QDir::currentPath() + "/patientsFolder";
          QDir().mkpath(folderPath);
      
          connect(scanWindow, &ScanWindow::deviceSelected, this, &MainWindow::handleDeviceSelected);
          connect(scanWindow, &ScanWindow::characteristicValueChanged, this, &MainWindow::handleCharacteristicValueChanged);
          //connect(this, &QMainWindow::resizeEvent, this, &MainWindow::onMainWindowResize);
      }
      
      MainWindow::~MainWindow()
      {
          if (controller) {
              controller->disconnectFromDevice();
              delete controller;
          }
          if(dataFile && dataFile->isOpen()){
              dataFile->close();
              delete dataFile;
          }
      
          delete ui;
      
      }
      
      /*void MainWindow::on_actionSave_as_txt_triggered()
      {
          QString fileName;
      
          if(currentFile.isEmpty()){
              fileName = QFileDialog::getSaveFileName(this, "Save");
              currentFile = fileName;
          }else{
              fileName = currentFile;
          }
          QFile file(fileName);
          if(!file.open(QIODevice::WriteOnly | QFile::Text)){
              QMessageBox::warning(this, "Warning", "Can not save file "+file.errorString());
              return;
          }
      
          setWindowTitle(fileName);
          QTextStream out(&file);
          //QString text = ui->textEdit->toPlainText();
          //out << text;
          file.close();
      }*/
      
      void MainWindow::on_actionSearch_triggered()
      {
          scanWindow->show();
      }
      
      void MainWindow::handleDeviceSelected(const QBluetoothDeviceInfo &device)
      {
          selectedDevice = device;
      
          if(controller) {
              delete controller;
          }
      
          controller = QLowEnergyController::createCentral(selectedDevice, this);
      
          connect(controller, &QLowEnergyController::connected, this, &MainWindow::onDeviceConnected);
          connect(controller, &QLowEnergyController::disconnected, this, &MainWindow::onDeviceDisconnected);
          connect(controller, &QLowEnergyController::serviceDiscovered, this, &MainWindow::onServiceDiscovered);
          connect(controller, &QLowEnergyController::mtuChanged, this, &MainWindow::handleMtuUpdated);
          connect(controller, &QLowEnergyController::connectionUpdated, this, &MainWindow::handleConnectionUpdated);
      
      
          controller->connectToDevice();
      }
      
      void MainWindow::onDeviceConnected()
      {
          qDebug() << "Device connected successfully";
          QMessageBox::information(this, "Connected", "This device is connected");
          scanWindow->hide();
      
          QString fileName = QFileDialog::getSaveFileName(this, tr("Save As"),tr("patientsFolder/untitled.txt"), tr("Text files (*.txt);;CSV files (*.csv)"));
          dataFile = new QFile(fileName);
      
          if (!dataFile->open(QIODevice::WriteOnly | QIODevice::Text)) {
              qDebug() << "Could not open file";
              delete dataFile;
              dataFile = nullptr;
              return;
          } else {
              qDebug() << "File opened for writing";
          }
      
          controller->discoverServices();
      }
      
      void MainWindow::onDeviceDisconnected()
      {
          qDebug() << "Device disconnected";
          QMessageBox::warning(this, "Disconnected", "This device has been disconnected");
          closeFile();
      }
      
      void MainWindow::closeFile(){
          if(dataFile && dataFile->isOpen()){
              dataFile->close();
          }
      }
      
      void MainWindow::onServiceDiscovered(const QBluetoothUuid &newService)
      {
          if (newService == deviceUUID) {
              QLowEnergyService *service = controller->createServiceObject(newService);
              if (service) {
                  connect(service, &QLowEnergyService::stateChanged, this, &MainWindow::onServiceStateChanged);
                  connect(service, &QLowEnergyService::characteristicChanged, this, &MainWindow::onCharacteristicChanged);
                  service->discoverDetails();
              }
          }
      }
      
      void MainWindow::onServiceStateChanged(QLowEnergyService::ServiceState s)
      {
          if (s == QLowEnergyService::RemoteServiceDiscovered) {
              QLowEnergyService *service = qobject_cast<QLowEnergyService *>(sender());
              const QList<QLowEnergyCharacteristic> characteristics = service->characteristics();
      
              for (const QLowEnergyCharacteristic &ch : characteristics) {
                  if (ch.uuid() == characteristicUUID) { // Replace with your characteristic UUID
                      if (ch.properties() & QLowEnergyCharacteristic::Notify) {
                          QLowEnergyDescriptor notificationDesc = ch.descriptor(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
                          if (notificationDesc.isValid()) {
                              service->writeDescriptor(notificationDesc, QByteArray::fromHex("0100"));
                              currentService = service;
                              currentCharacteristic = ch;
                              timer.start();
                          }
                      }
                  }
                  qDebug() << "Service UUID: " << service->serviceUuid().toString();
                  qDebug() << "Characteristic UUID: " << ch.uuid().toString();
                  qDebug() << "Name: " << ch.name();
              }
          }
      }
      
      void MainWindow::onCharacteristicChanged(const QLowEnergyCharacteristic &ch, const QByteArray &value)
      {
              //qDebug() << "Characteristic value changed:" << ch.uuid().toString();
          if(dataFile->isOpen()){
              if (value.size() != 60 * sizeof(uint32_t)) {
                  qDebug() << "Data not complete";
                  return;
              }
              const uint32_t *data = reinterpret_cast<const uint32_t*>(value.constData());
      
              QVector<uint32_t> uint32Data;
      
              xDataReadingRaw.clear();
              yDataReadingRaw.clear();
              zDataReadingRaw.clear();
              xDataReadingMs2.clear();
              yDataReadingMs2.clear();
              zDataReadingMs2.clear();
      
              QByteArray dataArray;
              QDataStream dataStream(&dataArray, QIODevice::WriteOnly);
              QTextStream stream(dataFile);
      
              for (int i = 0; i < 60; ++i) {
                  uint32Data.append(data[i]);
              }
      
              for (int i = 0; i < 60; i += 3) {
                  xDataReadingRaw.append(data[i]);
                  xDataReadingMs2.append(fullConvertion(static_cast<int64_t>(data[i])));
      
                  yDataReadingRaw.append(data[i+1]);
                  yDataReadingMs2.append(fullConvertion(static_cast<int64_t>(data[i+1])));
      
                  zDataReadingRaw.append(data[i+2]);
                  zDataReadingMs2.append(fullConvertion(static_cast<int64_t>(data[i+2])));
      
                  dataStream << data[i] << data[i + 1] << data[i + 2];
                  stream << QString::number(data[i]) << ", " << QString::number(data[i + 1]) << ", " << QString::number(data[i + 2]) << ";\n";
              }
      
              /*if(ui->actionRawValuesRecording->isChecked()){
                  plotThreeAxes(ui->graphicsViewReading,xDataReadingRaw,yDataReadingRaw,zDataReadingRaw, 1,-1);
              }else{
                  if(ui->actionMs2Recording->isChecked()){
                      plotThreeAxes(ui->graphicsViewReading,xDataReadingMs2,yDataReadingMs2,zDataReadingMs2, 1,-1);
                  }
              }*/
          }
      
      }
      
      void MainWindow::handleCharacteristicValueChanged(const QString &value)
      {
          /*ui->textEdit->append(value); // Assuming there is a QTextEdit named textEdit in your UI*/
      }
      
      void MainWindow::writeLastValues(){
          if(dataFile && dataFile->isOpen()){
              qDebug() << "Time: " << (timer.elapsed()/1000.0);
              QByteArray dataArray;
              QDataStream dataStream(&dataArray, QIODevice::WriteOnly);
              QTextStream stream(dataFile);
              dataStream << (timer.elapsed()/1000.0);
              stream << (timer.elapsed()/1000.0) << ";\n";
          }
      }
      
      void MainWindow::on_actionDisconnect_triggered()
      {
          writeLastValues();
          if(controller){
              controller->disconnectFromDevice();
          }
      }
      
      void MainWindow::on_actionOpen_triggered()
      {
          try{
             QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), tr("patientsFolder/"), tr("Text Files (*.txt);;CSV Files (*.csv)"));
              if(!fileName.isEmpty()){
                 plotDataFromOpenFile(fileName);
             }
          } catch (const std::exception &e){
              qDebug() << "Exception caught: " << e.what();
          }
      
      }
      
      double MainWindow::fullConvertion(int64_t value)
      {
          int64_t converted = convertToMs2(value);
          int64_t xQuot = divS64Rem(converted, scaleFactorDiv, &remainder);
          return static_cast<double>(xQuot) + static_cast<double>(remainder) / scaleFactorDiv;
      }
      
      void MainWindow::onMainWindowResize(QResizeEvent *event)
      {
          ui->graphicsViewOpened->setMinimumHeight(event->size().height()/2);
          ui->graphicsViewOpened->setMinimumWidth(event->size().width());
      }
      
      void MainWindow::setMinMaxVals(double& minValue, double& maxValue, bool isRecording)
      {
          if(isRecording){
              if(ui->actionMs2Recording->isChecked()){
                  minValue -= 1;
                  maxValue +=1;
              }else{
                  minValue -= 1000;
                  maxValue +=1000;
              }
          }else{
              if(ui->actionMs2Open->isChecked()){
                  minValue -= 1;
                  maxValue +=1;
              }else{
                  minValue -= 1000;
                  maxValue +=1000;
              }
          }
      }
      
      void MainWindow::plotDataFromOpenFile(const QString &fileName)
      {
          openedFile = new QFile(fileName);
          if(!openedFile->open(QIODevice::ReadOnly | QIODevice::Text)){
              QMessageBox::warning(this, "Warning", "Could not open file: "+openedFile->errorString());
          }
          xDataOpenRaw.clear();
          yDataOpenRaw.clear();
          zDataOpenRaw.clear();
          xDataOpenMs2.clear();
          yDataOpenMs2.clear();
          zDataOpenMs2.clear();
      
          QTextStream in(openedFile);
          while(!in.atEnd()){
              QString line = in.readLine();
              line = line.left(line.length() - 1);
              QStringList values = line.split(',');
              if(values.size() == 3){
                  bool ok;
      
                  xDataOpenRaw.append(values[0].trimmed().toDouble());
                  xDataOpenMs2.append(fullConvertion(values[0].toLongLong(&ok)));
      
                  yDataOpenRaw.append(values[1].trimmed().toDouble());
                  yDataOpenMs2.append(fullConvertion(values[1].toLongLong(&ok)));
      
                  zDataOpenRaw.append(values[2].trimmed().toDouble());
                  zDataOpenMs2.append(fullConvertion(values[2].toLongLong(&ok)));
              }else{
                  totalTimeOpen = values[0].toDouble();
              }
          }
          openedFile->close();
          if(totalTimeOpen == 0.0){
              totalTimeOpen = -1;
          }
      
          if(ui->actionRawValuesOpen->isChecked()){
              plotThreeAxes(ui->graphicsViewOpened,xDataOpenRaw,yDataOpenRaw,zDataOpenRaw, 0,totalTimeOpen);
          }else{
              if(ui->actionMs2Open->isChecked()){
                  plotThreeAxes(ui->graphicsViewOpened,xDataOpenMs2,yDataOpenMs2,zDataOpenMs2, 0, totalTimeOpen);
              }
          }
      }
      
      void MainWindow::plotThreeAxes(QGraphicsView* graphicsView, const QVector<double>& arrayX, const QVector <double>& arrayY, const QVector <double>& arrayZ, bool isRecording, double timeTotal){
          int sizeX = arrayX.size();
          int sizeY = arrayY.size();
          int sizeZ = arrayZ.size();
          if( sizeX != sizeY || sizeX != sizeZ || sizeY != sizeZ){
              QMessageBox::warning(this, "Warning", "Axis arrays differ in size => X: "+QString::number(sizeX)+", Y: "+QString::number(sizeY)+", Z: "+QString::number(sizeZ));
          }
          chartOpen = new QChart();
          chartOpen->setTitle("Thumb Acceleration");
      
          seriesXOpen = new QLineSeries();
          seriesYOpen = new QLineSeries();
          seriesZOpen = new QLineSeries();
      
          seriesXOpen->setName("X axis");
          seriesYOpen->setName("Y axis");
          seriesZOpen->setName("Z axis");
      
          double samplingFreq = 0.0;
          double samplingPeriod = 0.0;
      
          if(timeTotal != -1){
              samplingFreq = arrayX.size() / timeTotal;
              samplingPeriod = 1.0 / samplingFreq;
          }else{
              samplingFreq = 20000.0 / 3;
              samplingPeriod = 1.0 / samplingFreq;
          }
      
          double time = 0;
          for(int i = 0; i<arrayX.size(); i++){
              time = i * samplingPeriod;
              *seriesXOpen << QPointF(time,arrayX[i]);
              *seriesYOpen << QPointF(time,arrayY[i]);
              *seriesZOpen << QPointF(time,arrayZ[i]);
          }
      
          chartOpen->addSeries(seriesXOpen);
          chartOpen->addSeries(seriesYOpen);
          chartOpen->addSeries(seriesZOpen);
      
          QValueAxis *chartXAxis = new QValueAxis();
          QValueAxis *chartYAxis = new QValueAxis();
      
          chartXAxis->setTitleText("Time (s)");
          chartOpen->addAxis(chartXAxis, Qt::AlignBottom);
      
          if(ui->actionMs2Open->isChecked()){
              chartYAxis->setTitleText("Acceleration (m/s^2)");
          }else{
              chartYAxis->setTitleText("Acceleration (raw)");
          }
      
          chartOpen->addAxis(chartYAxis, Qt::AlignLeft);
      
          seriesXOpen->attachAxis(chartXAxis);
          seriesXOpen->attachAxis(chartYAxis);
          if(isRecording){
              updateChartVisibility(seriesXOpen,ui->actionShow_X_Axis_Recording->isChecked(), 1);
          }else{
              updateChartVisibility(seriesXOpen,ui->actionShow_X_Axis_Open->isChecked(), 0);
          }
      
          seriesYOpen->attachAxis(chartXAxis);
          seriesYOpen->attachAxis(chartYAxis);
          if(isRecording){
              updateChartVisibility(seriesYOpen,ui->actionShow_Y_Axis_Recording->isChecked(), 1);
          }else{
              updateChartVisibility(seriesYOpen,ui->actionShow_Y_Axis_Open->isChecked(), 0);
          }
      
          seriesZOpen->attachAxis(chartXAxis);
          seriesZOpen->attachAxis(chartYAxis);
          if(isRecording){
              updateChartVisibility(seriesZOpen,ui->actionShow_Z_Axis_Recording->isChecked(), 1);
          }else{
              updateChartVisibility(seriesZOpen,ui->actionShow_Z_Axis_Open->isChecked(), 0);
          }
      
          double minValue = std::min({ *std::min_element(arrayX.begin(), arrayX.end()),
                                      *std::min_element(arrayY.begin(), arrayY.end()),
                                      *std::min_element(arrayZ.begin(), arrayZ.end()) });
          double maxValue = std::max({ *std::max_element(arrayX.begin(), arrayX.end()),
                                      *std::max_element(arrayY.begin(), arrayY.end()),
                                      *std::max_element(arrayZ.begin(), arrayZ.end()) });
          setMinMaxVals(minValue, maxValue, isRecording);
          chartYAxis->setRange(minValue, maxValue);
      
          QChartView* chartView = new QChartView(chartOpen);
          chartView->setMinimumSize(ui->centralwidget->width() - 10,ui->centralwidget->height()/2);
          //chartView->setSi
          //chartView->setMinimumSize(700, 400);
          QGraphicsScene* scene = new QGraphicsScene();
          scene->addWidget(chartView);
      
          graphicsView->setScene(scene);
      }
      
      void MainWindow::updateChartVisibility(QLineSeries* series, bool checked, bool isRecording)
      {
          QVector<QLineSeries*> seriesList;
      
          if(isRecording){
              if(seriesXRecording && ui->actionShow_X_Axis_Recording->isChecked()){
                      seriesList.append(seriesXRecording);
                  }
              if(seriesYRecording && ui->actionShow_Y_Axis_Recording->isChecked()){
                  seriesList.append(seriesYRecording);
              }
              if(seriesZRecording && ui->actionShow_Z_Axis_Recording->isChecked()){
                  seriesList.append(seriesZRecording);
              }
      
          } else{
              if(seriesXOpen && ui->actionShow_X_Axis_Open->isChecked()){
                  seriesList.append(seriesXOpen);
              }
              if(seriesYOpen && ui->actionShow_Y_Axis_Open->isChecked()){
                  seriesList.append(seriesYOpen);
              }
              if(seriesZOpen && ui->actionShow_Z_Axis_Open->isChecked()){
                  seriesList.append(seriesZOpen);
              }
          }
      
      
          QList<QAbstractAxis*> axes = chartOpen->axes(Qt::Vertical);
          if(!axes.isEmpty()){
              QValueAxis *yAxis = qobject_cast<QValueAxis*>(axes.first());
              updateAxisRange(yAxis,seriesList,isRecording);
          }
      
          if(checked){
              series->setVisible(true);
          }else{
              series->setVisible(false);
          }
      }
      
      void MainWindow::on_actionShow_All_Open_changed()
      {
          if(ui->actionShow_All_Open->isChecked()){
              ui->actionShow_X_Axis_Open->setChecked(true);
              ui->actionShow_Y_Axis_Open->setChecked(true);
              ui->actionShow_Z_Axis_Open->setChecked(true);
          }
      }
      
      void MainWindow::check3Open(){
          if(ui->actionShow_X_Axis_Open->isChecked() &&
              ui->actionShow_Y_Axis_Open->isChecked() &&
              ui->actionShow_Z_Axis_Open->isChecked()){
                  ui->actionShow_All_Open->setChecked(true);
          }
      }
      
      void MainWindow::on_actionShow_X_Axis_Open_changed()
      {
          if(!ui->actionShow_X_Axis_Open->isChecked()){
              ui->actionShow_All_Open->setChecked(false);
          }else{
              check3Open();
          }
          if(seriesXOpen){
              updateChartVisibility(seriesXOpen,ui->actionShow_X_Axis_Open->isChecked(), 0);
          }
      
      }
      
      void MainWindow::on_actionShow_Y_Axis_Open_changed()
      {
          if(!ui->actionShow_Y_Axis_Open->isChecked()){
              ui->actionShow_All_Open->setChecked(false);
          }else{
              check3Open();
          }
      
          if(seriesYOpen){
              updateChartVisibility(seriesYOpen,ui->actionShow_Y_Axis_Open->isChecked(), 0);
          }
      }
      
      void MainWindow::on_actionShow_Z_Axis_Open_changed()
      {
          if(!ui->actionShow_Z_Axis_Open->isChecked()){
              ui->actionShow_All_Open->setChecked(false);
          }else{
              check3Open();
          }
      
          if(seriesZOpen){
              updateChartVisibility(seriesZOpen,ui->actionShow_Z_Axis_Open->isChecked(), 0);
          }
      }
      
      void MainWindow::on_actionShow_All_Recording_changed()
      {
          if(ui->actionShow_All_Recording->isChecked()){
              ui->actionShow_X_Axis_Recording->setChecked(true);
              ui->actionShow_Y_Axis_Recording->setChecked(true);
              ui->actionShow_Z_Axis_Recording->setChecked(true);
          }
      }
      
      void MainWindow::check3Recording(){
          if(ui->actionShow_X_Axis_Recording->isChecked() &&
              ui->actionShow_Y_Axis_Recording->isChecked() &&
              ui->actionShow_Z_Axis_Recording->isChecked()){
              ui->actionShow_All_Recording->setChecked(true);
          }
      }
      
      void MainWindow::on_actionShow_X_Axis_Recording_changed()
      {
          if(!ui->actionShow_X_Axis_Recording->isChecked()){
              ui->actionShow_All_Recording->setChecked(false);
          }else{
              check3Recording();
          }
      
          if(seriesXRecording){
              updateChartVisibility(seriesXRecording,ui->actionShow_X_Axis_Recording->isChecked(), 1);
          }
      }
      
      void MainWindow::on_actionShow_Y_Axis_Recording_changed()
      {
          if(!ui->actionShow_Y_Axis_Recording->isChecked()){
              ui->actionShow_All_Recording->setChecked(false);
          }else{
              check3Recording();
          }
      
          if(seriesYRecording){
              updateChartVisibility(seriesYRecording,ui->actionShow_Y_Axis_Recording->isChecked(), 1);
          }
      }
      
      void MainWindow::on_actionShow_Z_Axis_Recording_changed()
      {
          if(!ui->actionShow_Z_Axis_Recording->isChecked()){
              ui->actionShow_All_Recording->setChecked(false);
          }else{
              check3Recording();
          }
      
          if(seriesZRecording){
              updateChartVisibility(seriesZRecording,ui->actionShow_Z_Axis_Recording->isChecked(), 1);
          }
      }
      
      void MainWindow::updateAxisRange(QValueAxis* axis, QVector<QLineSeries*> seriesList, bool isRecording)
      {
          double minValue = std::numeric_limits<double>::max();
          double maxValue = std::numeric_limits<double>::min();
          bool hasData = false;
          QPointF point;
      
          if(!seriesList.isEmpty()){
              for (QLineSeries* series : seriesList) {
                  if(series){
                      for (int i = 0; i < series->count(); i++) {
                          point = series->at(i);
                          hasData = true;
                          minValue = std::min(minValue, point.y());
                          maxValue = std::max(maxValue, point.y());
                      }
                  }
              }
          }
          if(hasData){
              setMinMaxVals(minValue, maxValue, isRecording);
              axis->setRange(minValue, maxValue);
          } else{
              axis->setRange(0, 1);
          }
      
      }
      
      void MainWindow::on_actionRawValuesOpen_changed()
      {
          if(ui->actionRawValuesOpen->isChecked()){
              ui->actionMs2Open->setChecked(false);
              if(!xDataOpenRaw.isEmpty()){
                  plotThreeAxes(ui->graphicsViewOpened,xDataOpenRaw,yDataOpenRaw,zDataOpenRaw,0,totalTimeOpen);
              }
          }else{
              ui->actionMs2Open->setChecked(true);
          }
      }
      
      void MainWindow::on_actionMs2Open_changed()
      {
          if(ui->actionMs2Open->isChecked()){
              ui->actionRawValuesOpen->setChecked(false);
              if(!xDataOpenMs2.isEmpty()){
                  plotThreeAxes(ui->graphicsViewOpened,xDataOpenMs2,yDataOpenMs2,zDataOpenMs2,0,totalTimeOpen);
              }
      
          }else{
              ui->actionRawValuesOpen->setChecked(true);
          }
      }
      
      int64_t MainWindow::divS64Rem(int64_t dividend, int32_t divisor, int32_t *remainder)
      {
          if(divisor == 0){
              *remainder = 0;
              return 0;
          }
          *remainder = dividend % divisor;
          return dividend / divisor;
      }
      
      int64_t MainWindow::convertToMs2(int64_t rawValue)
      {
          int64_t accelData;
          if((rawValue & MISC_BIT64(19)) == MISC_BIT64(19)){
              accelData = rawValue | NegAccMask64;
          } else{
              accelData = rawValue;
          }
          return static_cast<double>(accelData) * scaleFactorMult;
      }
      
      void MainWindow::on_actionRawValuesRecording_changed()
      {
          if(ui->actionRawValuesRecording->isChecked()){
              ui->actionMs2Recording->setChecked(false);
          }else{
      
          }
      }
      
      void MainWindow::on_actionMs2Recording_changed()
      {
          if(ui->actionMs2Recording->isChecked()){
              ui->actionRawValuesRecording->setChecked(false);
          }else{
      
          }
      }
      
      void MainWindow::handleMtuUpdated(int mtu)
      {
          qDebug() << "MTU updated:" << mtu;
      }
      
      void MainWindow::handleConnectionUpdated(const QLowEnergyConnectionParameters &params)
      {
          qDebug() << "Connection updated: minimum interval:" << params.minimumInterval()
                   << "Maximum Interval: " << params.maximumInterval()
                   << "Latency:" << params.latency()
                   << "Timeout:" << params.supervisionTimeout();
      }
      
      void MainWindow::on_actionStop_recording_triggered()
      {
          if (currentService && currentCharacteristic.isValid()) {
              QLowEnergyDescriptor notificationDesc = currentCharacteristic.descriptor(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
              if (notificationDesc.isValid()) {
      
                  currentService->writeDescriptor(notificationDesc, QByteArray::fromHex("0000"));
                  writeLastValues();
                  QThread::msleep(100);
                  closeFile();
              }
          }
      }
      
      
      

      scanwindow.h

      #ifndef SCANWINDOW_H
      #define SCANWINDOW_H
      
      #include <QMainWindow>
      #include <QBluetoothDeviceDiscoveryAgent>
      #include <QBluetoothDeviceInfo>
      #include <QLowEnergyController>
      #include <QListWidgetItem>
      
      namespace Ui {
      class ScanWindow;
      }
      
      class ScanWindow : public QMainWindow
      {
          Q_OBJECT
      
      public:
          explicit ScanWindow(QWidget *parent = nullptr);
          ~ScanWindow();
      
      private slots:
          void on_startScanButton_clicked();
          void deviceDiscovered(const QBluetoothDeviceInfo &device);
          void on_deviceList_itemClicked(QListWidgetItem *item);
          void on_connectButton_clicked();
      
          void on_clearButton_clicked();
      
      signals:
          void characteristicValueChanged(const QString &value);
          void deviceSelected(const QBluetoothDeviceInfo &device);
      
      private:
          Ui::ScanWindow *ui;
          QBluetoothDeviceDiscoveryAgent *discoveryAgent;
          QBluetoothDeviceInfo selectedDevice;
          QList<QLowEnergyService*> services;
      };
      
      #endif // SCANWINDOW_H
      
      

      scanwindow.cpp

      #include "scanwindow.h"
      #include "ui_scanwindow.h"
      #include <QMessageBox>
      #include <QPermissions>
      #include <QCoreApplication>
      
      ScanWindow::ScanWindow(QWidget *parent)
          : QMainWindow(parent)
          , ui(new Ui::ScanWindow)
          , discoveryAgent(new QBluetoothDeviceDiscoveryAgent(this))
      {
          ui->setupUi(this);
      
          ui->connectButton->setDisabled(true);
      
          connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, this, &ScanWindow::deviceDiscovered);
      }
      
      ScanWindow::~ScanWindow()
      {
      
          qDeleteAll(services);
          services.clear();
      
          delete ui;
      
      }
      
      void ScanWindow::on_startScanButton_clicked()
      {
          ui->deviceList->clear();
      
      #if QT_CONFIG(permissions)
          QBluetoothPermission permission;
          permission.setCommunicationModes(QBluetoothPermission::Access);
      
          switch (qApp->checkPermission((permission))) {
          case Qt::PermissionStatus::Undetermined:
              qDebug() << "Undetermined";
              qApp->requestPermission(permission, this,  &ScanWindow::on_startScanButton_clicked);
          break;
          case Qt::PermissionStatus::Denied:
              qDebug() << "Denied";
          break;
          case Qt::PermissionStatus::Granted:
              qDebug() << "Granted";
          break;
      
          }
      #endif
      
          discoveryAgent->setLowEnergyDiscoveryTimeout(15000);
          discoveryAgent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
      }
      
      void ScanWindow::deviceDiscovered(const QBluetoothDeviceInfo &device){
      
          if (device.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration) {
              qDebug() << "Added";
              QString label = device.name();
              QListWidgetItem *item = new QListWidgetItem(label, ui->deviceList);
              item->setData(Qt::UserRole,QVariant::fromValue(device));
          }
      
      }
      
      void ScanWindow::on_deviceList_itemClicked(QListWidgetItem *item) {
          QBluetoothDeviceInfo device = item->data(Qt::UserRole).value<QBluetoothDeviceInfo>();
      
          selectedDevice = device;
      
          ui->connectButton->setEnabled(true);
      
          qDebug() << "Selected device:" << device.name() << device.address().toString();
      }
      
      void ScanWindow::on_connectButton_clicked()
      {
          if(!selectedDevice.isValid()){
              qDebug() << "No device selected or device info is invalid";
              return;
          }
      
          emit deviceSelected(selectedDevice);
      }
      
      
      
      void ScanWindow::on_clearButton_clicked()
      {
          ui->deviceList2->clear();
          new QListWidgetItem(tr("Oak2"), ui->deviceList2);
          ui->deviceList2->repaint();
          ui->deviceList2->updateGeometry();
          ui->deviceList2->update();
          QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
      }
      
      
      
      M Offline
      M Offline
      mvuori
      wrote on last edited by
      #2

      @AdrianLV To verify QList's behaviour you should create the tiniest function (call that from your main() so that nothing else messes with it) that tests only that, nothing more.

      A 1 Reply Last reply
      1
      • A AdrianLV

        Hello there,

        I am creating an application that will search for bluetooth devices and then connect to one sensor of mine and display the sensor data. I have my main widget, and the search of the devices happens in a second widget. I built my application first with MSVC2019 and in my Computer(Windows 11) it can do everything (I have the Qt6.7 version).

        Now, I tried to run it in my Android device(With Clang arm64-v8a), but there are some features that are not working as they were in the desktop app. I also tried setting a list in the MainWidget, but I have the same problems. The main one is the QList:

        • When I press on my button, nothing happens, it should be clearing the list and adding a new item.
        • I simply can not select any items.
        • My layout makes everything go to the left after opening the widget

        I am sure it will be something really basic. But I am blocked and have absolutely no idea what to do. I tried to repaint the widget, to process the events and to update. None of these work.

        Any help would be really helpful. I tried submitting the files, but it is not allowing me. So I will just put the full code under.

        Thank you for your time.
        Adrian Lopez

        P.s. I get the following warning (:-1: warning: Warning: SDK processing. This version only understands SDK XML versions up to 3 but an SDK XML file of version 4 was encountered. This can happen if you use versions of Android Studio and the command-line tools that were released at different times.)

        mainwindow.h:

        #ifndef MAINWINDOW_H
        #define MAINWINDOW_H
        
        #include <QMainWindow>
        #include <QFile>
        #include <QTextStream>
        #include "scanwindow.h"
        #include <QtCharts/QChart>
        #include <QtCharts/QLineSeries>
        #include <QtCharts/QValueAxis>
        #include <QtCharts/QChartView>
        
        #define MISC_BIT(n) (1U << (n))
        #define MISC_GENMASK(h, l) (((~0U) - (1U << (l)) + 1) & (~0U >> (31 - (h))))
        
        #define MISC_BIT64(n) (1ULL << (n))
        #define MISC_GENMASK64(h, l) (((~0ULL) - (1ULL << (l)) + 1) & (~0ULL >> (63 - (h))))
        
        
        const int32_t scaleFactorDiv = 1000000000;
        const int64_t scaleFactorMult = 38245;
        const uint32_t NegAccMask = MISC_GENMASK(31, 20);
        const uint64_t NegAccMask64 = MISC_GENMASK64(63,20);
        
        QT_BEGIN_NAMESPACE
        namespace Ui {
        class MainWindow;
        }
        QT_END_NAMESPACE
        
        class MainWindow : public QMainWindow
        {
            Q_OBJECT
        
        public:
            MainWindow(QWidget *parent = nullptr);
            ~MainWindow();
        
        private slots:
            //void on_actionSave_as_txt_triggered();
            void on_actionSearch_triggered();
            void on_actionDisconnect_triggered();
            void on_actionOpen_triggered();
            void plotDataFromOpenFile(const QString &fileName);
            void plotThreeAxes(QGraphicsView* graphicsView, const QVector<double>& arrayX, const QVector <double>& arrayY, const QVector <double>& arrayZ, bool isRecording, double timeTotal);
            void updateChartVisibility(QLineSeries* series, bool checked, bool isRecording);
            void on_actionShow_X_Axis_Open_changed();
            void on_actionShow_Y_Axis_Open_changed();
            void on_actionShow_Z_Axis_Open_changed();
            void on_actionShow_All_Open_changed();
            void check3Open();
            void on_actionShow_All_Recording_changed();
            void on_actionShow_X_Axis_Recording_changed();
            void on_actionShow_Y_Axis_Recording_changed();
            void on_actionShow_Z_Axis_Recording_changed();
            void check3Recording();
            void updateAxisRange(QValueAxis* axis, QVector<QLineSeries*> seriesList, bool isRecording);
            void on_actionRawValuesOpen_changed();
            void on_actionMs2Open_changed();
            int64_t divS64Rem(int64_t dividend, int32_t divisor, int32_t *remainder);
            int64_t convertToMs2(int64_t rawValue);
            double fullConvertion(int64_t value);
            void onMainWindowResize(QResizeEvent* event);
            void setMinMaxVals(double& minValue, double& maxValue, bool isRecording);
        
        
            void on_actionRawValuesRecording_changed();
        
            void on_actionMs2Recording_changed();
        
            void on_actionStop_recording_triggered();
        
        public slots:
            void handleDeviceSelected(const QBluetoothDeviceInfo &device);
            void onDeviceConnected();
            void onDeviceDisconnected();
            void onServiceDiscovered(const QBluetoothUuid &newService);
            void onServiceStateChanged(QLowEnergyService::ServiceState s);
            void onCharacteristicChanged(const QLowEnergyCharacteristic &ch, const QByteArray &value);
            void handleCharacteristicValueChanged(const QString &value);
            void handleMtuUpdated(int mtu);
            void handleConnectionUpdated(const QLowEnergyConnectionParameters &params);
            void writeLastValues();
            void closeFile();
        
        private:
            Ui::MainWindow *ui;
            QString currentFile;
            ScanWindow *scanWindow;
            QLowEnergyController *controller = nullptr;
            QBluetoothDeviceInfo selectedDevice;
            QBluetoothUuid deviceUUID = QBluetoothUuid("eb056941-14b2-48f9-83ac-e39842e15855");
            QBluetoothUuid characteristicUUID = QBluetoothUuid("eb056942-14b2-48f9-83ac-e39842e15855");
            QLowEnergyService *currentService;
            QLowEnergyCharacteristic currentCharacteristic;
            QVector<double> xDataReadingRaw;
            QVector<double> yDataReadingRaw;
            QVector<double> zDataReadingRaw;
            QVector<double> xDataReadingMs2;
            QVector<double> yDataReadingMs2;
            QVector<double> zDataReadingMs2;
            QVector<double> xDataOpenRaw;
            QVector<double> yDataOpenRaw;
            QVector<double> zDataOpenRaw;
            QVector<double> xDataOpenMs2;
            QVector<double> yDataOpenMs2;
            QVector<double> zDataOpenMs2;
            QFile *dataFile = nullptr;
            QFile *openedFile = nullptr;
            QLineSeries* seriesXOpen = nullptr;
            QLineSeries* seriesYOpen = nullptr;
            QLineSeries* seriesZOpen = nullptr;
            QLineSeries* seriesXRecording = nullptr;
            QLineSeries* seriesYRecording = nullptr;
            QLineSeries* seriesZRecording = nullptr;
            QChart* chartOpen;
            const int32_t scaleFactorDiv = 1000000000;
            int32_t remainder = 0;
            QElapsedTimer timer;
            double totalTimeOpen = 0;
        
        };
        #endif // MAINWINDOW_H
        
        

        mainwindow.cpp

        #include "mainwindow.h"
        #include "./ui_mainwindow.h"
        
        #include "scanwindow.h"
        #include <QFileDialog>
        #include <QMessageBox>
        #include <QThread>
        
        MainWindow::MainWindow(QWidget *parent)
            : QMainWindow(parent)
            , ui(new Ui::MainWindow)
        {
            ui->setupUi(this);
        
            scanWindow = new ScanWindow(this);
            QRect mGeometry = this->geometry();
            QRect sGeometry = this->geometry();
        
            int moveX = mGeometry.x() + (mGeometry.width() - sGeometry.width())/2;
            int moveY = mGeometry.y() + (mGeometry.height() - sGeometry.height())/2;
        
            scanWindow->move(moveX,moveY);
        
            scanWindow->hide();
        
            QString folderPath = QDir::currentPath() + "/patientsFolder";
            QDir().mkpath(folderPath);
        
            connect(scanWindow, &ScanWindow::deviceSelected, this, &MainWindow::handleDeviceSelected);
            connect(scanWindow, &ScanWindow::characteristicValueChanged, this, &MainWindow::handleCharacteristicValueChanged);
            //connect(this, &QMainWindow::resizeEvent, this, &MainWindow::onMainWindowResize);
        }
        
        MainWindow::~MainWindow()
        {
            if (controller) {
                controller->disconnectFromDevice();
                delete controller;
            }
            if(dataFile && dataFile->isOpen()){
                dataFile->close();
                delete dataFile;
            }
        
            delete ui;
        
        }
        
        /*void MainWindow::on_actionSave_as_txt_triggered()
        {
            QString fileName;
        
            if(currentFile.isEmpty()){
                fileName = QFileDialog::getSaveFileName(this, "Save");
                currentFile = fileName;
            }else{
                fileName = currentFile;
            }
            QFile file(fileName);
            if(!file.open(QIODevice::WriteOnly | QFile::Text)){
                QMessageBox::warning(this, "Warning", "Can not save file "+file.errorString());
                return;
            }
        
            setWindowTitle(fileName);
            QTextStream out(&file);
            //QString text = ui->textEdit->toPlainText();
            //out << text;
            file.close();
        }*/
        
        void MainWindow::on_actionSearch_triggered()
        {
            scanWindow->show();
        }
        
        void MainWindow::handleDeviceSelected(const QBluetoothDeviceInfo &device)
        {
            selectedDevice = device;
        
            if(controller) {
                delete controller;
            }
        
            controller = QLowEnergyController::createCentral(selectedDevice, this);
        
            connect(controller, &QLowEnergyController::connected, this, &MainWindow::onDeviceConnected);
            connect(controller, &QLowEnergyController::disconnected, this, &MainWindow::onDeviceDisconnected);
            connect(controller, &QLowEnergyController::serviceDiscovered, this, &MainWindow::onServiceDiscovered);
            connect(controller, &QLowEnergyController::mtuChanged, this, &MainWindow::handleMtuUpdated);
            connect(controller, &QLowEnergyController::connectionUpdated, this, &MainWindow::handleConnectionUpdated);
        
        
            controller->connectToDevice();
        }
        
        void MainWindow::onDeviceConnected()
        {
            qDebug() << "Device connected successfully";
            QMessageBox::information(this, "Connected", "This device is connected");
            scanWindow->hide();
        
            QString fileName = QFileDialog::getSaveFileName(this, tr("Save As"),tr("patientsFolder/untitled.txt"), tr("Text files (*.txt);;CSV files (*.csv)"));
            dataFile = new QFile(fileName);
        
            if (!dataFile->open(QIODevice::WriteOnly | QIODevice::Text)) {
                qDebug() << "Could not open file";
                delete dataFile;
                dataFile = nullptr;
                return;
            } else {
                qDebug() << "File opened for writing";
            }
        
            controller->discoverServices();
        }
        
        void MainWindow::onDeviceDisconnected()
        {
            qDebug() << "Device disconnected";
            QMessageBox::warning(this, "Disconnected", "This device has been disconnected");
            closeFile();
        }
        
        void MainWindow::closeFile(){
            if(dataFile && dataFile->isOpen()){
                dataFile->close();
            }
        }
        
        void MainWindow::onServiceDiscovered(const QBluetoothUuid &newService)
        {
            if (newService == deviceUUID) {
                QLowEnergyService *service = controller->createServiceObject(newService);
                if (service) {
                    connect(service, &QLowEnergyService::stateChanged, this, &MainWindow::onServiceStateChanged);
                    connect(service, &QLowEnergyService::characteristicChanged, this, &MainWindow::onCharacteristicChanged);
                    service->discoverDetails();
                }
            }
        }
        
        void MainWindow::onServiceStateChanged(QLowEnergyService::ServiceState s)
        {
            if (s == QLowEnergyService::RemoteServiceDiscovered) {
                QLowEnergyService *service = qobject_cast<QLowEnergyService *>(sender());
                const QList<QLowEnergyCharacteristic> characteristics = service->characteristics();
        
                for (const QLowEnergyCharacteristic &ch : characteristics) {
                    if (ch.uuid() == characteristicUUID) { // Replace with your characteristic UUID
                        if (ch.properties() & QLowEnergyCharacteristic::Notify) {
                            QLowEnergyDescriptor notificationDesc = ch.descriptor(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
                            if (notificationDesc.isValid()) {
                                service->writeDescriptor(notificationDesc, QByteArray::fromHex("0100"));
                                currentService = service;
                                currentCharacteristic = ch;
                                timer.start();
                            }
                        }
                    }
                    qDebug() << "Service UUID: " << service->serviceUuid().toString();
                    qDebug() << "Characteristic UUID: " << ch.uuid().toString();
                    qDebug() << "Name: " << ch.name();
                }
            }
        }
        
        void MainWindow::onCharacteristicChanged(const QLowEnergyCharacteristic &ch, const QByteArray &value)
        {
                //qDebug() << "Characteristic value changed:" << ch.uuid().toString();
            if(dataFile->isOpen()){
                if (value.size() != 60 * sizeof(uint32_t)) {
                    qDebug() << "Data not complete";
                    return;
                }
                const uint32_t *data = reinterpret_cast<const uint32_t*>(value.constData());
        
                QVector<uint32_t> uint32Data;
        
                xDataReadingRaw.clear();
                yDataReadingRaw.clear();
                zDataReadingRaw.clear();
                xDataReadingMs2.clear();
                yDataReadingMs2.clear();
                zDataReadingMs2.clear();
        
                QByteArray dataArray;
                QDataStream dataStream(&dataArray, QIODevice::WriteOnly);
                QTextStream stream(dataFile);
        
                for (int i = 0; i < 60; ++i) {
                    uint32Data.append(data[i]);
                }
        
                for (int i = 0; i < 60; i += 3) {
                    xDataReadingRaw.append(data[i]);
                    xDataReadingMs2.append(fullConvertion(static_cast<int64_t>(data[i])));
        
                    yDataReadingRaw.append(data[i+1]);
                    yDataReadingMs2.append(fullConvertion(static_cast<int64_t>(data[i+1])));
        
                    zDataReadingRaw.append(data[i+2]);
                    zDataReadingMs2.append(fullConvertion(static_cast<int64_t>(data[i+2])));
        
                    dataStream << data[i] << data[i + 1] << data[i + 2];
                    stream << QString::number(data[i]) << ", " << QString::number(data[i + 1]) << ", " << QString::number(data[i + 2]) << ";\n";
                }
        
                /*if(ui->actionRawValuesRecording->isChecked()){
                    plotThreeAxes(ui->graphicsViewReading,xDataReadingRaw,yDataReadingRaw,zDataReadingRaw, 1,-1);
                }else{
                    if(ui->actionMs2Recording->isChecked()){
                        plotThreeAxes(ui->graphicsViewReading,xDataReadingMs2,yDataReadingMs2,zDataReadingMs2, 1,-1);
                    }
                }*/
            }
        
        }
        
        void MainWindow::handleCharacteristicValueChanged(const QString &value)
        {
            /*ui->textEdit->append(value); // Assuming there is a QTextEdit named textEdit in your UI*/
        }
        
        void MainWindow::writeLastValues(){
            if(dataFile && dataFile->isOpen()){
                qDebug() << "Time: " << (timer.elapsed()/1000.0);
                QByteArray dataArray;
                QDataStream dataStream(&dataArray, QIODevice::WriteOnly);
                QTextStream stream(dataFile);
                dataStream << (timer.elapsed()/1000.0);
                stream << (timer.elapsed()/1000.0) << ";\n";
            }
        }
        
        void MainWindow::on_actionDisconnect_triggered()
        {
            writeLastValues();
            if(controller){
                controller->disconnectFromDevice();
            }
        }
        
        void MainWindow::on_actionOpen_triggered()
        {
            try{
               QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), tr("patientsFolder/"), tr("Text Files (*.txt);;CSV Files (*.csv)"));
                if(!fileName.isEmpty()){
                   plotDataFromOpenFile(fileName);
               }
            } catch (const std::exception &e){
                qDebug() << "Exception caught: " << e.what();
            }
        
        }
        
        double MainWindow::fullConvertion(int64_t value)
        {
            int64_t converted = convertToMs2(value);
            int64_t xQuot = divS64Rem(converted, scaleFactorDiv, &remainder);
            return static_cast<double>(xQuot) + static_cast<double>(remainder) / scaleFactorDiv;
        }
        
        void MainWindow::onMainWindowResize(QResizeEvent *event)
        {
            ui->graphicsViewOpened->setMinimumHeight(event->size().height()/2);
            ui->graphicsViewOpened->setMinimumWidth(event->size().width());
        }
        
        void MainWindow::setMinMaxVals(double& minValue, double& maxValue, bool isRecording)
        {
            if(isRecording){
                if(ui->actionMs2Recording->isChecked()){
                    minValue -= 1;
                    maxValue +=1;
                }else{
                    minValue -= 1000;
                    maxValue +=1000;
                }
            }else{
                if(ui->actionMs2Open->isChecked()){
                    minValue -= 1;
                    maxValue +=1;
                }else{
                    minValue -= 1000;
                    maxValue +=1000;
                }
            }
        }
        
        void MainWindow::plotDataFromOpenFile(const QString &fileName)
        {
            openedFile = new QFile(fileName);
            if(!openedFile->open(QIODevice::ReadOnly | QIODevice::Text)){
                QMessageBox::warning(this, "Warning", "Could not open file: "+openedFile->errorString());
            }
            xDataOpenRaw.clear();
            yDataOpenRaw.clear();
            zDataOpenRaw.clear();
            xDataOpenMs2.clear();
            yDataOpenMs2.clear();
            zDataOpenMs2.clear();
        
            QTextStream in(openedFile);
            while(!in.atEnd()){
                QString line = in.readLine();
                line = line.left(line.length() - 1);
                QStringList values = line.split(',');
                if(values.size() == 3){
                    bool ok;
        
                    xDataOpenRaw.append(values[0].trimmed().toDouble());
                    xDataOpenMs2.append(fullConvertion(values[0].toLongLong(&ok)));
        
                    yDataOpenRaw.append(values[1].trimmed().toDouble());
                    yDataOpenMs2.append(fullConvertion(values[1].toLongLong(&ok)));
        
                    zDataOpenRaw.append(values[2].trimmed().toDouble());
                    zDataOpenMs2.append(fullConvertion(values[2].toLongLong(&ok)));
                }else{
                    totalTimeOpen = values[0].toDouble();
                }
            }
            openedFile->close();
            if(totalTimeOpen == 0.0){
                totalTimeOpen = -1;
            }
        
            if(ui->actionRawValuesOpen->isChecked()){
                plotThreeAxes(ui->graphicsViewOpened,xDataOpenRaw,yDataOpenRaw,zDataOpenRaw, 0,totalTimeOpen);
            }else{
                if(ui->actionMs2Open->isChecked()){
                    plotThreeAxes(ui->graphicsViewOpened,xDataOpenMs2,yDataOpenMs2,zDataOpenMs2, 0, totalTimeOpen);
                }
            }
        }
        
        void MainWindow::plotThreeAxes(QGraphicsView* graphicsView, const QVector<double>& arrayX, const QVector <double>& arrayY, const QVector <double>& arrayZ, bool isRecording, double timeTotal){
            int sizeX = arrayX.size();
            int sizeY = arrayY.size();
            int sizeZ = arrayZ.size();
            if( sizeX != sizeY || sizeX != sizeZ || sizeY != sizeZ){
                QMessageBox::warning(this, "Warning", "Axis arrays differ in size => X: "+QString::number(sizeX)+", Y: "+QString::number(sizeY)+", Z: "+QString::number(sizeZ));
            }
            chartOpen = new QChart();
            chartOpen->setTitle("Thumb Acceleration");
        
            seriesXOpen = new QLineSeries();
            seriesYOpen = new QLineSeries();
            seriesZOpen = new QLineSeries();
        
            seriesXOpen->setName("X axis");
            seriesYOpen->setName("Y axis");
            seriesZOpen->setName("Z axis");
        
            double samplingFreq = 0.0;
            double samplingPeriod = 0.0;
        
            if(timeTotal != -1){
                samplingFreq = arrayX.size() / timeTotal;
                samplingPeriod = 1.0 / samplingFreq;
            }else{
                samplingFreq = 20000.0 / 3;
                samplingPeriod = 1.0 / samplingFreq;
            }
        
            double time = 0;
            for(int i = 0; i<arrayX.size(); i++){
                time = i * samplingPeriod;
                *seriesXOpen << QPointF(time,arrayX[i]);
                *seriesYOpen << QPointF(time,arrayY[i]);
                *seriesZOpen << QPointF(time,arrayZ[i]);
            }
        
            chartOpen->addSeries(seriesXOpen);
            chartOpen->addSeries(seriesYOpen);
            chartOpen->addSeries(seriesZOpen);
        
            QValueAxis *chartXAxis = new QValueAxis();
            QValueAxis *chartYAxis = new QValueAxis();
        
            chartXAxis->setTitleText("Time (s)");
            chartOpen->addAxis(chartXAxis, Qt::AlignBottom);
        
            if(ui->actionMs2Open->isChecked()){
                chartYAxis->setTitleText("Acceleration (m/s^2)");
            }else{
                chartYAxis->setTitleText("Acceleration (raw)");
            }
        
            chartOpen->addAxis(chartYAxis, Qt::AlignLeft);
        
            seriesXOpen->attachAxis(chartXAxis);
            seriesXOpen->attachAxis(chartYAxis);
            if(isRecording){
                updateChartVisibility(seriesXOpen,ui->actionShow_X_Axis_Recording->isChecked(), 1);
            }else{
                updateChartVisibility(seriesXOpen,ui->actionShow_X_Axis_Open->isChecked(), 0);
            }
        
            seriesYOpen->attachAxis(chartXAxis);
            seriesYOpen->attachAxis(chartYAxis);
            if(isRecording){
                updateChartVisibility(seriesYOpen,ui->actionShow_Y_Axis_Recording->isChecked(), 1);
            }else{
                updateChartVisibility(seriesYOpen,ui->actionShow_Y_Axis_Open->isChecked(), 0);
            }
        
            seriesZOpen->attachAxis(chartXAxis);
            seriesZOpen->attachAxis(chartYAxis);
            if(isRecording){
                updateChartVisibility(seriesZOpen,ui->actionShow_Z_Axis_Recording->isChecked(), 1);
            }else{
                updateChartVisibility(seriesZOpen,ui->actionShow_Z_Axis_Open->isChecked(), 0);
            }
        
            double minValue = std::min({ *std::min_element(arrayX.begin(), arrayX.end()),
                                        *std::min_element(arrayY.begin(), arrayY.end()),
                                        *std::min_element(arrayZ.begin(), arrayZ.end()) });
            double maxValue = std::max({ *std::max_element(arrayX.begin(), arrayX.end()),
                                        *std::max_element(arrayY.begin(), arrayY.end()),
                                        *std::max_element(arrayZ.begin(), arrayZ.end()) });
            setMinMaxVals(minValue, maxValue, isRecording);
            chartYAxis->setRange(minValue, maxValue);
        
            QChartView* chartView = new QChartView(chartOpen);
            chartView->setMinimumSize(ui->centralwidget->width() - 10,ui->centralwidget->height()/2);
            //chartView->setSi
            //chartView->setMinimumSize(700, 400);
            QGraphicsScene* scene = new QGraphicsScene();
            scene->addWidget(chartView);
        
            graphicsView->setScene(scene);
        }
        
        void MainWindow::updateChartVisibility(QLineSeries* series, bool checked, bool isRecording)
        {
            QVector<QLineSeries*> seriesList;
        
            if(isRecording){
                if(seriesXRecording && ui->actionShow_X_Axis_Recording->isChecked()){
                        seriesList.append(seriesXRecording);
                    }
                if(seriesYRecording && ui->actionShow_Y_Axis_Recording->isChecked()){
                    seriesList.append(seriesYRecording);
                }
                if(seriesZRecording && ui->actionShow_Z_Axis_Recording->isChecked()){
                    seriesList.append(seriesZRecording);
                }
        
            } else{
                if(seriesXOpen && ui->actionShow_X_Axis_Open->isChecked()){
                    seriesList.append(seriesXOpen);
                }
                if(seriesYOpen && ui->actionShow_Y_Axis_Open->isChecked()){
                    seriesList.append(seriesYOpen);
                }
                if(seriesZOpen && ui->actionShow_Z_Axis_Open->isChecked()){
                    seriesList.append(seriesZOpen);
                }
            }
        
        
            QList<QAbstractAxis*> axes = chartOpen->axes(Qt::Vertical);
            if(!axes.isEmpty()){
                QValueAxis *yAxis = qobject_cast<QValueAxis*>(axes.first());
                updateAxisRange(yAxis,seriesList,isRecording);
            }
        
            if(checked){
                series->setVisible(true);
            }else{
                series->setVisible(false);
            }
        }
        
        void MainWindow::on_actionShow_All_Open_changed()
        {
            if(ui->actionShow_All_Open->isChecked()){
                ui->actionShow_X_Axis_Open->setChecked(true);
                ui->actionShow_Y_Axis_Open->setChecked(true);
                ui->actionShow_Z_Axis_Open->setChecked(true);
            }
        }
        
        void MainWindow::check3Open(){
            if(ui->actionShow_X_Axis_Open->isChecked() &&
                ui->actionShow_Y_Axis_Open->isChecked() &&
                ui->actionShow_Z_Axis_Open->isChecked()){
                    ui->actionShow_All_Open->setChecked(true);
            }
        }
        
        void MainWindow::on_actionShow_X_Axis_Open_changed()
        {
            if(!ui->actionShow_X_Axis_Open->isChecked()){
                ui->actionShow_All_Open->setChecked(false);
            }else{
                check3Open();
            }
            if(seriesXOpen){
                updateChartVisibility(seriesXOpen,ui->actionShow_X_Axis_Open->isChecked(), 0);
            }
        
        }
        
        void MainWindow::on_actionShow_Y_Axis_Open_changed()
        {
            if(!ui->actionShow_Y_Axis_Open->isChecked()){
                ui->actionShow_All_Open->setChecked(false);
            }else{
                check3Open();
            }
        
            if(seriesYOpen){
                updateChartVisibility(seriesYOpen,ui->actionShow_Y_Axis_Open->isChecked(), 0);
            }
        }
        
        void MainWindow::on_actionShow_Z_Axis_Open_changed()
        {
            if(!ui->actionShow_Z_Axis_Open->isChecked()){
                ui->actionShow_All_Open->setChecked(false);
            }else{
                check3Open();
            }
        
            if(seriesZOpen){
                updateChartVisibility(seriesZOpen,ui->actionShow_Z_Axis_Open->isChecked(), 0);
            }
        }
        
        void MainWindow::on_actionShow_All_Recording_changed()
        {
            if(ui->actionShow_All_Recording->isChecked()){
                ui->actionShow_X_Axis_Recording->setChecked(true);
                ui->actionShow_Y_Axis_Recording->setChecked(true);
                ui->actionShow_Z_Axis_Recording->setChecked(true);
            }
        }
        
        void MainWindow::check3Recording(){
            if(ui->actionShow_X_Axis_Recording->isChecked() &&
                ui->actionShow_Y_Axis_Recording->isChecked() &&
                ui->actionShow_Z_Axis_Recording->isChecked()){
                ui->actionShow_All_Recording->setChecked(true);
            }
        }
        
        void MainWindow::on_actionShow_X_Axis_Recording_changed()
        {
            if(!ui->actionShow_X_Axis_Recording->isChecked()){
                ui->actionShow_All_Recording->setChecked(false);
            }else{
                check3Recording();
            }
        
            if(seriesXRecording){
                updateChartVisibility(seriesXRecording,ui->actionShow_X_Axis_Recording->isChecked(), 1);
            }
        }
        
        void MainWindow::on_actionShow_Y_Axis_Recording_changed()
        {
            if(!ui->actionShow_Y_Axis_Recording->isChecked()){
                ui->actionShow_All_Recording->setChecked(false);
            }else{
                check3Recording();
            }
        
            if(seriesYRecording){
                updateChartVisibility(seriesYRecording,ui->actionShow_Y_Axis_Recording->isChecked(), 1);
            }
        }
        
        void MainWindow::on_actionShow_Z_Axis_Recording_changed()
        {
            if(!ui->actionShow_Z_Axis_Recording->isChecked()){
                ui->actionShow_All_Recording->setChecked(false);
            }else{
                check3Recording();
            }
        
            if(seriesZRecording){
                updateChartVisibility(seriesZRecording,ui->actionShow_Z_Axis_Recording->isChecked(), 1);
            }
        }
        
        void MainWindow::updateAxisRange(QValueAxis* axis, QVector<QLineSeries*> seriesList, bool isRecording)
        {
            double minValue = std::numeric_limits<double>::max();
            double maxValue = std::numeric_limits<double>::min();
            bool hasData = false;
            QPointF point;
        
            if(!seriesList.isEmpty()){
                for (QLineSeries* series : seriesList) {
                    if(series){
                        for (int i = 0; i < series->count(); i++) {
                            point = series->at(i);
                            hasData = true;
                            minValue = std::min(minValue, point.y());
                            maxValue = std::max(maxValue, point.y());
                        }
                    }
                }
            }
            if(hasData){
                setMinMaxVals(minValue, maxValue, isRecording);
                axis->setRange(minValue, maxValue);
            } else{
                axis->setRange(0, 1);
            }
        
        }
        
        void MainWindow::on_actionRawValuesOpen_changed()
        {
            if(ui->actionRawValuesOpen->isChecked()){
                ui->actionMs2Open->setChecked(false);
                if(!xDataOpenRaw.isEmpty()){
                    plotThreeAxes(ui->graphicsViewOpened,xDataOpenRaw,yDataOpenRaw,zDataOpenRaw,0,totalTimeOpen);
                }
            }else{
                ui->actionMs2Open->setChecked(true);
            }
        }
        
        void MainWindow::on_actionMs2Open_changed()
        {
            if(ui->actionMs2Open->isChecked()){
                ui->actionRawValuesOpen->setChecked(false);
                if(!xDataOpenMs2.isEmpty()){
                    plotThreeAxes(ui->graphicsViewOpened,xDataOpenMs2,yDataOpenMs2,zDataOpenMs2,0,totalTimeOpen);
                }
        
            }else{
                ui->actionRawValuesOpen->setChecked(true);
            }
        }
        
        int64_t MainWindow::divS64Rem(int64_t dividend, int32_t divisor, int32_t *remainder)
        {
            if(divisor == 0){
                *remainder = 0;
                return 0;
            }
            *remainder = dividend % divisor;
            return dividend / divisor;
        }
        
        int64_t MainWindow::convertToMs2(int64_t rawValue)
        {
            int64_t accelData;
            if((rawValue & MISC_BIT64(19)) == MISC_BIT64(19)){
                accelData = rawValue | NegAccMask64;
            } else{
                accelData = rawValue;
            }
            return static_cast<double>(accelData) * scaleFactorMult;
        }
        
        void MainWindow::on_actionRawValuesRecording_changed()
        {
            if(ui->actionRawValuesRecording->isChecked()){
                ui->actionMs2Recording->setChecked(false);
            }else{
        
            }
        }
        
        void MainWindow::on_actionMs2Recording_changed()
        {
            if(ui->actionMs2Recording->isChecked()){
                ui->actionRawValuesRecording->setChecked(false);
            }else{
        
            }
        }
        
        void MainWindow::handleMtuUpdated(int mtu)
        {
            qDebug() << "MTU updated:" << mtu;
        }
        
        void MainWindow::handleConnectionUpdated(const QLowEnergyConnectionParameters &params)
        {
            qDebug() << "Connection updated: minimum interval:" << params.minimumInterval()
                     << "Maximum Interval: " << params.maximumInterval()
                     << "Latency:" << params.latency()
                     << "Timeout:" << params.supervisionTimeout();
        }
        
        void MainWindow::on_actionStop_recording_triggered()
        {
            if (currentService && currentCharacteristic.isValid()) {
                QLowEnergyDescriptor notificationDesc = currentCharacteristic.descriptor(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
                if (notificationDesc.isValid()) {
        
                    currentService->writeDescriptor(notificationDesc, QByteArray::fromHex("0000"));
                    writeLastValues();
                    QThread::msleep(100);
                    closeFile();
                }
            }
        }
        
        
        

        scanwindow.h

        #ifndef SCANWINDOW_H
        #define SCANWINDOW_H
        
        #include <QMainWindow>
        #include <QBluetoothDeviceDiscoveryAgent>
        #include <QBluetoothDeviceInfo>
        #include <QLowEnergyController>
        #include <QListWidgetItem>
        
        namespace Ui {
        class ScanWindow;
        }
        
        class ScanWindow : public QMainWindow
        {
            Q_OBJECT
        
        public:
            explicit ScanWindow(QWidget *parent = nullptr);
            ~ScanWindow();
        
        private slots:
            void on_startScanButton_clicked();
            void deviceDiscovered(const QBluetoothDeviceInfo &device);
            void on_deviceList_itemClicked(QListWidgetItem *item);
            void on_connectButton_clicked();
        
            void on_clearButton_clicked();
        
        signals:
            void characteristicValueChanged(const QString &value);
            void deviceSelected(const QBluetoothDeviceInfo &device);
        
        private:
            Ui::ScanWindow *ui;
            QBluetoothDeviceDiscoveryAgent *discoveryAgent;
            QBluetoothDeviceInfo selectedDevice;
            QList<QLowEnergyService*> services;
        };
        
        #endif // SCANWINDOW_H
        
        

        scanwindow.cpp

        #include "scanwindow.h"
        #include "ui_scanwindow.h"
        #include <QMessageBox>
        #include <QPermissions>
        #include <QCoreApplication>
        
        ScanWindow::ScanWindow(QWidget *parent)
            : QMainWindow(parent)
            , ui(new Ui::ScanWindow)
            , discoveryAgent(new QBluetoothDeviceDiscoveryAgent(this))
        {
            ui->setupUi(this);
        
            ui->connectButton->setDisabled(true);
        
            connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, this, &ScanWindow::deviceDiscovered);
        }
        
        ScanWindow::~ScanWindow()
        {
        
            qDeleteAll(services);
            services.clear();
        
            delete ui;
        
        }
        
        void ScanWindow::on_startScanButton_clicked()
        {
            ui->deviceList->clear();
        
        #if QT_CONFIG(permissions)
            QBluetoothPermission permission;
            permission.setCommunicationModes(QBluetoothPermission::Access);
        
            switch (qApp->checkPermission((permission))) {
            case Qt::PermissionStatus::Undetermined:
                qDebug() << "Undetermined";
                qApp->requestPermission(permission, this,  &ScanWindow::on_startScanButton_clicked);
            break;
            case Qt::PermissionStatus::Denied:
                qDebug() << "Denied";
            break;
            case Qt::PermissionStatus::Granted:
                qDebug() << "Granted";
            break;
        
            }
        #endif
        
            discoveryAgent->setLowEnergyDiscoveryTimeout(15000);
            discoveryAgent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
        }
        
        void ScanWindow::deviceDiscovered(const QBluetoothDeviceInfo &device){
        
            if (device.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration) {
                qDebug() << "Added";
                QString label = device.name();
                QListWidgetItem *item = new QListWidgetItem(label, ui->deviceList);
                item->setData(Qt::UserRole,QVariant::fromValue(device));
            }
        
        }
        
        void ScanWindow::on_deviceList_itemClicked(QListWidgetItem *item) {
            QBluetoothDeviceInfo device = item->data(Qt::UserRole).value<QBluetoothDeviceInfo>();
        
            selectedDevice = device;
        
            ui->connectButton->setEnabled(true);
        
            qDebug() << "Selected device:" << device.name() << device.address().toString();
        }
        
        void ScanWindow::on_connectButton_clicked()
        {
            if(!selectedDevice.isValid()){
                qDebug() << "No device selected or device info is invalid";
                return;
            }
        
            emit deviceSelected(selectedDevice);
        }
        
        
        
        void ScanWindow::on_clearButton_clicked()
        {
            ui->deviceList2->clear();
            new QListWidgetItem(tr("Oak2"), ui->deviceList2);
            ui->deviceList2->repaint();
            ui->deviceList2->updateGeometry();
            ui->deviceList2->update();
            QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
        }
        
        
        
        jsulmJ Offline
        jsulmJ Offline
        jsulm
        Lifetime Qt Champion
        wrote on last edited by
        #3

        @AdrianLV I doubt this has anything to do with QList.

        This will not work on Android (also not on any other OS if the application is properly installed, because applications are not allowed to write in their installation folder):

        QString folderPath = QDir::currentPath() + "/patientsFolder";
        QDir().mkpath(folderPath);
        

        Use https://doc.qt.io/qt-6/qstandardpaths.html to find correct location for application data.

        "When I press on my button, nothing happens, it should be clearing the list and adding a new item" - verify why the signal/slot connection works and if it does whether the slot is called.

        "I also tried setting a list in the MainWidget, but I have the same problems" - what list?

        Moving windows on a mobile platform like Android isn't going to work.

        https://forum.qt.io/topic/113070/qt-code-of-conduct

        A 1 Reply Last reply
        1
        • M Offline
          M Offline
          MartinGU
          wrote on last edited by
          #4

          Android screen redraws are really fucked up in C++,
          I have the same problem items not being selected.
          Example of bugreport: https://bugreports.qt.io/browse/QTBUG-128794

          If you want to save data with your application in Android you can use QSettings.
          https://doc.qt.io/qt-6/qsettings.html
          Use the first constructor, the one without filename.

          /Martin

          A 1 Reply Last reply
          0
          • A Offline
            A Offline
            ankou29666
            wrote on last edited by
            #5

            Qt Widgets has never been intended to be used on mobile devices such as Android or iOS.
            Qt Quick is much more suitable for those devices. I seriously doubt this bug report will ever be addressed.

            A 1 Reply Last reply
            0
            • M mvuori

              @AdrianLV To verify QList's behaviour you should create the tiniest function (call that from your main() so that nothing else messes with it) that tests only that, nothing more.

              A Offline
              A Offline
              AdrianLV
              wrote on last edited by
              #6

              @mvuori Thank you, I tried creating a new project in which I added the QList widget and it is already not responding how it is supposed to. I guess I will have to change the way I am displaying my list.

              1 Reply Last reply
              0
              • jsulmJ jsulm

                @AdrianLV I doubt this has anything to do with QList.

                This will not work on Android (also not on any other OS if the application is properly installed, because applications are not allowed to write in their installation folder):

                QString folderPath = QDir::currentPath() + "/patientsFolder";
                QDir().mkpath(folderPath);
                

                Use https://doc.qt.io/qt-6/qstandardpaths.html to find correct location for application data.

                "When I press on my button, nothing happens, it should be clearing the list and adding a new item" - verify why the signal/slot connection works and if it does whether the slot is called.

                "I also tried setting a list in the MainWidget, but I have the same problems" - what list?

                Moving windows on a mobile platform like Android isn't going to work.

                A Offline
                A Offline
                AdrianLV
                wrote on last edited by
                #7

                @jsulm

                I doubt this has anything to do with QList.

                Then is it Android behaivour?

                Use https://doc.qt.io/qt-6/qstandardpaths.html to find correct location for application data.

                Thank you so much, I had not reached that far to test that part of my app, so I did not know if that would work out.

                verify why the signal/slot connection works and if it does whether the slot is called.

                The slot is being called, it is just the refreshing of the list that does not work.

                what list?

                A QListWidget, but I erased it when I saw it not working.

                Moving windows on a mobile platform like Android isn't going to work.

                What would you suggest instead of moving windows?

                Thank you for your time.

                jsulmJ 1 Reply Last reply
                0
                • M MartinGU

                  Android screen redraws are really fucked up in C++,
                  I have the same problem items not being selected.
                  Example of bugreport: https://bugreports.qt.io/browse/QTBUG-128794

                  If you want to save data with your application in Android you can use QSettings.
                  https://doc.qt.io/qt-6/qsettings.html
                  Use the first constructor, the one without filename.

                  /Martin

                  A Offline
                  A Offline
                  AdrianLV
                  wrote on last edited by
                  #8

                  @MartinGU

                  Example of bugreport: https://bugreports.qt.io/browse/QTBUG-128794

                  I see, but you still have not got a reply, right?

                  Use the first constructor, the one without filename.

                  Is this one better than: https://doc.qt.io/qt-6/qstandardpaths.html?

                  Thank you so much for your time!

                  M 1 Reply Last reply
                  0
                  • A ankou29666

                    Qt Widgets has never been intended to be used on mobile devices such as Android or iOS.
                    Qt Quick is much more suitable for those devices. I seriously doubt this bug report will ever be addressed.

                    A Offline
                    A Offline
                    AdrianLV
                    wrote on last edited by
                    #9

                    @ankou29666
                    Hi, I guess I discovered a little bit late that QtQuick was better for mobile development. I am still learning, I guess for the next mobile development I do I will start with QtQuick directly.
                    Thank you for your time!

                    1 Reply Last reply
                    0
                    • A AdrianLV

                      @jsulm

                      I doubt this has anything to do with QList.

                      Then is it Android behaivour?

                      Use https://doc.qt.io/qt-6/qstandardpaths.html to find correct location for application data.

                      Thank you so much, I had not reached that far to test that part of my app, so I did not know if that would work out.

                      verify why the signal/slot connection works and if it does whether the slot is called.

                      The slot is being called, it is just the refreshing of the list that does not work.

                      what list?

                      A QListWidget, but I erased it when I saw it not working.

                      Moving windows on a mobile platform like Android isn't going to work.

                      What would you suggest instead of moving windows?

                      Thank you for your time.

                      jsulmJ Offline
                      jsulmJ Offline
                      jsulm
                      Lifetime Qt Champion
                      wrote on last edited by
                      #10

                      @AdrianLV said in Running application in Android reduced functionalities for QList:

                      What would you suggest instead of moving windows?

                      Why do you want to move windows on Android? By default an application consumes the whole space (except the top and bottom bars).

                      "A QListWidget, but I erased it when I saw it not working" - so, it is not about QList but QListWidget? Did you debug the slot to see what happens?
                      You could also provide a minimal compilable example showing this issue.

                      https://forum.qt.io/topic/113070/qt-code-of-conduct

                      A 1 Reply Last reply
                      0
                      • A AdrianLV

                        @MartinGU

                        Example of bugreport: https://bugreports.qt.io/browse/QTBUG-128794

                        I see, but you still have not got a reply, right?

                        Use the first constructor, the one without filename.

                        Is this one better than: https://doc.qt.io/qt-6/qstandardpaths.html?

                        Thank you so much for your time!

                        M Offline
                        M Offline
                        MartinGU
                        wrote on last edited by
                        #11

                        @AdrianLV said in Running application in Android reduced functionalities for QList:

                        @MartinGU

                        Example of bugreport: https://bugreports.qt.io/browse/QTBUG-128794

                        I see, but you still have not got a reply, right?

                        I got a reply from Axel Spoerl that there are problems, but if/when it will be fixed is anyones guess.

                        Did I understand that that the redraw problems persist in QtQuick?

                        Use the first constructor, the one without filename.

                        Is this one better than: https://doc.qt.io/qt-6/qstandardpaths.html?

                        Depends on what you want. If you want to save data for your app, like settings/INI files then QSettings are best.
                        If you want to share your data with other apps, make it visible as a file to the user then use the correct QStandardPath.

                        Thank you so much for your time!
                        No worries :)

                        A 1 Reply Last reply
                        0
                        • jsulmJ jsulm

                          @AdrianLV said in Running application in Android reduced functionalities for QList:

                          What would you suggest instead of moving windows?

                          Why do you want to move windows on Android? By default an application consumes the whole space (except the top and bottom bars).

                          "A QListWidget, but I erased it when I saw it not working" - so, it is not about QList but QListWidget? Did you debug the slot to see what happens?
                          You could also provide a minimal compilable example showing this issue.

                          A Offline
                          A Offline
                          AdrianLV
                          wrote on last edited by
                          #12

                          Why do you want to move windows on Android?

                          I don't necessarily want it to be moving window, but I just wanted to open a second window in which I would be able to connect my device to my sensor.

                          You could also provide a minimal compilable example showing this issue.

                          Sorry, how is this done? Should I compress the build file and upload it here? Or is it compressing the files without the build?

                          Thank you for your time!

                          jsulmJ 1 Reply Last reply
                          0
                          • A AdrianLV

                            Why do you want to move windows on Android?

                            I don't necessarily want it to be moving window, but I just wanted to open a second window in which I would be able to connect my device to my sensor.

                            You could also provide a minimal compilable example showing this issue.

                            Sorry, how is this done? Should I compress the build file and upload it here? Or is it compressing the files without the build?

                            Thank you for your time!

                            jsulmJ Offline
                            jsulmJ Offline
                            jsulm
                            Lifetime Qt Champion
                            wrote on last edited by
                            #13

                            @AdrianLV said in Running application in Android reduced functionalities for QList:

                            but I just wanted to open a second window in which I would be able to connect my device to my sensor.

                            You should not do this on mobile platforms - this is against the style guidelines (mobile applications usually do not have more than one window).

                            "Sorry, how is this done? Should I compress the build file and upload it here?" - no, you simply provide a minimal application showing this issue, without any unnecessary code. This makes it easier to reproduce the issue and to debug it. You provided a lot of code, but most of it is not relevant for the issue.

                            https://forum.qt.io/topic/113070/qt-code-of-conduct

                            A A 2 Replies Last reply
                            0
                            • M MartinGU

                              @AdrianLV said in Running application in Android reduced functionalities for QList:

                              @MartinGU

                              Example of bugreport: https://bugreports.qt.io/browse/QTBUG-128794

                              I see, but you still have not got a reply, right?

                              I got a reply from Axel Spoerl that there are problems, but if/when it will be fixed is anyones guess.

                              Did I understand that that the redraw problems persist in QtQuick?

                              Use the first constructor, the one without filename.

                              Is this one better than: https://doc.qt.io/qt-6/qstandardpaths.html?

                              Depends on what you want. If you want to save data for your app, like settings/INI files then QSettings are best.
                              If you want to share your data with other apps, make it visible as a file to the user then use the correct QStandardPath.

                              Thank you so much for your time!
                              No worries :)

                              A Offline
                              A Offline
                              AdrianLV
                              wrote on last edited by
                              #14

                              @MartinGU

                              but if/when it will be fixed is anyones guess.

                              That is a shame...

                              Did I understand that that the redraw problems persist in QtQuick?

                              I did not try my application with QtQuick, I was ready to try to do the transition, but I thought of a workaround that I don't like, but I guess for now it will be the solution(Not displaying a second window, but just connect directly to a pre saved UUID device).

                              Depends on what you wan

                              Wow, thank you so much!

                              1 Reply Last reply
                              0
                              • jsulmJ jsulm

                                @AdrianLV said in Running application in Android reduced functionalities for QList:

                                but I just wanted to open a second window in which I would be able to connect my device to my sensor.

                                You should not do this on mobile platforms - this is against the style guidelines (mobile applications usually do not have more than one window).

                                "Sorry, how is this done? Should I compress the build file and upload it here?" - no, you simply provide a minimal application showing this issue, without any unnecessary code. This makes it easier to reproduce the issue and to debug it. You provided a lot of code, but most of it is not relevant for the issue.

                                A Offline
                                A Offline
                                AdrianLV
                                wrote on last edited by
                                #15

                                @jsulm

                                You should not do this on mobile platforms

                                I see... Thank you for the advice

                                no, you simply provide a minimal application showing this issue, without any unnecessary code.

                                I created this small app, should be created as widget app with a ui. I compiled it with Clang arm64-68. Add a QListWidget Item and call it list to the window, add 2 buttons one called refill and other one clear and add slots on clicked

                                void MainWindow::on_refill_clicked()
                                {
                                    for (int var = 0; var < 6; ++var) {
                                        new QListWidgetItem(QString::number(var), ui->list);
                                    }
                                
                                }
                                
                                
                                void MainWindow::on_clear_clicked()
                                {
                                    ui->list->clear();
                                }
                                

                                In my device, when running it you can see how the list gets partially cleared and partially filled.

                                jsulmJ 1 Reply Last reply
                                0
                                • A AdrianLV

                                  @jsulm

                                  You should not do this on mobile platforms

                                  I see... Thank you for the advice

                                  no, you simply provide a minimal application showing this issue, without any unnecessary code.

                                  I created this small app, should be created as widget app with a ui. I compiled it with Clang arm64-68. Add a QListWidget Item and call it list to the window, add 2 buttons one called refill and other one clear and add slots on clicked

                                  void MainWindow::on_refill_clicked()
                                  {
                                      for (int var = 0; var < 6; ++var) {
                                          new QListWidgetItem(QString::number(var), ui->list);
                                      }
                                  
                                  }
                                  
                                  
                                  void MainWindow::on_clear_clicked()
                                  {
                                      ui->list->clear();
                                  }
                                  

                                  In my device, when running it you can see how the list gets partially cleared and partially filled.

                                  jsulmJ Offline
                                  jsulmJ Offline
                                  jsulm
                                  Lifetime Qt Champion
                                  wrote on last edited by
                                  #16

                                  @AdrianLV This is a piece of code, not a minimal application.
                                  But OK.
                                  "you can see how the list gets partially cleared and partially filled" - you mean not all entries are removed if you clear the list and if you add 6 entries you see less than 6 of them in the UI? And this only happens on Android?
                                  Does "ui->list->update();" after clearing the list or adding entries to it help?

                                  https://forum.qt.io/topic/113070/qt-code-of-conduct

                                  A 1 Reply Last reply
                                  0
                                  • jsulmJ jsulm

                                    @AdrianLV This is a piece of code, not a minimal application.
                                    But OK.
                                    "you can see how the list gets partially cleared and partially filled" - you mean not all entries are removed if you clear the list and if you add 6 entries you see less than 6 of them in the UI? And this only happens on Android?
                                    Does "ui->list->update();" after clearing the list or adding entries to it help?

                                    A Offline
                                    A Offline
                                    AdrianLV
                                    wrote on last edited by
                                    #17

                                    @jsulm

                                    This is a piece of code, not a minimal application.

                                    Sorry, how can I share the minimal application?

                                    you mean not all entries are removed if you clear the list and if you add 6 entries you see less than 6 of them in the UI? And this only happens on Android?

                                    All entries are removed on the backend, but not on the graphics(Only when you click 2 times the clear button you can see that they were removed). After adding the elements, you can see only after the second adding that there is something being added. And yes, in my computer it is working normally.

                                    Does "ui->list->update();" after clearing the list or adding entries to it help?

                                    Sadly, not...

                                    jsulmJ 1 Reply Last reply
                                    0
                                    • A AdrianLV

                                      @jsulm

                                      This is a piece of code, not a minimal application.

                                      Sorry, how can I share the minimal application?

                                      you mean not all entries are removed if you clear the list and if you add 6 entries you see less than 6 of them in the UI? And this only happens on Android?

                                      All entries are removed on the backend, but not on the graphics(Only when you click 2 times the clear button you can see that they were removed). After adding the elements, you can see only after the second adding that there is something being added. And yes, in my computer it is working normally.

                                      Does "ui->list->update();" after clearing the list or adding entries to it help?

                                      Sadly, not...

                                      jsulmJ Offline
                                      jsulmJ Offline
                                      jsulm
                                      Lifetime Qt Champion
                                      wrote on last edited by
                                      #18

                                      @AdrianLV said in Running application in Android reduced functionalities for QList:

                                      Sorry, how can I share the minimal application?

                                      You can upload it to some file sharing service and post the link here.

                                      To me it sounds like a bug. You can report it on Qt Bug Tracker adding a minimal application. Keep in mind that for mobile platforms Qt Company prefers QML/QtQuick over QtWidgets.

                                      https://forum.qt.io/topic/113070/qt-code-of-conduct

                                      D 1 Reply Last reply
                                      0
                                      • jsulmJ jsulm

                                        @AdrianLV said in Running application in Android reduced functionalities for QList:

                                        but I just wanted to open a second window in which I would be able to connect my device to my sensor.

                                        You should not do this on mobile platforms - this is against the style guidelines (mobile applications usually do not have more than one window).

                                        "Sorry, how is this done? Should I compress the build file and upload it here?" - no, you simply provide a minimal application showing this issue, without any unnecessary code. This makes it easier to reproduce the issue and to debug it. You provided a lot of code, but most of it is not relevant for the issue.

                                        A Offline
                                        A Offline
                                        ankou29666
                                        wrote on last edited by
                                        #19

                                        @jsulm said in Running application in Android reduced functionalities for QList:

                                        @AdrianLV said in Running application in Android reduced functionalities for QList:

                                        but I just wanted to open a second window in which I would be able to connect my device to my sensor.

                                        You should not do this on mobile platforms - this is against the style guidelines (mobile applications usually do not have more than one window).

                                        StackLayout in QML or QStackLayout or QStackWidget (among others) for QtWidgets could be considered as an alternative to a popup window.

                                        1 Reply Last reply
                                        0
                                        • jsulmJ jsulm

                                          @AdrianLV said in Running application in Android reduced functionalities for QList:

                                          Sorry, how can I share the minimal application?

                                          You can upload it to some file sharing service and post the link here.

                                          To me it sounds like a bug. You can report it on Qt Bug Tracker adding a minimal application. Keep in mind that for mobile platforms Qt Company prefers QML/QtQuick over QtWidgets.

                                          D Offline
                                          D Offline
                                          drwho 0
                                          wrote on last edited by
                                          #20

                                          @jsulm said in Running application in Android reduced functionalities for QList:

                                          Keep in mind that for mobile platforms Qt Company prefers QML/QtQuick over QtWidgets.

                                          Did Qt communicate this somewhere?

                                          jsulmJ 1 Reply Last reply
                                          0

                                          • Login

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Users
                                          • Groups
                                          • Search
                                          • Get Qt Extensions
                                          • Unsolved