Data labels in linechart Qt Charts - qt

I am trying to add data labels in LineChart using Qt Charts
like this Image.
I am not able to figure out how I can do that. Any help will be appreciated.
I am using this example https://doc.qt.io/qt-5/qtcharts-linechart-example.html
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QLineSeries *series = new QLineSeries();
series->append(0, 6);
series->append(2, 4);
series->append(3, 8);
series->append(7, 4);
series->append(10, 5);
QChart *chart = new QChart();
chart->legend()->hide();
chart->addSeries(series);
chart->createDefaultAxes();
chart->setTitle("Simple line chart example");
QChartView *chartView = new QChartView(chart);
chartView->setRenderHint(QPainter::Antialiasing);
QMainWindow window;
window.setCentralWidget(chartView);
window.resize(400, 300);
window.show();
return a.exec();
}
I get following output
I want something like this

Have you tried to set the labels to visible?
QLineSeries *series = new QLineSeries();
series->setPointLabelsVisible(true); // is false by default
series->setPointLabelsColor(Qt::black);
series->setPointLabelsFormat("#yPoint");

Related

How to create Subplot using QCharts?

I want to create two subplots (like 2 rows), the first plot will show the line series graph based on Analog to Digital Converter counts stored in a text file and the second plot will show the line series graph based on Temperature values stored in a text file.
I am able to plot the line series in the same plot, but I want to plot it in two separate subplots.
#include <QApplication>
#include <QMainWindow>
#include <QFile>
#include <QTextStream>
#include <QDateTime>
#include <QTime>
#include <QtCharts/QChartView>
#include <QtCharts/QLineSeries>
#include <QDateTimeAxis>
#include <QValueAxis>
#include <QDebug>
QT_CHARTS_USE_NAMESPACE
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// Open File
QFile file("D:\\Projects\\Embedded\\ArduinoTempLogger\\01-21-18.txt");
if( !file.open(QIODevice::ReadOnly|QIODevice::Text) )
{
qDebug() << "File don't exist";
return 1;
}
QTextStream stream(&file);
QLineSeries *adc_series = new QLineSeries();
QLineSeries *temp_series = new QLineSeries();
QDateTime datetime = QDateTime::currentDateTime();
while( !stream.atEnd() )
{
QString line = stream.readLine();
QStringList values = line.split(",");
QTime time;
time = QTime::fromString(values[0], "hh:mm:ss");
datetime.setTime(time);
adc_series->append( datetime.toMSecsSinceEpoch(), values[1].toUInt() );
temp_series->append( datetime.toMSecsSinceEpoch(), values[2].toDouble() );
// qDebug() << time.toString("hh:mm:ss") << "-->" << datetime.toMSecsSinceEpoch();
}
file.close();
QChart *chart = new QChart();
chart->legend()->hide();
chart->addSeries(adc_series);
chart->addSeries(temp_series);
// chart->createDefaultAxes();
chart->setTitle("Temperature Plot");
// Since we use QLineSeries, calling createDefaultAxes will create QValueAxis both as X and Y axis.
// To use QDateTimeAxis we need to set it manually to the chart.
// First, the instance of QDateTimeAxis is created, then the number of ticks to be shown is set.
//
QDateTimeAxis *axisX = new QDateTimeAxis;
axisX->setTickCount(10);
axisX->setFormat("hh:mm:ss");
axisX->setTitleText("Time Axis");
chart->addAxis(axisX, Qt::AlignBottom);
adc_series->attachAxis(axisX);
temp_series->attachAxis(axisX);
QValueAxis *axisY = new QValueAxis;
axisY->setLabelFormat("%i");
axisY->setTitleText("Temperature and ADC Value");
axisY->setRange(0, 100);
chart->addAxis(axisY, Qt::AlignLeft);
adc_series->attachAxis(axisY);
temp_series->attachAxis(axisY);
QChartView *chartView = new QChartView(chart);
chartView->setRenderHint(QPainter::Antialiasing);
QMainWindow window;
window.setCentralWidget(chartView);
window.resize(820, 600);
window.show();
return a.exec();
}
The data which I am reading from the file is in the following format.
16:08:45,50,24.4
16:08:46,47,22.9
16:08:47,60,29.3
16:08:48,45,22
16:08:49,49,23.9
16:08:50,54,26.4
16:08:51,46,22.5
16:08:52,40,19.5
16:08:53,50,24.4
16:08:54,50,24.4
16:08:55,50,24.4
16:08:56,59,28.8
16:08:57,49,23.9
16:08:58,62,30.3
16:08:59,58,28.3
16:09:00,47,22.9
16:09:01,54,26.4
16:09:02,61,29.8
16:09:03,47,22.9
16:09:04,50,24.4
16:09:05,55,26.9
16:09:06,46,22.5
16:09:07,60,29.3
16:09:08,49,23.9
16:09:09,57,27.8
16:09:10,42,20.5
16:09:11,49,23.9
16:09:12,56,27.3
16:09:13,64,31.3
16:09:14,51,24.9
16:09:15,53,25.9
16:09:16,57,27.8
I am using Qt 5.14.1 on Windows 10
Can someone please guide me achieving in this?
Thanks in advance.
There is no direct solution provided by Qt, so there are several alternatives:
Create 2 QChartView and place them inside a QVBoxLayout.
Create 2 QChart and place them inside a QChartView using a QGraphicsLinearLayout.
The first method is trivial so I will not show an example, however if I show the code of the second method:
#include <QtWidgets>
#include <QtCharts>
QT_CHARTS_USE_NAMESPACE
class GraphicsView: public QGraphicsView{
public:
GraphicsView(QWidget *parent=nullptr):QGraphicsView(parent){
setScene(new QGraphicsScene);
layout = new QGraphicsLinearLayout(Qt::Vertical);
form = new QGraphicsWidget;
form->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
form->setLayout(layout);
scene()->addItem(form);
layout->setSpacing(0);
}
void addChart(QChart *chart){
if(chart){
layout->addItem(chart);
}
}
protected:
void resizeEvent(QResizeEvent *event){
if(scene())
scene()->setSceneRect(QRect(QPoint(0, 0), event->size()));
if(form)
form->resize(event->size());
QGraphicsView::resizeEvent(event);
}
private:
QGraphicsWidget *form;
QGraphicsLinearLayout *layout;
};
static bool create_series(QLineSeries *adc_series, QLineSeries *temp_series){
QFile file("D:\\Projects\\Embedded\\ArduinoTempLogger\\01-21-18.txt");
if( !file.open(QIODevice::ReadOnly|QIODevice::Text)){
qDebug() << "File don't exist";
return false;
}
QTextStream stream(&file);
QDateTime datetime = QDateTime::currentDateTime();
while( !stream.atEnd()){
QString line = stream.readLine();
QStringList values = line.split(",");
datetime.setTime(QTime::fromString(values[0], "hh:mm:ss"));
adc_series->append( datetime.toMSecsSinceEpoch(), values[1].toUInt() );
temp_series->append( datetime.toMSecsSinceEpoch(), values[2].toDouble() );
}
file.close();
return true;
}
static QChart* create_chart(const QString & title, QLineSeries *series){
QChart * chart = new QChart;
chart->legend()->hide();
chart->addSeries(series);
QDateTimeAxis *axisX = new QDateTimeAxis;
axisX->setTickCount(10);
axisX->setFormat("hh:mm:ss");
axisX->setTitleText("Time Axis");
chart->addAxis(axisX, Qt::AlignBottom);
series->attachAxis(axisX);
QValueAxis *adc_axisY = new QValueAxis;
adc_axisY->setLabelFormat("%i");
adc_axisY->setTitleText(title);
adc_axisY->setRange(0, 100);
chart->addAxis(adc_axisY, Qt::AlignLeft);
series->attachAxis(adc_axisY);
return chart;
}
int main(int argc, char *argv[]){
QApplication a(argc, argv);
QLineSeries *adc_series = new QLineSeries;
QLineSeries *temp_series = new QLineSeries;
if(!create_series(adc_series, temp_series))
return -1;
GraphicsView view;
view.addChart(create_chart("ADC Value", adc_series));
view.addChart(create_chart("Temperature Value", temp_series));
view.show();
view.resize(640, 480);
return a.exec();
}
On the other hand, Qt has not given much love to Qt Charts, so simple tasks such as subplots do not exist, so I recommend using other libraries such as QCustomPlot that do offer that functionality, in this link there is an example.

