рисовать в QFrame при нажатии кнопки.

Скажем, есть QPushButton с именем "Draw", QLineEdit и QFrame. При нажатии кнопки я хочу взять число из QLineEdit и нарисовать круг в QFrame. Как я могу это сделать? Пожалуйста, предоставьте мне код.

P.S. Проблема в том, что методы отрисовки QPainter должны вызываться в методе drawEvent.


person Narek    schedule 22.07.2010    source источник


Ответы (3)


Если @Kaleb Pederson answer недостаточно для вас, тогда вот полное решение для простой настройки, соответствующее тому, что вы описываете. Протестировано с Qt 4.5.2 в Linux. У меня было свободное время... ;)

основной.cpp:

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

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

    Window w;
    w.show();

    return qapp.exec();
}

окно.ч

#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;
};

окно.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();
}

кадр.ч:

#pragma once

#include <QFrame>

class Frame : public QFrame
{
Q_OBJECT

public:
    Frame( QWidget* );

    void setCircleRadius( int );

protected:
    void paintEvent( QPaintEvent* );

private:
    int m_radius;
};

кадр.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 );
    }
}
person Troubadour    schedule 22.07.2010

Если вы хотите, чтобы ваш фрейм рисовал, ему нужен способ узнать, что он должен что-то рисовать, поэтому создайте слот, который будет получать уведомление:

/* 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));
}

Затем в вашем подклассе фрейма вам нужно переопределить paintEvent(), чтобы нарисовать круг:

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

Пока слот, отвечающий на сигнал кнопки clicked(), излучает сигнал, который вызывает слот drawCircle с правильными аргументами, все должно работать правильно.

person Kaleb Pederson    schedule 22.07.2010

Вы не рисуете непосредственно на фрейме.
Начните здесь с графического просмотра, это сначала выглядит сложно, но программа с графическим интерфейсом - это большой скачок, когда вы впервые сталкиваетесь с ней

В большинстве графических интерфейсов (Qt, OpenGL и т. д.) вы создаете список элементов, которые хотите отрисовать в своей программе, и каким-то образом сохраняете их — затем есть функция draw(), которая вызывается, когда компьютеру нужно нарисовать вашу картинку — например, когда оно перемещается или перед ним перемещается другое окно. Затем вызывается функция OnDraw или OnRepaint и т. д., и вам нужно нарисовать список объектов.

Другой способ сделать это — нарисовать их все на изображении (QOimage или QPixmap) и скопировать его на экран в OnDraw или OnRepaint — вы можете сделать это, например, для графического пакета.

person Martin Beckett    schedule 22.07.2010
comment
Вы не рисуете прямо на кадре. Почему нет? - person Troubadour; 22.07.2010
comment
Класс QFrame — это базовый класс виджетов, которые могут иметь рамку. - person Martin Beckett; 22.07.2010
comment
Вы по-прежнему можете рисовать непосредственно на QFrame или любом его подклассе. См. мой ответ для рабочего пример. - person Troubadour; 22.07.2010
comment
Я вижу, что QGraphicsView и QGraphicsScene — это то, что мне нужно, но я не могу разместить текст в QGraphicsScene там, где хочу. Метод addText() этого класса не имеет аргумента, указывающего координаты. Как я могу это сделать? - person Narek; 22.07.2010
comment
@Martin Beckett: Вот что я прошу вас обосновать. Раньше я работал над приложением Qt, которое было написано задолго до появления QGraphicsView, и мы никогда не беспокоились о переносе на него, поскольку все работало просто отлично. QGraphicsView — хорошая новая часть графического интерфейса, но я бы не сказал, что она обязательна. - person Troubadour; 22.07.2010
comment
@Troubadour - моя ошибка, я думал, что это в значительной степени обязательно, если вы не пытаетесь создать какой-то странный эффект. В основном я просто рисую в виджете OpenGL. - person Martin Beckett; 22.07.2010