Running application in Android reduced functionalities for QList
-
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 LopezP.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 ¶ms); 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 ¶ms) { 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); }
-
@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.
-
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-128794If 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
-
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. -
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.
-
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!
-
@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! -
@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. -
@AdrianLV said in Running application in Android reduced functionalities for QList:
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 :) -
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!
-
@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.
-
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!
-
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.
-
@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? -
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...
-
@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.
-
@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.