QScrollArea Child Widget size set according to to Parents size change

I want to fit (child) widget into the parent widget size. So if the parent window is too small to display all the elements of the child widget the QScrollArea should appear otherwise it should be invisible.
I have attached the pictures for a better understanding.
The black box is where I want my scroll to appear. Since when we reduce the size of the window, sometimes you can't see the scroll bar (as displayed in the below picture) it doesn't look elegant enough for big projects.
Please help me with the same, thanks in advance.
Here's the sample code that I used for example:
int main(int argc, char *argv[]){
QApplication a(argc, argv);
QScrollPractice w;
QDialog * dlg = new QDialog();
//dlg->setGeometry(100, 100, 260, 260);
dlg->setMinimumSize(150, 200);
QScrollArea *scrollArea = new QScrollArea(dlg);
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
scrollArea->setWidgetResizable(true);
//scrollArea->setGeometry(10, 10, 200, 200);
//scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Ignored);
//QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
scrollArea->setSizePolicy(sizePolicy);
QWidget *widget = new QWidget(scrollArea);
scrollArea->setWidget(widget);
QVBoxLayout *layout = new QVBoxLayout(widget);
widget->setLayout(layout);
for (int i = 0; i < 10; i++)
{
QPushButton *button = new QPushButton(QString("%1").arg(i));
layout->addWidget(button);
}
dlg->show();
return a.exec();
}
Your Dialog is missing a layout as well. Thats the reason the scrollArea Widget isnt spread out across the dialog.
#include <QApplication>
#include <QDialog>
#include <QScrollArea>
#include <QVBoxLayout>
#include <QPushButton>
int main(int argc, char* argv[]){
QApplication a(argc, argv);
QDialog* dlg = new QDialog();
dlg->setMinimumSize(150, 200);
QScrollArea* scrollArea = new QScrollArea(dlg);
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
scrollArea->setWidgetResizable(true);
QWidget* widget = new QWidget(scrollArea);
scrollArea->setWidget(widget);
QVBoxLayout* dlgLayout = new QVBoxLayout();
dlg->setLayout( dlgLayout );
dlgLayout->addWidget( scrollArea );
QVBoxLayout* layout = new QVBoxLayout(widget);
widget->setLayout(layout);
for (int i = 0; i < 10; i++)
{
QPushButton* button = new QPushButton(QString("%1").arg(i));
layout->addWidget(button);
}
dlg->show();
return a.exec();
}
I modified your code to make it run and compileable, also I added antoher QVBoxLayout and added it to the dialog. Then the scrollArea gets added to that Layout. Hope this helps.

