Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

I have some problem when using lamdba with QTimer :: singleshot!



  • I write a photography program and I use QSingleshot as a timer for the snapshot!
    My code:

    QTimer::singleShot(2000,[&painter,this]{readyToTakeOneImage(painter);});
    or
    QTimer::singleShot(2000,[&,this]{readyToTakeOneImage(painter);});

    When I run the program in use with QPainter,it shows errors:

    QPainter::font: Painter not active
    QPainter::setFont: Painter not active
    QPainter::setPen: Painter not active

    although i used reference in expression lamdba but it seems in function lambda was unable to reference the QPainter parameter!

    Here is the complete code of the functions:

    *if(flagToTake)
    {
    QTimer::singleShot(2000,[&painter,this]{readyToTakeOneImage(painter);});
    }

    void photoWidget::readyToTakeOneImage(QPainter& painter)
    {
    const QRect rectTarget(0, 0, 640, 480);
    flagToDisplay=false;
    flagToDisplayMupt=false;
    QFont font = painter.font();
    font.setPixelSize(150);
    font.setStyle(QFont::StyleOblique);
    painter.setFont(font);
    painter.setPen(Qt::yellow);

    QPointF top=QPointF(rectTarget.width()/2-70,rectTarget.height()/2);
    painter.drawText(top,QString::number(numberChanged-1));
    
    if(numberChanged==1)
    {
       timeforNumber->stop();
       timeforTake->start();
       painter.fillRect(rectTarget,QColor(255,255,255,numberChanged));
       connect(this,&photoWidget::takeSignal,this,&photoWidget::takeSlot);
       flagToTake=false;
    }
    

    }*

    Hope you help me with the problem I am having,thank you for your help!!


  • Moderators

    Please show us the relevant part of your code, where you set the QPaintDevice, either via a call to begin or the creation of QPainter,

    That's where the issue should be



  • yes,this is about all of my code is having problems.thank you so much!

    *void photoWidget::paintEvent(QPaintEvent *)
    {
    const QRect rectTarget(0, 0, 640, 480);
    const QRect rectSource(0, 0, 640, 480);

    QPainter painter(this);
    painter.drawPixmap(rectTarget,QPixmap::fromImage(this->image),rectSource);
    

    if(flagToTake)
    {
    //QFont font = painter.font();
    //font.setPixelSize(150);
    //font.setStyle(QFont::StyleOblique);
    //painter.setFont(font);
    //painter.setPen(Qt::yellow);

       //QPointF top=QPointF(rectTarget.width()/2-230,rectTarget.height()/2+30);
       //painter.drawText(top,"Ready");
       QTimer::singleShot(2000,[&painter,this]{readyToTakeOneImage(painter);});
    }
    else if(flagToDisplay)
       readyToDisplayImage(painter);
    else if(flagToDisplayMupt)
       readyToDisplayImageMuptiple(painter);
    

    }
    void photoWidget::readyToTakeOneImage(QPainter& painter)
    {
    const QRect rectTarget(0, 0, 640, 480);
    flagToDisplay=false;
    flagToDisplayMupt=false;
    QFont font = painter.font();
    font.setPixelSize(150);
    font.setStyle(QFont::StyleOblique);
    painter.setFont(font);
    painter.setPen(Qt::yellow);

    QPointF top=QPointF(rectTarget.width()/2-70,rectTarget.height()/2);
    painter.drawText(top,QString::number(numberChanged-1));
    
    if(numberChanged==1)
    {
       timeforNumber->stop();
       timeforTake->start();
       painter.fillRect(rectTarget,QColor(255,255,255,numberChanged));
       connect(this,&photoWidget::takeSignal,this,&photoWidget::takeSlot);
       flagToTake=false;
    }
    

    }

    void photoWidget::readyToDisplayImage(QPainter& painter)
    {
    const QRect rectTarget(0, 0, 640, 480);
    const QRect rectSource(0, 0, 640, 480);
    QDir dir(filePath);
    flagToTake=false;
    flagToDisplayMupt=false;
    QString fileName=filePath+"/image"+QString::number(static_cast<quint8>(dir.count()-3))+".jpg";
    QImageReader reader(fileName);
    reader.setAutoTransform(true);

     const QImage newImage=reader.read();
     if (newImage.isNull()) {
         QMessageBox::information(this,tr("Display a taken photo"),
                                  tr("Cannot load %1: %2")
                                  .arg(QDir::toNativeSeparators(fileName), reader.errorString()));
         return;
    }
     painter.drawPixmap(rectTarget,QPixmap::fromImage(newImage),rectSource);
    

    }
    void photoWidget::readyToDisplayImageMuptiple(QPainter &painter)
    {
    quint16 xPos=10;
    quint8 index=3;
    for(int i=0;i<3;i++)
    {
    displayImageMuptiple(painter,xPos,index);
    xPos+=205;
    index+=i;
    }
    }
    void photoWidget::displayImageMuptiple(QPainter&painter,quint16 x,quint8 indexOfImage)
    {
    const QRect rectTarget(x, 80, 180, 160);
    const QRect rectSource(x, 80, 180, 160);
    QDir dir(filePath);
    QString fileName=filePath+"/image"+QString::number(static_cast<quint8>(dir.count()-indexOfImage))+".jpg";
    QImageReader reader(fileName);
    reader.setAutoTransform(true);

    const QImage newImage=reader.read();
    if (newImage.isNull()) {
        QMessageBox::information(this,tr("Display a taken photo"),
                                 tr("Cannot load %1: %2")
                                 .arg(QDir::toNativeSeparators(fileName), reader.errorString()));
        return;
    }
    
    painter.drawPixmap(rectTarget,QPixmap::fromImage(newImage),rectSource);
    

    }*


  • Moderators

    @DBot well I expected as much,

    You have the paintEvent overwritten, which is fine and common practice.

    However, the QPainter for the widget that you create in there is only valid as long as the paintEvent function is being called.

    You're not supposed to break out of that call stack via a QTimer and in the connected slot/or lambda to access the QPainter.

    Do all QPainter operations, that have your QWidget as target, inside the paintEvent and you should be fine.



  • I thought the same way at first, but I thought maybe I did the wrong way and couldn't optimize the code.So now I have to find another timer function for my code.Thank you,nice a good day!


Log in to reply