how to send Qline coordinate to a QPainter Widget

2019-03-02 15:17发布

问题:

I created a Qwidget, Form_temp, that draw lines based on an array of data created in the parent widget MainWindow. The issue I face is the data I send from the MainWindow to Form_temp via the slot send_data is not seen by other functions in Form_temp. (paintEvent).

I am not able to figure out the loop hole. I added few Debug points to validate that the data arrives in Form_temp.

Here is the code with some explanation. I did this with QTCreator Please help, I spend few days on this and am not able to move forward.

Another question: paintEven happen each time the user moves the mouse or another widget is updating its view (e.g I have a label showing the time). I'd like to filter the QPaintevens, I just want an update when the data changes. Is there a better way to do this than what I have coded?

Qwidget : header

    #ifndef FORM_TEMP_H
    #define FORM_TEMP_H
    #include <QWidget>
    #include <QDebug>

    namespace Ui { class Form_temp;   }

    class Form_temp : public QWidget        {
        Q_OBJECT
    public:
        QPainter *p;
        void paintEvent(QPaintEvent*);
        explicit Form_temp(QWidget *parent = 0);
        ~Form_temp();
        void send_data (int *parray, int asize);

        int array[48];
        int size;
        bool myupdate;

    private:
        Ui::Form_temp *ui;
    };

    #endif // FORM_TEMP_H

Qwidget : core

#include "form_temp.h"
#include "ui_form_temp.h"
#include <cstdlib>
#include <QPainter>
#include <QDebug>

Form_temp::Form_temp(QWidget *parent) : QWidget(parent), ui(new Ui::Form_temp) {
    myupdate = false;
    ui->setupUi(this);
}
Form_temp::~Form_temp() { delete ui; }

void Form_temp::paintEvent(QPaintEvent*) {
    qDebug("Paintevent occurs");
    if (myupdate) {     // Event happen whenever I move the mouse,
                        // I only want an update when data changes.
      p = new QPainter(this);
      QPen pen(Qt::green, 3, Qt::DashDotLine, Qt::RoundCap, Qt::RoundJoin);
      p->setPen(pen);
      p->setRenderHint(QPainter::Antialiasing,true);

      qDebug()<< "this size" <<size;        
      for (int i= 0; i< size; ++i) {
         qDebug()<< "array[i" <<i <<"]="<< array[i];
      }
      [...]
      p->drawLine(x1,y1,x2,y2);
      [...]
    }
myupdate = false;  
}

void Form_temp::send_data (int *parray, int asize){
    size = asize;
     for (int i= 0; i< asize; ++i) {array[i] = parray[i];}
     myupdate = true;  // make sure the event will update the drawing
     this->update();   // create a Qpaint Event

     qDebug()<< size;  // print the data so we know we are passing data correctly
     for (int i= 0; i< asize; ++i) {
        qDebug()<< "array[i" <<i <<"]="<< array[i];
     }
}

MainWindow: header

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H

    #include <QMainWindow>
    #include <QtGui>
    #include "gpio.h"
    #include "form_temp.h"
    namespace Ui {
        class MainWindow;
    }

    class MainWindow : public QMainWindow
    {
        Q_OBJECT

    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
        //QPropertyAnimation *m_ani ;
        //QPropertyAnimation *m_ani2 ;
        Form_temp *temp_graph;
    [...]
    #endif // MAINWINDOW_H

MainWindow: core

    MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow){

        // Start UI
        ui->setupUi(this);

        temp_graph = new Form_temp;
        startTimer(1000); // get timer event every sec.

   }

   void MainWindow::timerEvent(QTimerEvent *event)  {

      int data[]= {1,2,3};
      temp_graph->send_data(data, 3);
   }
  [...]

Thanks for reading. Sebastien.

回答1:

It's very difficult to assess the code as it is posted here.

It looks like you created the QWidget subclass, Form_temp, using Qt Designer which means it has some extra design-time baggage that it doesn't really need.

