Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
265 views
in Technique[技术] by (71.8m points)

qt - Qt5 : Displaying a Qpainter with layouts

I started using Qt5 a little while ago and I don't know how to set the position of my drawing in my window.

I have a Drawing class which is a QWidget and which contains my paintEvent() function and other functions; and a MainWindow class which contains some widgets. So in order to display my Qpainter, I have to include it in my layout, which is the main window layout, but the window doesn't adapt to the Qpainter at all; the dimensions of the buttons, sliders .. adapt so as to organize themselves and occupy all the space of my window, but they totally ignore my Qpainter and it partly disappears if I put at least 2 widgets.

Do you have any solutions to better manage the position of these elements?

main.cpp :

#include <QtGui>
#include <QApplication>

#include "mywidget.h"

int main( int argc, char **argv )
{
  QApplication app(argc, argv);

  MainWindow window;

  window.show();

  return app.exec();
}

mywidget.h :

#ifndef MYWIDGET_H
#define MYWIDGET_H

#include <QtGui>
#include <QWidget>
#include <QSlider>
#include <QScrollBar>
#include <QApplication>
#include <QGridLayout>
#include <QObject>
#include <QPoint>
#include <QLabel>
#include <QPolygon>


class Drawing : public QWidget
{
    Q_OBJECT

public:
    Drawing();

    void paintEvent(QPaintEvent* e);

public slots:
    void slide(int abscisse);
    void rotate();

private:
      QPoint o;
      QPoint a;
      QPoint b;
      QPoint c;
      QPoint d;
};

//--------------------------------------

class MainWindow : public QWidget
{
    Q_OBJECT

public:
  MainWindow();

private:
      QSlider* m_slider1;
      QSlider* m_slider2;
      QGridLayout* m_layout;
      Drawing* m_dessin;
};



#endif // MYWIDGET_H

mywidget.cpp :

#include "mywidget.h"
#include <iostream> //POUR LES TESTS

MainWindow::MainWindow() : QWidget()
{
    setGeometry(330, 140, 840, 620);

    m_slider1 = new QSlider(Qt::Horizontal, this);
    m_slider1->setRange(150, 650);
    m_slider1->setSliderPosition(400);

    m_slider2 = new QSlider(Qt::Horizontal, this);
    m_slider2->setSliderPosition(50);

    m_layout = new QGridLayout;

    m_layout->addWidget(new QLabel("Translation Horizontale"), 1, 0);
    m_layout->addWidget(m_slider1, 2, 0);

    m_layout->addWidget(new QLabel("Rotation"), 0, 1);
    m_layout->addWidget(m_slider2, 1, 1);


    m_dessin = new Drawing;
    m_layout->addWidget(m_dessin, 0, 0);

    setLayout(m_layout);

    QObject::connect(m_slider1, SIGNAL(valueChanged(int)), m_dessin, SLOT(slide(int)));
    QObject::connect(m_slider2, SIGNAL(valueChanged(int)), m_dessin, SLOT(rotate()));

}

//--------------------------------------------------------

Drawing::Drawing() : QWidget(), o(400, 150), a(o.x()-50 , o.y()-50), b(o.x()+50 , o.y()-50), c(o.x()+50 , o.y()+50), d(o.x()-50 , o.y()+50) {}


void Drawing::paintEvent(QPaintEvent *e) {

    QPolygon poly;
    poly << a << b << c << d;

    QWidget::paintEvent(e); // effectue le comportement standard

    QPainter painter(this); // construire

    painter.setPen( QPen(Qt::white, 2) ); // personnaliser

    painter.drawPolygon(poly); // dessiner
}


void Drawing::slide(int abscisse) {

    if (a == QPoint(o.x()-50 , o.y()-50)) {

        o.setX(abscisse);
        a.setX(o.x()-50);
        b.setX(o.x()+50);
        c.setX(o.x()+50);
        d.setX(o.x()-50);
    }

    else {

        o.setX(abscisse);
        a.setX(o.x());
        b.setX(o.x()+75);
        c.setX(o.x());
        d.setX(o.x()-75);
    }

    update();
}

