selected SIGNAL from QwtPlotPicker seems to be sending 3 times - c++

I have a QwtPlot and I need to select a point by clicking on it.
I'm using the QwtPickerClickPointMachine and the QwtPlotPicker classes to do so:
QwtPickerClickPointMachine picker_m = new QwtPickerClickPointMachine();
QwtPlotPicker d_picker = new QwtPlotPicker(QwtPlot::xBottom, QwtPlot::yLeft,
QwtPlotPicker::CrossRubberBand, QwtPicker::AlwaysOn,
dataPlot->canvas()); // dataPlot == QwtPlot
d_picker->setStateMachine(picker_m);
connect(d_picker, SIGNAL(selected(QPointF)), this, SLOT(test(QPointF)));
On my test function I am just printing an output:
void MyClass::test(QPointF point)
{
qDebug() << "test";
}
But the problem is that when I click on the QwtPlot the output is:
test
test
test
It seems to be calling three times. I don't have any idea why this is happening. Can someone give me an explanation please?

Related

unable to make an intro before showing anything in the window and after the window is polished

I am working on Unix 19.02 and Qt 5.13.0 .
I am trying to make an introduction for my application before anything is shown up in the window. So, what I thought is to make the QPainter change the background color in a while-loop. I tried it too many times and I had a problem in the timing : "When is the moment or the event that I should make the qpainter start the introduction?". I searched and found out the best thing is to reimplement this function :
void showEvent(QShowEvent* event) {...}
inside that function, I call "repaint()", and it will do all the introduction.
I tried all of these ways :
Making the while-loop inside the "paintEvent" function.
Making the while-loop outside the "paintEvent" function, and every time we change the color of the background I call "repaint()". Surely I made a small timeout for the computer to slow it down a bit.
-Note: using these two ways above, the window shows up, but it's background-color is black and nothing shows up neither the color doesn't change until the introduction is finished!
Lastely, a while-loop that does not use "QPainter", it uses stylesheet instead and after we change the "background-color" property. We call : ui->centeralWidget->style->polish(ui->centeralWidget);
The last way, forces the window not to show up until the introduction is finished completely (it takes 5 seconds to execute the introduction, the while-loop). this is the code :
QString ss; // for opacity
QString ss_prefix = "background-color: rgba(255, 255, 255, ";
QString ss_suffix = ");";
while(i<=50) {
i++;
Opacity += 5;
qDebug() << "Changing opacity : " << ss_prefix+std::to_string(Opacity).c_str()+ss_suffix;
ui->centralWidget->setStyleSheet(
ss_prefix+std::to_string(Opacity).c_str()+ss_suffix);
ui->centralWidget->style()->polish(ui->centralWidget);
QThread::currentThread()->msleep(100); // 100 * 50 = 5000/1000 = 5 seconds to execute!
}
Nevertheless, there are other ways to make an introduction, but I really would want to know what is happening and fix this problem!
The last equation is meant to calculate the time to execute :
100(sleep) * 50(The code will get executed 50 times) = 5000 / 1000 (it is in milli, so divide by 1000) = 5 seconds
Wish you understood my situation.
You're not providing complete code, so I am partially guessing here.
You need to wait for the main app event loop to get started before starting your animation. If you call that animation routine (with the msleep() at the end) from the QMainWindow (or whatever your top-level QWidget is) constructor, the main window is never given a chance to show itself (until the animation is done).
If I'm right, you could consider starting your animation from the first QWidget::showEvent() by using a bool flag to know when the first show happens. Another way would be to start a QTimer::singleShot(0, this, &MainWindow::animate) in the constructor (the timer will trigger once the main event loop starts). There are other ways, but the main point is that you need to let the QApplication event loop to be running and the window to have already been initialized.
Having said all that, I'd probably take a different approach, maybe with a QSplashScreen or a custom QWidget to show the animation before, or while, loading the main window in the background.
Also, look into QString template/replacement system, specifically the arg() methods and how they can be used to simplify string construction.
As #MaximPaperno points out, the problem is while-loop + msleep() since they block the eventloop preventing the GUI from working normally. For these cases, Qt provides strategies such as QTimer, QXAnimation, etc. In this case a simple solution is to use QVariantAnimation:
*.h
// ...
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private Q_SLOTS:
void applyOpacity(const QVariant &value);
// ...
*.cpp
// ...
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QVariantAnimation *animation = new QVariantAnimation(this);
animation->setStartValue(0);
animation->setEndValue(255);
animation->setDuration(5 * 1000);
connect(animation, &QVariantAnimation::valueChanged, this, &MainWindow::applyOpacity);
animation->start(QAbstractAnimation::DeleteWhenStopped);
}
// ...
void MainWindow::applyOpacity(const QVariant & value)
{
bool ok;
int opacity = value.toInt(&ok);
if(ok) {
QString qss = QString("background-color: rgba(255, 255, 255, %1)").arg(opacity);
ui->centralWidget->setStyleSheet(qss);
}
}
It's a trivial situation. Just show welcome window first. When it is closed, show your main window. Use signals to achieve it.

How to plot with QwtPlot from Qt slot?

