I was developping a datalogging application with Qt Creator (Qt 5.9) and I wanted to add a graph with the help of QtCharts.
I explain what I do:
I begin to declare my line as a global variable:
QLineSeries *serie;
In the loop of creating the mainwindow, I create a chart, standard axis and all I need to view the line where I want.
QChart *chart = new QChart();
chart->setTitle("Données accélération");
chart->setAnimationOptions(QChart::AllAnimations);
QChartView *chartView = new QChartView(chart);
chartView->setMinimumWidth(700);
chartView->setRenderHint(QPainter::Antialiasing);
ui->gridLayout_2->addWidget(chartView,0,3,3,1);
QLineSeries *serie = new QLineSeries();
//QSplineSeries *serie = new QSplineSeries();
serie->append(QPointF(50, 50));
serie->append(QPointF(55, 55));
QPen green(Qt::red);
green.setWidth(3);
serie->setPen(green);
chart->addSeries(serie);
chart->createDefaultAxes();
In another function, I use a serialevent to make some choices depending on a switch:
case acquisition :
reely = (recev_message.toInt())/1000;
reelx = index+1;
qDebug() << reely;
serie->append(reelx, reely);
index++;
After a freeze when I received a serial message, I launched a debug. And it seems that a SIGSEGV append at the step serie->append(reelx, reely);
I don't understand why I can't append a new value when in the example programs for Qtcharts it seems to work.
Thank you for your reading.
I found where is the problem.
I effectively declared the serie as a global variable. But in the mainvindow building function I wrote:
QLineSeries *serie = new QLineSeries();
It seems that the compiler deducted that I was re-declaring the object and changed the scope of it. And when I tried to use one of the members in another function, I wasn't in the right scope
So, I changed by that line:
serie = new QLineSeries();
And everything work like a charm.
Thanks to everybody
Related
Is there a way to connect QAbstractSeries to a clicked signal because the type of the QAbstractSeries is a QLineSeries?
I can do the following:
QlineSeries *series = new QLineSeries();
QChart *chart = new QChart();
series->append(1,1);
chart->addSeries(series);
connect(series, &QLineSeries::clicked, this, &View::myFunction);
But if i have defined the series in another class and i can only access the series through
QList<QAbstractSeries*> seriesList = chart->series();
I cannot connect a series through
connect(seriesList[0], &QAbstractSeries::clicked, this, &View::myFunction);
because QAbstractSeries has not a signal "clicked". But i can access the type through
seriesList[0].type();
But now i don't know how to handle the connection with this information. Or is there another way to get the series out of my chart as a QLineSeries?
The clicked signal is associated with the objects of the class QXYSeries and their derivatives such as QLineSeries so the solution is to make a casting to filter the series:
for(QAbstractSeries* series: chart->series()){
if(QXYSeries* xyseries = qobject_cast<QXYSeries *>(series)){
connect(xyseries, &QXYSeries::clicked, this, &View::myFunction);
}
}
With the previous code they will be applied to the classes derived from QXYSeries such as QLineSeries and QScatterSeries, but if you only want to apply to QLineSeries then you must do the following:
for(QAbstractSeries* series: chart->series()){
if(QLineSeries* lineseries = qobject_cast<QLineSeries *>(series)){
connect(lineseries, &QLineSeries::clicked, this, &View::myFunction);
}
}
I am using a QTreeWidget and setting a widget for the QTreeWidgetItem in the QTreeWidget. It is working fine but when I do the same for second time, the application is crashing.
The below is working fine.
QTreeWidget* treewidget = new QTreeWidget();
QTreeWidgetItem* item0 = new QTreeWidgetItem((QTreeWidget*)0, QStringList(QString("item0")));
treewidget->insertTopLevelItem(0,item0);
QSlider* slider0 = new QSlider();
treewidget->setItemWidget(item0, 0, slider0);
But if I add the last line once again, it is crashing when running the application.
The below is crashing.
QTreeWidget* treewidget = new QTreeWidget();
QTreeWidgetItem* item0 = new QTreeWidgetItem((QTreeWidget*)0, QStringList(QString("item0")));
treewidget->insertTopLevelItem(0,item0);
QSlider* slider0 = new QSlider();
treewidget->setItemWidget(item0, 0, slider0);
treewidget->setItemWidget(item0, 0, slider0); // Intentionally added to simulate the issue
The above is an example to show the issue, but in my application, based on some events, I delete the tree widget items and add it later. When I set the item widget (after adding the items later), I am getting the crash.
I could not figure out why. Any ideas? FYI, I am using Qt 5.3.2 MSVC 2010, 32 bit.
treewidget->setItemWidget(item0, 0, slider0);
treewidget->setItemWidget(item0, 0, slider0);// Intentionally added to simulate the issue
I look at Qt code (4.x):
void QTreeWidget::setItemWidget(QTreeWidgetItem *item, int column, QWidget *widget)
{
Q_D(QTreeWidget);
QAbstractItemView::setIndexWidget(d->index(item, column), widget);
}
and QAbstractItemView::setIndexWidget:
void QAbstractItemView::setIndexWidget(const QModelIndex &index, QWidget *widget)
{
Q_D(QAbstractItemView);
if (!d->isIndexValid(index))
return;
if (QWidget *oldWidget = indexWidget(index)) {
d->persistent.remove(oldWidget);
d->removeEditor(oldWidget);
oldWidget->deleteLater();
}
so if you add slider0 two times, then at first call it was added,
at seconds call Qt call for it deleteLater, and then added it,
are sure that this is what you want?
You have to set correct parent in the constructor of QTreeWidgetItem. Try this:
QTreeWidgetItem* item0 = new QTreeWidgetItem(treewidget);
Also it is important to understand who is owner of the slider0 after calling of setItemWidget(): the owner is your table, so 1) you don't need to delete this object; 2) the object will be deleted if you call setItemWidget for the same cell again. So, double call of treewidget->setItemWidget(item0, 0, slider0); seems very strange (second time you are setting the deleted object into that cell).
When I press a key there shall be a query to an engine. The results get put into a QListWidget by adding an item and setting the widget. Somehow this causes a massive memory overflow and even crashed my machine. But I dont get the error. Does clear() not delete the items passed to the QListWidget and the widgets set by setItemWidget(). I even tried to delete them on my own (comment), but still got a memoryleak. The error is in the if (!results.empty())-block, I guess, since commenting it out plugs the memoryleak.
void Widget::onTextEdited(const QString & text)
{
// QListWidgetItem * takenItem;
// while (takenItem = _results->takeItem(0)){
// delete _results->itemWidget(takenItem);
// delete takenItem;
// }
_results->clear(); _results->hide();
if (!text.isEmpty())
{
const std::vector<const Items::AbstractItem *> results = _engine.request(text);
if (!results.empty())
{
for (auto i : results){
QListWidgetItem *lwi = new QListWidgetItem;
_results->addItem(lwi);
ListItemWidget *w = new ListItemWidget;
w->setName(i->name());
w->setTooltip(i->path());
_results->setItemWidget(lwi, w);
}
_results->setFixedHeight(std::min(5,_results->count()) * 48); // TODO
_results->show();
}
}
this->adjustSize();
}
You should definitely use a memory leak detection tool instead of guessing around :)
UPDATE: clear() only deletes items but does not delete the widgets belonging to it. The widgets will be deleted if the QListWidget is deleted.
clear() does delete items and widgets belonging to it. And you mentioned that commenting out if(!results.empty()) solved the problem. I don't see any problem in the setItemWidget part. So I think the problem lies somewhere else, maybe ListItemWidget. How about you try replacing ListItemWidget with QLabel and see what happens. Eg:
QListWidgetItem *lwi = new QListWidgetItem;
_results->addItem(lwi);
//ListItemWidget *w = new ListItemWidget;
//w->setName(i->name());
//w->setTooltip(i->path());
QLabel *w = new QLabel;
w->setText("Hello");
_results->setItemWidget(lwi, w);
I'm trying to have animation on a button click event. But somehow the animation is not working. I have referred the Qt reference docs, but could not find the root cause which is causing the issue
Below is sample code :
void MainWindow::AnimationClick()
{
// define toolbar y movement positions for animation
TOOLBAR_Y_SHOWN = 0;
TOOLBAR_Y_HIDDEN = -m_AnimatedWidget->height();
m_AnimatedWidget = new AnimatedWidget(this);
QPropertyAnimation *m_ani = new QPropertyAnimation(m_AnimatedWidget, "pos", this);
m_ani->setDuration(500);
m_ani->setEndValue(QPoint(m_AnimatedWidget->pos().x(), TOOLBAR_Y_HIDDEN));
m_ani->setEasingCurve(QEasingCurve::InBack);
m_ani->start();
}
With the above implementation nothing is happening on the click event.
Any suggestions , Thanks.
This looks wrong:
TOOLBAR_Y_HIDDEN = -m_AnimatedWidget->height();
m_AnimatedWidget = new AnimatedWidget(this);
First you access m_AnimatedWidget then you allocate it?
When you get a crash, such as segmentation fault, always run your program in a debugger. It would have helped you find this error quite easy as it would have stopped on the line of the error.
m_ani->setDuration(500);
setDuration() argument is expressed in milliseconds. You should probably put more than half a second when you are testing.
I got it. I was not allowing the m_AnimatedWidget to show upon the screen.
Below is the edited snippet.
void MainWindow::AnimationClick()
{
// define toolbar y movement positions for animation
TOOLBAR_Y_SHOWN = 0;
m_AnimatedWidget = new AnimatedWidget(this);
TOOLBAR_Y_HIDDEN = -m_AnimatedWidget->height();
QPropertyAnimation *m_ani = new QPropertyAnimation(m_AnimatedWidget, "pos", this);
m_ani->setDuration(5000);
m_ani->setEndValue(QPoint(m_AnimatedWidget->pos().x(), TOOLBAR_Y_HIDDEN));
m_ani->setEasingCurve(QEasingCurve::InBack);
m_ani->start();
m_AnimatedWidget->show();
}
I face a very serious situation. By writing this question I hope that really professionals will express their opinion regarding to the problem I am going to describe. I have reported a bug in https://bugreports.qt.io/ :
I have created QPropertyAnimation for maximumWidth property of QTextEdit and it does not work (it immediately changes state from starting state to the end state), though it works for minimumWidth property.
Please see the attached code.
And have attached .h and .cpp files. See those files here (files are named new.h and new.cpp).
And I got the follwing response:
MaximumWidth is not the property you want to animate. It holds the maximum width that the widget can have, it's related to layouting and so on. Changing the maximumWidth (as well as the minimumWidth) does not necessarily trigger a relayout and repaint. You should animate the size.
Please explain me whether it is a bug or no? Please tell me how the minimumWith property is being animated but when it concerns to the maximumWidth property, then I should not work and that is OK? I just don't get their point... Please explain.
P.S. I have written this code because I wanted to close by animation the right QTextEdit and be sure that when I resize the main window, where the button and two QTextEdit are, the closed QTextEdit does not being restored.
Did you check the actual value of maximumWidth? You don't seem to set a specific maximumWidth in your code.
The default value for maximumWidth is 16777215, and you set a duration of 1 msec. for the closing animation. Fading from 16777215 to 3 in 1 msec. would look like "instant", I guess.
I don't think it is a bug; I'd call it "undefined behavior". That means that if you try to animate minimumWidth, nobody can tell you for sure what is supposed to happen, and maybe the code has some optimizations or corner cases where sometimes it works, others it doesn't.
Anyway, minimumWidth and maximumWidth aren't supposed to be used to define what the size of a QWidget is, only what it must not exceed; i.e. they weren't designed to do what you are trying to do, so it can be called a bug. If you want to animate, you have to use a deterministic approach, which in this case is using the geometry property.
This is not a bug, the response you got from the bug report pretty well explains the problem with your code and a solution.
Dear Sofahamster I have changed my code to the code below and it works fine. Thanks for your hint!
Header file
class MyWidget : public QWidget
{
Q_OBJECT
QTextEdit *m_textEditor1;
QTextEdit *m_textEditor2;
QPushButton *m_pushButton;
QHBoxLayout *m_layout;
QVBoxLayout *m_buttonLayout;
int m_deltaX;
bool m_isClosed;
public:
MyWidget(QWidget * parent = 0);
~MyWidget(){}
void resizeEvent( QResizeEvent * event );
private slots:
void closeOrOpenTextEdit2(bool isClosing);
};
Source file
MyWidget::MyWidget(QWidget * parent):QWidget(parent),m_deltaX(0)
{
m_pushButton = new QPushButton(this);
m_pushButton->setText(">");
m_pushButton->setCheckable(true);
m_pushButton->setFixedSize(16,16);
connect(m_pushButton, SIGNAL(clicked(bool)), this, SLOT(closeOrOpenTextEdit2(bool)));
m_textEditor1 = new QTextEdit(this);
m_textEditor1->setText("AAAAA AAAAAAAAAAA AAAAAAAAAAA AAAAAAA AAAAAAAAAAA AAAAAAAAAAA AA");
m_textEditor2 = new QTextEdit(this);
m_buttonLayout = new QVBoxLayout();
m_buttonLayout->addWidget(m_pushButton);
m_buttonLayout->addItem( new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding) );
m_layout = new QHBoxLayout;
m_layout->addWidget(m_textEditor1, 10);
m_layout->addSpacing(15);
m_layout->addLayout(m_buttonLayout);
m_layout->setSpacing(0);
m_layout->addWidget(m_textEditor2, 4);
setLayout(m_layout);
resize(800,500);
}
void MyWidget::closeOrOpenTextEdit2(bool isClosing)
{
m_isClosed = isClosing;
QPropertyAnimation *animation1 = new QPropertyAnimation(m_textEditor2, "maximumWidth");
if(isClosing) //close the second textEdit
{
m_textEditor2->setMaximumWidth(m_textEditor2->width());
int textEdit2_start = m_textEditor2->maximumWidth();
m_deltaX = textEdit2_start;
int textEdit2_end = 3;
animation1->setDuration(500);
animation1->setStartValue(textEdit2_start);
animation1->setEndValue(textEdit2_end);
m_pushButton->setText("<");
}
else //open
{
int textEdit2_start = m_textEditor2->maximumWidth();
int textEdit2_end = m_deltaX;
animation1->setDuration(500);
animation1->setStartValue(textEdit2_start);
animation1->setEndValue(textEdit2_end);
m_pushButton->setText(">");
}
animation1->start();
}
void MyWidget::resizeEvent( QResizeEvent * event )
{
if(!m_isClosed)
m_textEditor2->setMaximumWidth( QWIDGETSIZE_MAX );
}