QChart slows down in QT application - c++

So im writing a QT application that will read values from a serial port and display them in a graph during runtime. I managed to update my QChart during runtime with just a random generated value to try out updating in real time and it all works fine.
But my application slows down the more and more i append until it gets completely unusable.
I do understand that the list containing my points grows, but after a 100 points or so it really really slows down, thats really fast, it feels like i have some sort of memory leak?
I know the usual answer is "Don't use QCharts" but im a beginner at both C++ and QT so this is what i'm using for simplicity.
MainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtCharts/QChartView>
#include <QtCharts/QLineSeries>
#include <QGridLayout>
#include <QLabel>
#include <QDebug>
QT_CHARTS_USE_NAMESPACE
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
series = new QLineSeries();
chart = new QChart();
chart->legend()->hide();
chart->addSeries(series);
chart->createDefaultAxes();
chart->axes(Qt::Vertical).back()->setRange(-10, 10);
chart->axes(Qt::Horizontal).back()->setRange(0, 100);
chart->setContentsMargins(0, 0, 0, 0);
chart->setBackgroundRoundness(0);
QChartView *chartView = new QChartView(chart);
chartView->setRenderHint(QPainter::Antialiasing);
ui->setupUi(this);
QLabel *label = new QLabel();
label->setText("Hello World");
QGridLayout *layout = new QGridLayout;
QWidget * central = new QWidget();
setCentralWidget(central);
centralWidget()->setLayout(layout);
layout->addWidget(chartView, 0, 0);
clock = 0;
SerialPortReader *reader = new SerialPortReader(this);
connect(reader, SIGNAL(onReadValue(int)), this, SLOT(onReadValue(int)));
reader->run();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::onReadValue(int value){
++clock;
series->append(clock + 30, value);
chart->axes(Qt::Horizontal).back()->setRange(0 + clock, 100 + clock);
}
SerialPortReader.cpp
#include "serialportreader.h"
#include "mainwindow.h"
#include <QtCore>
#include <QRandomGenerator>
#include <QDebug>
SerialPortReader::SerialPortReader(QObject *parent) : QThread(parent)
{
this->parent = parent;
this->randomGenerator = QRandomGenerator::global();
}
void SerialPortReader::run() {
QTimer *timer = new QTimer(this);
timer->start(100);
connect(timer, SIGNAL(timeout()), this, SLOT(readValue()));
}
void SerialPortReader::readValue() {
int value = randomGenerator->bounded(-10, 10);
emit onReadValue(value);
}
I was just wondering if anyone has any suggestion to what could be wrong? or if there is a anything i can do, except for changing chart-lib.

After tinkering around i found out that the culprit wasn't actually a memory leak it was the:
chartView->setRenderHint(QPainter::Antialiasing);
As more and more data was presented the slower it got to do all the Antialiasing.
When i removed this everything suddenly went very smooth.

Related

Creating a 10x10 field of pushButtons

Hey I want to create a 8x8 field of pushButtons. When using this Code
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QVector>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
QGridLayout* layout = new QGridLayout();
ui->centralwidget->setLayout(layout);
QVector<QVector<QPushButton*>> buttons2DVector(8);
for (int i=0;i<8;i++){
buttons2DVector[i].resize(8);
for(int j=0;j<8;j++){
QPushButton *b = new QPushButton("button");
layout->addWidget(b,i,j);
buttons2DVector[i][j] = b;
}
}
the error is:
unknown type Name "QGridLayout"
unknown type Name "ui"
the Code was given to me but I dont know how to use it properly. As you can probably see I am a beginner in QT and C++ but it would be nice if someone could help me.
Assuming you added the following to your MainWindow class declaration:
QVector<QVector<QPushButton*>> buttons2DVector(8);
void createGrid();
You could create the grid programmatically as follows:
#include "mainwindow.h"
#include <QVector>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
createGrid();
}
void MainWindow::createGrid() {
QFrame *frame = new QFrame(this);
QGridLayout *layout = new QGridLayout(frame);
for (int i=0;i<8;i++){
buttons2DVector[i].resize(8);
for(int j=0;j<8;j++){
QPushButton *b = new QPushButton("button", layout);
layout->addWidget(b,i,j);
buttons2DVector[i][j] = b;
}
}
setCentralWidget(frame);
}

QPushButton color change in QLineEdit eventFilter