Good time of day! I have a question you'll maybe find silly and obvious, but i've already broke my head trying to solve this.
I want to plot some curve by pressing a QPushButton. I wrote the slot and connected it to the corresponding signal of this button. But when I click on it, nothing happens on the plot, although this function executes, and it can be viewed on the debugger and qDebug() output.
On the other hand, if you call this function directly, and not as a slot, it works perfectly. The only difference is the calling method: as a slot in first case and as a method in the second case.
Some code examples:
//Slot
void MainWindow::buttonClick()
{
qDebug() << "Enter";
XRDDataReader *xrdr = new XRDDataReader();
xrdr->fromFile("/home/hippi/Документы/Sources/Qt/49-3.xy");
ui->plot->plotXRD(xrdr->xValues(), xrdr->yValues());
qDebug() << "Quit";
}
void Plotter::plotXRD(QVector<double> x, QVector<double> y)
{
QwtPlotCurve *curve = new QwtPlotCurve();
curve->setRenderHint
( QwtPlotItem::RenderAntialiased, true );
curve->setPen(Qt::black, 2);
curve->setSamples(x,y);
curve->attach(mainPlot);
}
As long as autoreplotting is not enabled, you have to call replot to make changes happen.

(Qt C++) Send int value from dialog to MainWindow?

I am quite new to C++ and Qt. I've gotten pretty far on my current project, but I've been putting off this one part. I have a pushbutton that opens a new dialog like this:
void MainWindow::on_fillAll_clicked()
{
int yo;
BlockSelect bSelect;
bSelect.setModal(true);
bSelect.exec();
if( bSelect.exec() == QDialog::Accepted )
{
//Get stuff here?
//I want to fill yo with the spinbox value
yo = bSelect.stuff();
return;
}
qDebug() << yo;
}
This works fine. In the dialog I have a spin box. I want to send that value inputted to the spin box to my main window when the user clicks OK.
I have been trying to get "int yo;" to have that value from the spinbox but everything I try just gets an error.
I added this to my BlockSelect public class:
int stuff();
And I made this function in my blockselect.cpp:
int BlockSelect::stuff()
{
qDebug() << "The function was called";
return ui->yolo->value();
}
But qDebug never shows anything???
So how can I fill yo from the main window with yolo from the dialog?
Sorry if I didn't explain this well :( I'm still learning.
Thanks for your time :)
First of all, there is no need to call exec() twice, just use it once within the if statement.
To answer your question, you still have the bSelect dialog object (and I'm assuming BlockSelect is a class you define?), so make an accessor function inside it to retrieve the values you want.
if( bSelect.exec() == QDialog::Accepted )
{
//Get stuff here?
//I want to fill yo with the spinbox value
yo = bSelect.stuff();
return;
}
EDIT:
Your BlockSelect class needs to contain an accessor function, this means a function that returns a value.
int stuff() { return ui->yolo->value();}
What I'm doing here is retrieving the spinbox's value (assuming it is named 'yolo') and returning it as a result of calling the 'stuff' function.

Qt 4.7.4 QPropertyAnimation not working

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();
}

mousePressEvent called only from certain areas in scene

I have an application which draws lines based on different data from cars. I want my application to be able to select the lines drawn, and then make the corresponding item selected in a list on the left as well. The problem is that the mousePressEvent is only called when I press the mousebutton in the leftmost quarter of the scene. When it is called the curveSelected() function works as well, but I can't figure out why I can't invoke the mousePressEvent from the other areas on the scene.
First of all I have a mousePressEvent.
void DrawingScene:::mousePressEvent ( QGraphicsSceneMouseEvent * event ){
event->ignore();
bool leftbutton = (event->button() == Qt::LeftButton);
if(leftbutton)
{
qDebug() << "leftbutton";
emit leftButtonPress(event->scenePos());
}
QGraphicsScene::mousePressEvent(event);
}
Later connected:
connect(d_scene, SIGNAL(leftButtonPress(QPointF)), this, SLOT(curveSelected(QPointF)));
leftButtonPress is the signal emitted. Then I have the function which selects the item in the list. This method seems to work just fine. The problem exists without this function as well.
void CurveDrawer::curveSelected(QPointF pos){
QMapIterator<QPair<unitID, QString>, carData*> it(dataMap);
while(it.hasNext()){
it.next();
QPainterPath curPath = it.value()->pathItem->path();
if(curPath.contains(pos)){
for (int i = 0; i < list->count(); ++i) {
QListWidgetItem* curItem = list->item(i);
if(curItem == it.value()->listItem){
qDebug() << "curveSelected";
curItem->setSelected(true);
}
}
}
}
}
Anyone experienced something similar, or may see some obvious mistakes in my code?
EDIT:
How can i achieve that the mousePressEvent is called every time I click inside the scene? This is basically what I want it to do. Now it is only called when I click in certain area.
I tried to implement it with void DrawGraphicsView;;mousePressEvent(QMouseEvent *event) now, and the same problem existed there. The event just got invoked from certain areas in the scene.
The strange thing for me is that when a certain place in the scene is in the left of the viewport it is not possible to invoke the mousepressEvent, but when I scroll the same place to the right in the viewport, then it is suddenly possible to invoke the mousepressEvent. Does this make the problem clearer?