void Drawing::rotate() {

    if (a == QPoint(o.x()-50 , o.y()-50)) {

        a = QPoint(o.x() , o.y()+75);
        b = QPoint(o.x()+75 , o.y());
        c = QPoint(o.x() , o.y()-75);
        d = QPoint(o.x()-75 , o.y());
    }

    else {
        a = QPoint(o.x()-50 , o.y()-50);
        b = QPoint(o.x()+50 , o.y()-50);
        c = QPoint(o.x()+50 , o.y()+50);
        d = QPoint(o.x()-50 , o.y()+50);
    }

    update();
}

Snapshots:

Snapshot 1

Snapshot 2

Snapshot 3

question from:https://stackoverflow.com/questions/66068747/qt5-displaying-a-qpainter-with-layouts

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

After having seen the snapshots of OP, I thought about what might been happen.

The layout of OP doesn't look that wrong. I still believe that the layout plays only a minor role in OPs issue.

I tried to reproduce OPs issue with an even smaller MCVE of mine.

My testQGridLayout:

#include <QtWidgets>

class Drawing: public QFrame {

  public:
    Drawing(QWidget *pQParent = nullptr);
    virtual ~Drawing() = default;

    Drawing(const Drawing&) = delete;
    Drawing& operator=(const Drawing&) = delete;

  protected:
    virtual void paintEvent(QPaintEvent *pQEvent) override;
};

Drawing::Drawing(QWidget* pQParent):
  QFrame(pQParent)
{
  setFrameStyle(Box | Plain);
}

void Drawing::paintEvent(QPaintEvent* pQEvent)
{
  { QPainter qPainter(this);
    qPainter.drawText(QPoint(40, 40),
      QString("Size: %1 x %2").arg(width()).arg(height()));
    qPainter.setPen(Qt::red);
    qPainter.drawRect(300, 100, 200, 200);
  }
  // call base class paint event to keep it working
  QFrame::paintEvent(pQEvent);
}

class MainWindow: public QWidget {

  public:
    MainWindow(QWidget *pQParent = nullptr);
    virtual ~MainWindow() = default;

    MainWindow(const MainWindow&) = delete;
    MainWindow& operator=(const MainWindow&) = delete;

  private:
    QGridLayout _qGrid;
    Drawing _qDrawing;
    QSlider _qSliderT;
    QSlider _qSliderR;
};

MainWindow::MainWindow(QWidget *pQParent):
  QWidget(pQParent),
  _qSliderT(Qt::Horizontal),
  _qSliderR(Qt::Horizontal)
{
  resize(840, 620);
  _qGrid.addWidget(&_qDrawing, 0, 0);
  _qGrid.addWidget(new QLabel("Translation Horizontal"), 1, 0);
  _qSliderT.setRange(150, 650);
  _qSliderT.setSliderPosition(400);
  _qGrid.addWidget(&_qSliderT, 2, 0);
  _qGrid.addWidget(new QLabel("Rotation"), 1, 1);
  _qSliderR.setSliderPosition(50);
  _qGrid.addWidget(&_qSliderR, 2, 1);
  setLayout(&_qGrid);
}

int main(int argc, char **argv)
{
  qDebug() << "Qt Version:" << QT_VERSION_STR;
  QApplication app(argc, argv);
  // setup GUI
  MainWindow qWinMain;
  qWinMain.setWindowTitle("Test QGridLayout");
  qWinMain.show();
  // runtime loop
  return app.exec();
}

Output:

Qt Version: 5.15.1

Snapshot of testQGridLayout.exe

I made some changes to exclude what is a possible issue and what not.

  1. I derived my Drawing from QFrame. Thus, it was easy to give it a visible border. As expected, my Drawing _qDrawing occupies only the space above the first slider (QSlider _qSliderT; in my case).

  2. I added output of widget size to the Drawing::paintEvent() to see its size. Then I added the painting of a red rectangle. For that, I cared to cover a space which is partly inside the widget and partly below and right of it.

This is what I conclude:

  1. As exposed in the OPs code, the layout should be the same.

  2. OPs rectangle is always drawn at the same coordinates. Hence, it doesn't get visible until the Drawing grows large enough (with the main window).