How to set a QMetalRoughMaterial with QExtrudedTextMesh

I am trying to apply a metalic material texture to a 3D extruded text mesh.
I have based my example code on this:
https://code.woboq.org/qt5/qt3d/examples/qt3d/3d-text/main.cpp.html
The example uses the QPhongMaterial. I naively thought I could simply
replace that material by QMetalRoughMaterial which I tried.
#include <QCoreApplication>
#include <Qt3DCore/Qt3DCore>
#include <Qt3DExtras/Qt3DExtras>
#include <Qt3DExtras/QExtrudedTextMesh>
int main(int argc, char *argv[])
{
QGuiApplication a(argc, argv);
Qt3DExtras::Qt3DWindow *view = new Qt3DExtras::Qt3DWindow();
view->setTitle(QStringLiteral("3D Text CPP"));
view->defaultFrameGraph()->setClearColor(QColor("white"));
auto *root = new Qt3DCore::QEntity();
//Light
Qt3DCore::QEntity *lightEntity = new Qt3DCore::QEntity(root);
Qt3DRender::QPointLight *light = new Qt3DRender::QPointLight(lightEntity);
light->setColor("white");
light->setIntensity(0.5);
lightEntity->addComponent(light);
//auto *textMaterial = new Qt3DExtras::QPhongMaterial(root);
auto *textMaterial = new Qt3DExtras::QMetalRoughMaterial(root);
auto *text = new Qt3DCore::QEntity(root);
auto *textMesh = new Qt3DExtras::QExtrudedTextMesh();
auto *textTransform = new Qt3DCore::QTransform();
QFont font("Arial", 32, -1, false);
textTransform->setTranslation(QVector3D(-2.45f, 2.0 * .5f, 0));
textTransform->setScale(.8f);
textMesh->setDepth(.25f);
textMesh->setFont(font);
textMesh->setText("TEST");
//FOR PHONG MATERIAL
//textMaterial->setDiffuse(QColor("white"));
//textMaterial->setShininess(1.0);
//textMaterial->setSpecular(QColor("white"));
//FOR METAL
textMaterial->setBaseColor(QColor("blue"));
textMaterial->setMetalness(1.0);
textMaterial->setRoughness(0.2);
//textMaterial->setNormal(...)); //<-- what needs to come here?
text->addComponent(textMaterial);
text->addComponent(textMesh);
text->addComponent(textTransform);
// Camera
float aspect = static_cast<float>(view->screen()->size().width()) / view->screen()->size().height();
Qt3DRender::QCamera *camera = view->camera();
camera->lens()->setPerspectiveProjection(65.f, aspect, 0.1f, 100.f);
camera->setPosition(QVector3D(0, 1, 3));
camera->setViewCenter(QVector3D(0, 1, 0));
auto *cameraController = new Qt3DExtras::QOrbitCameraController(root);
cameraController->setCamera(camera);
view->setRootEntity(root);
view->show();
return a.exec();
}
With the code above, I see no text in the app window, whereas it works fine when using QPhongMaterial.
What am I missing here?