When you create your instance of Form_temp, you aren't setting MainWindow as the parent in the constructor so I'm not quite sure how your custom widget would paint itself at all since it never receives a call to show() itself. It's also never destroyed.

The required wiring to use a slot and implementation is not present either so it's not possible to determine if that is a problem area in this situation.

It should be possible for you to achieve your goal however :) I would strongly recommend that you review the Qt Analog Clock Example as this demonstrates quite well how to implement your own widget.

You mention that you only want your widget to update itself when you change the data but you are misunderstanding how the Qt framework operates. You want your widget to paint itself when you change the data but this is not the only time that the widget will need to paint itself so you should not try to restrict the paint operation in that manner.

Put the code in paintEvent() that will paint the entire widget as you want it to appear based on the current data. The framework will execute the paintEvent() when the widget first appears, when it is revealed after previously being obscured by another window and many other situations over which you have no control.

Add ordinary methods (no need for slots) that allow you to change the underlying data from outside the class and make sure those methods include a call to update() at the end of them so they will signal the framework that the widget should be repainted.

If your widget is complicated and slow to paint, you can look at the region specified in the event passed into paintEvent() to restrict your paint code to just the region that needs to be updated.

UPDATE:

Your code is close. I've trimmed it down to the bare essentials to demonstrate the basics. You should be able to elaborate on it for your needs.

main.cpp

#include <QApplication>
#include "MainWindow.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MainWindow mainWindow;
    mainWindow.show();
    return app.exec();
}

MainWindow.h

#ifndef _MAINWINDOW_H
#define _MAINWINDOW_H

#include "Form_temp.h"

#include <QWidget>
#include <QTimer>

class MainWindow : public QWidget
{
    Q_OBJECT
public:
    MainWindow();
    virtual ~MainWindow();

private:
    Form_temp *temp_graph;   
    QTimer m_timer;

private slots:
    void slot_timeout();

};

#endif  /* _MAINWINDOW_H */

main.cpp

#include "MainWindow.h"

MainWindow::MainWindow():
    temp_graph(0),
    m_timer(this)
{
    temp_graph = new Form_temp(this);
    connect(&m_timer, SIGNAL(timeout()), this, SLOT(slot_timeout()));
    m_timer.start(1000);
}

MainWindow::~MainWindow()
{
}

void MainWindow::slot_timeout()
{
    int y = temp_graph->getY();

    y++;
    if(y > 10)
    {
        y = 0;
    }

    temp_graph->setY(y);
}

Form_temp.h

#ifndef _FORM_TEMP_H
#define _FORM_TEMP_H

#include <QWidget>

class Form_temp : public QWidget
{
    Q_OBJECT
public:
    Form_temp(QWidget *parent = 0);
    virtual ~Form_temp();

    void setY(const int newY);
    int  getY();

protected:
    void paintEvent(QPaintEvent *event);

private:
    int m_y;
};

#endif  /* _FORM_TEMP_H */

Form_temp.cpp

#include "Form_temp.h"
#include <iostream>
#include <QPaintEvent>
#include <QPainter>
#include <QPen>

using namespace std;

Form_temp::Form_temp(QWidget *parent) :
    QWidget(parent),
    m_y(1)
{
    cout << "Form_temp created." << endl;
}

void Form_temp::setY(const int newY)
{
    m_y = newY;
    update();
}

int Form_temp::getY()
{
    return m_y;
}

Form_temp::~Form_temp()
{
    cout << "Form_temp destroyed." << endl;
}

void Form_temp::paintEvent(QPaintEvent *event)
{
    cout << "Form_temp paintEvent." << endl;

    QPainter p(this);

    QPen pen(Qt::green, 3, Qt::DashDotLine, Qt::RoundCap, Qt::RoundJoin);
    p.setPen(pen);
    p.setRenderHint(QPainter::Antialiasing, true);

    p.drawLine(0, m_y, width(), m_y);
}