I would like to make a push button visible when I insert a number in one of the lineedit. The button and linedit are on the same row. I know the position or name of the lineedit but i dont know how to link back to the push button to make it visible or to be able to change color.
If you look in the eventFilter thats where I'm stuck and I need some help.
Thank you
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QLineEdit>
#include <QPushButton>
#include <QGridLayout>
#include <QLabel>
#include <QRegion>
#include <QLayoutItem>
#include <QList>
#include<QObject>
#include <QEvent>
#include <QKeyEvent>
#include <QModelIndexList>
#include <QKeySequence>
#include <QSignalMapper>
#include<QIntValidator>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->scrollArea->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn );
ui->scrollArea->setWidgetResizable( true );
QWidget *widget = new QWidget(this);
ui->scrollArea->setWidget( widget );
QGridLayout *gridLayout = new QGridLayout();
widget->setLayout( gridLayout );
QPushButton *button[20];
for (int i = 0; i < 20; i++)
{
QLabel *label = new QLabel( QString( "%1" ).arg( i ) );
gridLayout->addWidget(label,i,1,1,1 );
gridLayout->setColumnMinimumWidth(1, 100);
gridLayout->setColumnMinimumWidth(2, 10);
if (i==5)
{
QLineEdit *lineEdit = new QLineEdit;
gridLayout->addWidget(lineEdit,i,5,1,1);
} else
{
QLineEdit *lineEdit = new QLineEdit(this);
gridLayout->addWidget(lineEdit,i,3,1,1);
lineEdit->setValidator(new QIntValidator(0,100,this));
lineEdit->setObjectName(QString::number(i));
lineEdit->installEventFilter(this);
gridLayout->setColumnMinimumWidth(4, 25);
gridLayout->setColumnMinimumWidth(5, 50);
gridLayout->setColumnMinimumWidth(6, 25);
QLineEdit *lineEdit_B = new QLineEdit;
gridLayout->addWidget(lineEdit_B,i,7,1,1);
lineEdit_B->setValidator(new QIntValidator(0,100,this));
gridLayout->setColumnMinimumWidth(8, 10);
}
gridLayout->setColumnMinimumWidth(9, 10);
button[i] = new QPushButton();
gridLayout->addWidget(button[i],i,10,1,1);
gridLayout->setColumnStretch(10,20);
button[i]->setFixedHeight(20);
button[i]->setFixedWidth(20);
button[i]->setStyleSheet("background-color:red;");
button[i]->setText(QString::number(i));
QRegion* region = new QRegion(*(new QRect(button[i]->x(),button[i]->y(),15,15)),QRegion::Ellipse);
button[i]->setMask(*region);
button[i]->setVisible(false);
gridLayout->setColumnMinimumWidth(10, 50);
gridLayout->setColumnMinimumWidth(11, 10);
}
}
MainWindow::~MainWindow()
{
delete ui;
}
bool MainWindow::eventFilter(QObject * obj, QEvent *event)// *event)
{
if (event->type() == QEvent::KeyPress)
{
ui->lineEdit->setText(QString("%1").arg(obj->objectName()));
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
qDebug() << "key " << keyEvent->key() << "from" << obj;
// HERE'S WHERE I NEED HELP
QPushButton* button = ui->scrollArea->findChild<QPushButton*>();
// I think here I would use a for loop to match the listedit
// with a number with the corresponding push button.
// When i find the push button I set it to yellow.
}
return QObject::eventFilter(obj, event);
}
void MainWindow::on_pushButton_clicked()
{
}
It is not necessary to use eventFilter, you complicate the task since it is difficult to discriminate which element it is. One possible option is to use the textChanged signal to display the button.
Also you had many tasks that are executed many times in the loop unnecessarily, those tasks that do not depend on the index must be out.
Also if you are going to store buttons do not use arrays, use containers like QList.
Also, you should not create pointers indiscriminately, since it is your responsibility to eliminate them, for example, QRegion is passed by value to setMask(), so it is not necessary to create a pointer.
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QGridLayout>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QScrollArea>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->scrollArea->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn );
ui->scrollArea->setWidgetResizable( true );
QWidget *widget = new QWidget(this);
ui->scrollArea->setWidget( widget );
QGridLayout *gridLayout = new QGridLayout(widget);
for(int i=0; i<20; i++){
QLabel *label = new QLabel(QString::number(i));
gridLayout->addWidget(label, i, 1);
QPushButton *button = new QPushButton(QString::number(i));
gridLayout->addWidget(button,i,10,1,1);
button->setFixedSize(20, 20);
button->setStyleSheet("background-color:red;");
QRegion region(QRect(button->pos(),QSize(15,15)),QRegion::Ellipse);
button->setMask(region);
button->hide();
if(i==5){
QLineEdit *lineEdit = new QLineEdit;
gridLayout->addWidget(lineEdit,i,5);
connect(lineEdit, &QLineEdit::textChanged, [button](const QString &text){
button->setVisible(!text.isEmpty());
});
}
else{
QLineEdit *lineEdit_A = new QLineEdit;
gridLayout->addWidget(lineEdit_A,i,3);
lineEdit_A->setValidator(new QIntValidator(0,100,this));
QLineEdit *lineEdit_B = new QLineEdit;
gridLayout->addWidget(lineEdit_B,i, 7);
lineEdit_B->setValidator(new QIntValidator(0,100,this));
connect(lineEdit_A, &QLineEdit::textChanged, [button](const QString &text){
button->setVisible(!text.isEmpty());
});
connect(lineEdit_B, &QLineEdit::textChanged, [button](const QString &text){
button->setVisible(!text.isEmpty());
});
}
}
gridLayout->setColumnMinimumWidth(1, 100);
gridLayout->setColumnMinimumWidth(2, 10);
gridLayout->setColumnMinimumWidth(4, 25);
gridLayout->setColumnMinimumWidth(5, 50);
gridLayout->setColumnMinimumWidth(6, 25);
gridLayout->setColumnMinimumWidth(8, 10);
gridLayout->setColumnMinimumWidth(9, 10);
gridLayout->setColumnStretch(10,20);
gridLayout->setColumnMinimumWidth(10, 50);
gridLayout->setColumnMinimumWidth(11, 10);
}
MainWindow::~MainWindow()
{
delete ui;
}
The complete example can be found in the following link.