Qt GUI design programmatically

I'm try to create a GUI application.
The main window, a QMainWindow, contains 9 labels with fixed size and also the size of the main window.
I tried to make it programmatically without Qt GUI Designer. The project is built without error but I cannot see any label nor layout shown on the main window. it's just blank.
Here is my source code:
WCwindow::WCwindow()
{
// initialize widgets with text
CAM111 = new QLabel("CAM 01");
CAM121 = new QLabel("CAM 02");
CAM131 = new QLabel("CAM 03");
CAM211 = new QLabel("CAM 04");
CAM221 = new QLabel("CAM 05");
CAM231 = new QLabel("CAM 06");
CAM311 = new QLabel("CAM 07");
CAM321 = new QLabel("CAM 08");
CAM331 = new QLabel("CAM 09");
CAM111->setFixedSize(wcW,wcH);
CAM121->setFixedSize(wcW,wcH);
CAM131->setFixedSize(wcW,wcH);
CAM211->setFixedSize(wcW,wcH);
CAM221->setFixedSize(wcW,wcH);
CAM231->setFixedSize(wcW,wcH);
CAM311->setFixedSize(wcW,wcH);
CAM321->setFixedSize(wcW,wcH);
CAM331->setFixedSize(wcW,wcH);
QGridLayout *layout = new QGridLayout;
layout->addWidget(CAM111,0,0);
layout->addWidget(CAM121,0,1);
layout->addWidget(CAM131,0,2);
layout->addWidget(CAM211,1,0);
layout->addWidget(CAM221,1,1);
layout->addWidget(CAM231,1,2);
layout->addWidget(CAM311,2,0);
layout->addWidget(CAM321,2,1);
layout->addWidget(CAM331,2,2);
setLayout(layout);
setWindowTitle("Camera Window");
setFixedSize(1000, 800);
}
of course, the class is initialized and evoked in main.cpp:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
WCwindow *WCwin = new WCwindow;
WCwin->show();
return app.exec();
}
what kind of bug am I having??
The code below works fine. The problem was in the code you weren't showing. When you use a QMainWindow, as you've eventually admitted to doing, you need to set its centralWidget with a new widget that you construct.
// main.cpp
#include <QVector>
#include <QMainWindow>
#include <QLabel>
#include <QGridLayout>
#include <QApplication>
class WCwindow : public QMainWindow
{
public:
WCwindow();
private:
QVector<QLabel*> cams;
QLabel* cam(int r, int c) const {
return cams[r*3 + c];
}
};
WCwindow::WCwindow()
{
QGridLayout *layout = new QGridLayout;
for (int i = 1; i < 10; ++ i) {
QLabel * const label = new QLabel(QString("CAM %1").arg(i, 2, 10, QLatin1Char('0')));
label->setFixedSize(200, 50);
layout->addWidget(label, (i-1) / 3, (i-1) % 3);
cams << label;
}
QWidget * central = new QWidget();
setCentralWidget(central);
centralWidget()->setLayout(layout);
setWindowTitle("Camera Window");
setFixedSize(1000, 800);
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
WCwindow win;
win.show();
return app.exec();
}
Is WCwindow a subclass of QMainWindow? In that case i would advise to remove the layout from your window in the GUI editor by clicking the "break layout" button in the top bar, then use the following:
//setup all your labels and layout ...
//creating a QWidget, and setting the WCwindow as parent
QWidget * widget = new QWidget(this);
//set the gridlayout for the widget
widget->setLayout(layout);
//setting the WCwindow's central widget
setCentralWidget(widget);

QBoxLayout screws up QFormLayout?

Following simplified code snippet:
#include <QtGui>
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QWidget *window = new QWidget();
QFormLayout *form = new QFormLayout();
// first row
form->addRow("First row:", new QLineEdit());
// second row
QWidget *hbox_widget = new QWidget();
QBoxLayout *hbox = new QHBoxLayout();
hbox->addWidget(new QLineEdit());
hbox_widget->setLayout(hbox);
form->addRow("Second row:", hbox_widget);
window->setLayout(form);
window->show();
return app.exec();
}
Here, I create a QFormLayout with two rows: the first is a classic example of label+input widget, the second one is almost the same, with the exception that the input widget is "boxed" in a QHBoxLayout(+containing widget).
For some reason, this seems to screw up the "vertical centering" of the input widget (in the 2nd row). How can I add a widget which contains others in a hboxlayout to a formlayout, and still have them all centered vertically?
Set the contents margins of the QHBoxLayout to 0:
QBoxLayout *hbox = new QHBoxLayout();
hbox->setContentsMargins(0, 0, 0, 0);

Resources