The origin of the QPainter (i.e. QPoint(0, 0)) is the upper left corner of the widget. This can be changed by applying transformations but I couldn't see this in OPs code. (The effect of the sliders, I neglect for now.)

Though, there are still some things which are not clear to me:

  1. The Drawing should clip the painting. Hence, I wonder, how OPs rectangle can appear over the rotate slider. Either, the OP used a span for the Drawing m_dessin, or the widget doesn't clip painting on the paint engine the OP uses. (The look is quite different than mine. Thus, it might be a different platform.)

  2. The layout which can be seen in OPs snapshots doesn't match the exposed code. In OPs snapshot, the Drawing occupies all extra space resulting from growing the main window. This is only possible when QGridLayout::setRowStretch()/GridLayout::setColumnStretch() had been used (as recommended in my first comment). However, the exposed code doesn't contain them.

To check this out, I changed the layout in MainWindow::MainWindow():

MainWindow::MainWindow(QWidget *pQParent):
  QWidget(pQParent),
  _qSliderT(Qt::Horizontal),
  _qSliderR(Qt::Horizontal)
{
  resize(840, 620);
  _qGrid.setRowStretch(0, 1);
  _qGrid.setColumnStretch(0, 1);
  _qGrid.addWidget(&_qDrawing, 0, 0, 1, 2);
  _qGrid.addWidget(new QLabel("Translation Horizontal"), 1, 0);
  _qSliderT.setRange(150, 650);
  _qSliderT.setSliderPosition(400);
  _qGrid.addWidget(&_qSliderT, 2, 0);
  _qGrid.addWidget(new QLabel("Rotation"), 1, 1);
  _qSliderR.setSliderPosition(50);
  _qGrid.addWidget(&_qSliderR, 2, 1);
  setLayout(&_qGrid);
}

Output:

Snapshot of testQGridLayout.exe after modification

Now, the layout seems to match the one of OPs snapshots.

Trying resize:

Video of testQGridLayout.exe while resizing

This looks exactly as it should:

  • the Drawing _qDrawing shrinks and grows with the main window size
  • the painting is clipped if the size of Drawing _qDrawing becomes too small to cover it.

Final Conclusion:

There is nothing wrong in OPs layout.

IMHO, OP is not yet fully clear about how coordinate systems apply in QPainter.

For this, I can warmly recommend an extra page of the Qt online doc., precisely dedicated to this topic:

Qt Doc.: Coordinate System


Continuation:

How to add a vertical slider:

class MainWindow: public QWidget {

  public:
    MainWindow(QWidget *pQParent = nullptr);
    virtual ~MainWindow() = default;

    MainWindow(const MainWindow&) = delete;
    MainWindow& operator=(const MainWindow&) = delete;

  private:
    QGridLayout _qGrid;
    Drawing _qDrawing;
    QSlider _qSliderV;
    QSlider _qSliderT;
    QSlider _qSliderR;
};

MainWindow::MainWindow(QWidget *pQParent):
  QWidget(pQParent),
  _qSliderV(Qt::Vertical),
  _qSliderT(Qt::Horizontal),
  _qSliderR(Qt::Horizontal)
{
  resize(840, 620);
  _qGrid.setRowStretch(0, 1);
  _qGrid.setColumnStretch(0, 1);
  _qGrid.addWidget(&_qDrawing, 0, 0, 1, 2);
  _qGrid.addWidget(&_qSliderV, 0, 2);
  _qGrid.addWidget(new QLabel("Translation Horizontal"), 1, 0);
  _qSliderT.setRange(150, 650);
  _qSliderT.setSliderPosition(400);
  _qGrid.addWidget(&_qSliderT, 2, 0);
  _qGrid.addWidget(new QLabel("Rotation"), 1, 1, 1, 2);
  _qSliderR.setSliderPosition(50);
  _qGrid.addWidget(&_qSliderR, 2, 1, 1, 2);
  setLayout(&_qGrid);
}

Output:

Snapshot of testQGridLayout.exe with add. vertical slider

To achieve this specific layout, I placed the _qSliderV into column 2 and gave _qSliderR (and its label) a column span of 2 as well.

To illustrate this, I added a sketch of the resulting grid to the above snapshot:

Snapshot of testQGridLayout.exe with grid sketch


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...