How do I access Awesomefonts in Qt on OpenSuse

I wish to use some of the icons in fontawesome (http://fontawesome.io/icons) in my Qt Application, I have extracted the fontawesome-webfont.ttf file into usr/share/fonts.I tried searching online but could n't find any such examples.This is a sample code I have written for extracting an image out of a Resource(not what is required) and also accessing some Qfonts that were existent in Qfont library itself.( i.e courier new in the example below).
#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QPixmap>
#include <QLabel>
#include <QHBoxLayout>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
centralWidget = new QWidget(this);
gridLayout = new QGridLayout( centralWidget );
mylabel = new QLabel();
mylabel2= new QLabel();
font = new QFont("courier");
addresspic = new QPixmap(":/new/prefix1/address.png");
*addresspic=addresspic->scaled(50,50,Qt::KeepAspectRatio, Qt::FastTransformation);
mylabel->setPixmap(*addresspic);
mylabel2->setTextFormat(Qt::RichText);
mylabel2->setGeometry(QRect(QPoint(100,100),QSize(150, 150)));
mylabel2->setText(" ADDRESS ICON ");
gridLayout->addWidget(mylabel2);
gridLayout->addWidget(mylabel);
font->setItalic(true);
font->setPixelSize(20);
mylabel2->setFont(*font);
// gridLayout->setVerticalSpacing(1);
// gridLayout->setHorizontalSpacing(1);
this->setCentralWidget(centralWidget);
}
MainWindow::~MainWindow()
{
delete ui;
}
Thanks again
EDIT: The screenshot of error
EDIT 2: Trying G.M.'s method resulted in the following error : Any Idea why?
From https://github.com/dridk/QFontIcon download and add the qfonticon.h and qfonticon.cpp files to your project, then create the icons with the following code:
QFontIcon::addFont("/path/your/fonts/{your font}.ttf");
QIcon icon = QFontIcon::icon(0xf2b9);
{your widget}->setIcon(icon);
Example:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPushButton>
#include "qfonticon.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QWidget *centralWidget;
QGridLayout *gridLayout;
centralWidget = new QWidget(this);
gridLayout = new QGridLayout( centralWidget );
QFontIcon::addFont("/usr/share/fonts/fontawesome-webfont.ttf");
for(int i = 0; i < 15; i++){
QIcon icon = QFontIcon::icon(0xf2b9+i);
QPushButton *b = new QPushButton();
b->setIcon(icon);
gridLayout->addWidget(b);
}
this->setCentralWidget(centralWidget);
}
MainWindow::~MainWindow()
{
delete ui;
}
More Information: https://github.com/dridk/QFontIcon
I tested it with Qt 5.7 and Qtcreator 4.2
Try loading the font explicitly with...
int fid = QFontDatabase::addApplicationFont("/usr/share/fonts/fontawesome-webfont.ttf");
You can then query the font family name(s) using...
QFontDatabase::applicationFontFamilies(fid);
In my case the above resulted in the single family name "FontAwesome". That being the case you should then be able to use the font with...
QFont f("FontAwesome");
Note: The above seems to work as far as it goes but specifying a point size for the font isn't working as expected. Not sure why as the ttf file appears to contain the requested glyph sizes.
Edit 1
The QFont as constructed above can be used like any other unicode font. So a QLabel could be created with...
QLabel label;
label.setFont(QFont("FontAwesome"));
label.setText("\uf0fe"); /* f0fe is the code point for fa-plus-square */
Note that the answer provided by #eyllanesc is probably a far better approach. I'm simply adding this edit for completeness sake.

