I am currently experimenting a bit with the Qt DataVisualization.
The goal is that I have a QLineEdit and when I exit it, I use the QLineEdit::editingFinished signal. And then I set the value that was entered to the selected Bar.
I get an error on line 46 when I start the second for loop when I try to access the QBarDataItem. I am getting a Read Access Violation there and I get the error on this line of the qarraydatapointer.h file from Qt:
bool needsDetach() const noexcept { return !d || d->needsDetach(); }
Here my code :
Main file:
#include <QApplication>
#include <QFile>
#include "Window.h"
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// creates a window
Window window;
QFile file(app.applicationDirPath() + "/Test.txt");
// Writes the x and y position of the selected Bar
QObject::connect(window.getSeries(), &QBar3DSeries::selectedBarChanged, [&]() {
if (!file.open(QIODevice::ReadWrite)) {
QTextStream stream(&file);
stream << window.getSeries()->selectedBar().x() << ", "
<< window.getSeries()->selectedBar().y() << ", "
<< window.getSeries()->dataProxy()->rowAt(window.getSeries()->selectedBar().x())->data()->value() << "\n";
}
});
QFile file1(app.applicationDirPath() + "/Data.txt");
if (file1.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&file1);
QBarDataRow *data = new QBarDataRow;
while (!in.atEnd()) {
QString line = in.readLine();
*data << line.toFloat();
}
window.getSeries()->dataProxy()->addRow(data);
}
window.show();
file.close();
file1.close();
return app.exec();
}
Window.h:
#ifndef WINDOW_H
#define WINDOW_H
#include <QMainWindow>
#include <QtDataVisualization>
#define WIDTH 1400
#define HEIGHT 800
struct Data {
Data() {
data1 = new QBarDataRow;
data2 = new QBarDataRow;
data3 = new QBarDataRow;
data4 = new QBarDataRow;
data5 = new QBarDataRow;
}
~Data() {
delete data1;
delete data2;
delete data3;
delete data4;
delete data5;
}
public:
QList<QBarDataRow *> data{ data1, data2, data3, data4, data5 };
QBarDataRow *data1;
QBarDataRow *data2;
QBarDataRow *data3;
QBarDataRow *data4;
QBarDataRow *data5;
};
class Window : public QMainWindow {
Q_OBJECT
public:
Window(QWidget *parent = nullptr);
~Window();
QBar3DSeries *getSeries();
protected:
void resizeEvent(QResizeEvent *event) override;
private:
Q3DBars *m_bars;
QBar3DSeries *m_series;
Data *m_data;
QWidget *m_graph;
};
#endif // WINDOW_H
Window.cpp:
#include "Window.h"
#include <QLineEdit>
static void setData(Data *data, QBar3DSeries *series) {
*data->data1 << 1.0f << 3.0f << 6.5f << 5.0f << 2.2f;
*data->data2 << 2.0f << 1.5f << 5.0f << 2.0f << 2.4f;
*data->data3 << 3.0f << 2.5f << 4.0f << 1.0f << 3.4f;
*data->data4 << 2.9f << 2.5f << 2.3f << 3.1f << 1.7f;
//*data->data5 << 1.6f << 1.1f << 1.8f << 4.8f << 3.4f;
series->dataProxy()->addRow(data->data1);
series->dataProxy()->addRow(data->data2);
series->dataProxy()->addRow(data->data3);
series->dataProxy()->addRow(data->data4);
//series->dataProxy()->addRow(data->data5);
}
Window::Window(QWidget *parent) : QMainWindow(parent) {
// Initialising variables
m_bars = new Q3DBars;
m_series = new QBar3DSeries;
m_data = new Data;
setWindowTitle("Physik");
resize(WIDTH, HEIGHT);
m_bars->rowAxis()->setRange(0, 4);
m_bars->columnAxis()->setRange(0, 4);
m_bars->scene()->activeCamera()->setCameraPosition(30, 30);
// set values which can then be seen
setData(m_data, m_series);
m_bars->addSeries(m_series);
// Creates a QWidget, which is a child of the QMainWindow (this)
m_graph = QWidget::createWindowContainer(m_bars, this);
m_graph->setGeometry(0, 0, WIDTH * 0.7, HEIGHT);
//--------------------------------------------------------------
QLineEdit *lineEdit = new QLineEdit(this);
lineEdit->setGeometry(WIDTH * 0.75, HEIGHT * 0.1, WIDTH * 0.85, HEIGHT * 0.15);
connect(lineEdit, &QLineEdit::editingFinished, [&]() {
QPoint position = m_series->selectedBar();
for (size_t i{}; i < m_data->data.size(); ++i) {
if (i == position.x()) {
size_t j{};
for (auto &value : *m_data->data[i]) {
if (j == position.y()) {
value.setValue(lineEdit->text().toFloat());
}
++j;
}
break;
}
}
});
}
Window::~Window() {}
QBar3DSeries *Window::getSeries() {
return m_series;
}
void Window::resizeEvent(QResizeEvent *event) {
QMainWindow::resizeEvent(event);
if (m_graph) {
m_graph->resize(event->size().width() * 0.7, event->size().height());
}
}
I tried to write my own QBarDataItem and QBarDataRow who inherit public both classes and tried to rewrite the functions, but it didn't work, and I really tried a lot of different stuff. But nothing worked, so I hope you can help me.
I know it's better to make this problem not too specific so that many people can help. In the end, I am only trying that I have a selected Bar and when I get out of the QLineEdit the value is then being set to the selected Bar.enter code here
When your
m_dataobject is constructed, its constructor implicitly initializes thedatamember first, which is receiving a copy of thedata1..data5members before they have been initialized. Those members are initialized after thedatalist is populated, and the pointers stored in thedatalist are never being updated later. So thedatalist is left holding invalid pointers.So, inside of your
editingFinishedlambda, when your loop retrieves a stored pointer fromm_data->data[i]and tries to dereference that pointer, you experience Undefined Behavior, which in this case is resulting in a runtime error.Try this instead for your
Datastruct:Also, there's no real need to
new/deletethedata1..data5members manually at all, eg:Or:
That being said, you also don't need the secondary loops at all, since you already know exactly which item to update: