Question

Say there is a QPushButton named "Draw", a QLineEdit and a QFrame. On clicking the button I want to take a number from QLineEdit and draw a circle in a QFrame. How can I do this? Please provide me with the code.

P.S. The problem is that draw methods of the QPainter should be called in drawEvent method.

Was it helpful?

Solution

If @Kaleb Pederson's answer is not enough for you then here's a complete solution for a simple set-up matching what you describe. Tested with Qt 4.5.2 on Linux. I had some spare time... ;)

main.cpp:

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

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

    Window w;
    w.show();

    return qapp.exec();
}

window.h

#pragma once

class QLineEdit;
class QPushButton;
#include <QWidget>

class Frame;

class Window : public QWidget
{
Q_OBJECT

public:
    Window();

private slots:
    void onButtonClicked();

private:
    QLineEdit*   m_lineEdit;
    QPushButton* m_pushButton;
    Frame*       m_frame;
};

window.cpp:

#include <QHBoxLayout>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>

#include "frame.h"
#include "window.h"

Window::Window()
    : m_lineEdit  ( new QLineEdit( this ) )
    , m_pushButton( new QPushButton( tr( "Draw" ), this ) )
    , m_frame     ( new Frame( this ) )
{
    connect( m_pushButton, SIGNAL( clicked() )
           , SLOT( onButtonClicked() ) );

    QHBoxLayout*const hLayout = new QHBoxLayout;
    hLayout->addWidget( m_lineEdit );
    hLayout->addWidget( m_pushButton );

    QVBoxLayout*const vLayout = new QVBoxLayout( this );
    vLayout->addLayout( hLayout );
    m_frame->setFixedSize( 300, 400 );
    vLayout->addWidget( m_frame );

    setLayout( vLayout );
}

void Window::onButtonClicked()
{
    const int r = m_lineEdit->text().toInt(); // r == 0 if invalid
    m_frame->setCircleRadius( r );
    m_frame->update();
}

frame.h:

#pragma once

#include <QFrame>

class Frame : public QFrame
{
Q_OBJECT

public:
    Frame( QWidget* );

    void setCircleRadius( int );

protected:
    void paintEvent( QPaintEvent* );

private:
    int m_radius;
};

frame.cpp:

#include <QPainter>

#include "frame.h"

Frame::Frame( QWidget* parent )
    : QFrame( parent )
    , m_radius( 0 )
{
    setFrameStyle( QFrame::Box );
}

void Frame::setCircleRadius( int radius )
{
    m_radius = radius;
}

void Frame::paintEvent( QPaintEvent* pe )
{
    QFrame::paintEvent( pe );

    if ( m_radius > 0 )
    {
        QPainter p( this );
        p.drawEllipse( rect().center(), m_radius, m_radius );
    }
}

OTHER TIPS

If you want your frame to do the drawing, then it needs a way to know that it should draw something, so create a slot that will receive notification:

/* slot */ void drawCircle(QPoint origin, int radius) {
    addCircle(origin, radius);
    update(); // update the UI
}

void addCircle(QPoint origin, int radius) {
    circleList.add(new Circle(origin,radius));
}

Then, your frame subclass you need to override paintEvent() to draw the circle:

void paintEvent(QPaintEvent *event) {
    QFrame::paintEvent(event);
    QPainter painter(this);
    foreach (Circle c, circleList) { // understand foreach requirements
        painter.drawEllipse(c.origin(), c.radius(), c.radius());
    }
}

As long as the slot responding to the button's clicked() signal emits a signal that calls the drawCircle slot with the correct arguments everything should work correctly.

You don't draw diectly onto a frame.
Start here graphicsview, it looks complicated at first - but GUI program is a big leap when you first encounter it

In most GUIs (Qt, OpenGL etc) you build up a list of elements you want to draw in your program and store them somehow - then there is a draw() function that gets called when the computer needs to draw your picture - eg when it is moved or another window is moved in front of it. The OnDraw or OnRepaint etc function then gets called and you have to draw the list of objects.

Another way to do this is to draw them all to an image (QOimage or QPixmap) and copy that to the screen in OnDraw or OnRepaint - you might do this for a graphics package for example.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top