Playing video on fullscreen mode in QT

I want to play(shared, not multiple) video file(mp4) using QMediaPlayer(with output videothread to QGraphicsVideoItem) on multiple monitors on the single computer, connected by HDMI/DVI cable.
I made a video playback on a single monitor, but I need to play this video on several monitors as one.
I need of crossplatform(Linux/Windows) solution and i must provide configuration monitors for playing video in my application.
Whether it is possible to organize a means of QT 5.4 or extended C++ libraries?
If yes, please prompt me the best way to do it.
Sorry for bad English and thanks for the help in advance!
Hello! I need to make playing video overlay images.
I am used QT components QMediaPlayer and QGraphicsVideoItem to organize it.
But I could not stretch the video to fill the screen(fullscreen mode).
It looks like this:
Please, help me. Thank you.
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QWebView>
#include <QVBoxLayout>
#include <QFile>
#include <QMediaPlayer>
#include <QtMultimedia>
#include <QGraphicsVideoItem>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QVBoxLayout *layout = new QVBoxLayout;
layout->setContentsMargins(0, 0, 0, 0);
this->centralWidget()->setLayout(layout);
layout->addWidget(ui->graphicsView);
ui->graphicsView->setStyleSheet("background: transparent");
this->showMaximized();
QMediaPlayer * player = new QMediaPlayer();
QGraphicsVideoItem *item = new QGraphicsVideoItem;
QGraphicsScene * scene = new QGraphicsScene;
item->setSize(QSize(ui->graphicsView->width(),ui->graphicsView->height()));
ui->graphicsView->setScene(scene);
player->setVideoOutput(item);
qDebug() << item;
ui->graphicsView->scene()->addItem(item);
QPixmap pix1( "/home/ibragim/examples/ntv.png" );
player->setMedia(QUrl::fromLocalFile("/home/ibragim/examples/sm.mp4"));
player->play();
ui->graphicsView->show();
ui->graphicsView->scene()->addPixmap(pix1.scaledToHeight(100))->setPos(160,30);
}
MainWindow::~MainWindow()
{
delete ui;
}
this might do what you desire ...
void QGraphicsView::fitInView(const QGraphicsItem * item, Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio)
This is an overloaded function.
Ensures that item fits tightly inside the view, scaling the view according to aspectRatioMode.

QGridlayout changes height of row

I have a problem with a QGridLayout. One row of my layout contains an element (QProgressbar) that is normaly hidden. When there is some progress to report i call show on it. The problem is that when i call show on the QProgressbar the row above the row containing it will be slightly resized in height (1-3 px). So the whole layout does a little "jump" which looks ugly.
I have given a minimalRowHeight to the row that contains the QProgressbar that is much larger then the height of the QProgressbar but still the height of the row will increase on show().
I have attached a very minimal version of my program that demonstrates the problem. Can anyone give me a hint what is going on there?
Header:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QtGui/QMainWindow>
#include <QLineEdit>
#include <QtWebKit/QWebView>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
private:
QLineEdit* input;
QWebView *webview;
private slots:
void slotLoadButton();
};
#endif // MAINWINDOW_H
Source:
#include "mainwindow.h"
#include <QProgressBar>
#include <QPushButton>
#include <QGridLayout>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QGridLayout *grid = new QGridLayout;
input = new QLineEdit;
QPushButton *loadButton = new QPushButton("load");
connect(loadButton, SIGNAL(clicked()),
this, SLOT(slotLoadButton()));
webview = new QWebView;
QProgressBar *progress = new QProgressBar;
progress->setFixedHeight(25);
progress->hide();
connect(webview, SIGNAL(loadStarted()),
progress, SLOT(show()));
connect(webview, SIGNAL(loadProgress(int)),
progress, SLOT(setValue(int)));
connect(webview, SIGNAL(loadFinished(bool)),
progress, SLOT(hide()));
grid->addWidget(input, 0, 0);
grid->addWidget(loadButton, 0, 1);
grid->addWidget(webview, 1, 0, 1, -1);
grid->setRowMinimumHeight(2, 35);
grid->addWidget(progress, 2, 1);
QWidget* widget = new QWidget;
widget->setLayout(grid);
setCentralWidget(widget);
}
void MainWindow::slotLoadButton()
{
QUrl url = input->text();
webview->load(url);
}
This is likely caused by the vertical spacing and/or margins of the layout. You should try playing with those properties.
This looks like a bug in Qt. Try reporting it
This is a workaround:
//grid->addWidget(progress, 2, 1);
QHBoxLayout *l = new QHBoxLayout;
l->addWidget(progress);
QWidget *w = new QWidget;
w->setLayout(l);
grid->addWidget(w, 2, 1);