9

我将如何绘制一个矩形?

我尝试了两种不同的方法;

void MyWidget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setPen(Qt::black);
    QRect rect = QRect(290, 20, 70, 40);
    painter.drawText(rect, Qt::AlignCenter,
                      "Data");
    painter.drawRect(rect);
}

哪个工作正常(即使参数没有命名也没有使用),但我不想使用 QPaintEvent * 我没有用它。

所以我试着重命名我的函数;

void MyWidget::draw()
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setPen(Qt::black);
    QRect rect = QRect(290, 20, 70, 40);
    painter.drawText(rect, Qt::AlignCenter,
                      "Data");
    painter.drawRect(rect);
}

这不显示任何内容(但没有错误)。

如果我不使用 QPaintEvent * 为什么它不起作用?

4

5 回答 5

10

绘制事件是绘制系统在需要重绘小部件时调用的方法。这就是为什么简单地命名自己的方法是行不通的。油漆系统永远不会调用它。

你真的应该使用QPaintEvent. 它为您提供了需要绘制的矩形。此矩形将基于小部件的大小,因此不要在您的绘制事件中使用显式矩形,而是将您的小部件设置为正确的大小。如果您的小部件移动、调整大小等,将生成一个绘制事件。

void MyWidget::paintEvent(QPaintEvent *event)
{
    QRect rect = event->rect();
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setPen(Qt::black);
    painter.drawText(rect, Qt::AlignCenter,
                      "Data");
    painter.drawRect(rect);
}

现在,如果您想将绘制逻辑分离到另一种方法中,那很好。但是您需要从绘画事件中调用它:

void MyWidget::paintEvent(QPaintEvent *event)
{
    QRect rect = event->rect();
    draw(rect);
}

void MyWidget::draw(QRect &rect)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setPen(Qt::black);
    painter.drawText(rect, Qt::AlignCenter,
                      "Data");
    painter.drawRect(rect);
}

如果您想完全绕过您所说的绘制事件,并且只想创建一个静态矩形来显示,一种方法是将其绘制一次到像素图并将其显示在 QLabel 中:

QPixMap pix(200,100);
QPainter painter(&pix);
// do paint operations
painter.end()
someLabel.setPixmap(pix)
于 2012-12-31T20:00:32.237 回答
2

您需要的任何数据paintEvent()都应该可以作为包含类的字段进行访问,在您的情况下,是MyWidget. 这些私有字段可以MyWidget通过“setter”暴露给客户端,这将在调用之前设置数据值update()MyWidget这将触发对paintEvent().

于 2012-12-31T19:49:59.157 回答
1

@Mat 也告诉过你:“事件”是启动画家的正确方法。
QPainter 只能在 QPaintEvent 事件之后调用,该事件带有可以绘制对象的安全区域

所以你必须找到另一种策略来传输你的数据,帮助我提出一个简单的方法,可以适应很多情况。

小部件.cpp

#include <QtGui>
#include "widget.h"

#define MIN_DCX    (0.1)
#define MAX_DCX    (5.0)

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{    
    dcx=MIN_DCX;
    setFixedSize(170, 100);
}

void Widget::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event); 
    QPainter painter;
    painter.begin(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setPen(Qt::black);
    pcx=dcx*2;
    QRect rect = QRect(50-dcx,25-dcx,60+pcx,40+pcx);
    painter.drawText(rect, Qt::AlignCenter,printData);
    painter.drawRect(rect);
    painter.end();

}

void Widget::setPrintData(QString value){
   printData = value;
   dcx=(dcx>MAX_DCX)?MIN_DCX:dcx+MIN_DCX;
}

小部件.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent);
    void setPrintData(QString value);

protected:
    void paintEvent(QPaintEvent *event);

private:
    QString printData;
    float dcx;
    float pcx;
};


#endif

窗口.cpp

#include <QtGui>
#include "widget.h"
#include "window.h"

#define MAX_SDCX  20

Window::Window()
    : QWidget()
{
    gobject = new Widget(this);

    textMode=1;
    rectMode=1;
    gobject->setPrintData(msgs[textMode]);

    QGridLayout *layout = new QGridLayout;
    layout->addWidget(gobject, 0, 0);
    setLayout(layout);

    QTimer *timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(dataOnAir()));
    timer->start(10);

    setWindowTitle(tr("Rect Shaking"));
}



void Window::dataOnAir(){
    if((++rectMode)>MAX_SDCX){
        rectMode=0;
        textMode^=1;
    }
    gobject->setPrintData(msgs[textMode]);
    gobject->repaint();
}

窗口.h

#ifndef WINDOW_H
#define WINDOW_H

#include <QWidget>
#include "widget.h"

class Window : public QWidget
{
    Q_OBJECT

public:
    Window();

private slots:
    void dataOnAir();

private:
    Widget *gobject;
    const QString msgs[2] = {"Hello","World"};
    int textMode;
    int rectMode;
};

#endif

主文件

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

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

正如您在代码中看到的那样,在对象“小部件”之外执行了一个计时器

每 10 毫秒发送一次重绘小部件以重绘具有不同大小的“矩形”,并且每 20 个周期(200 毫秒)将文本“hello”更改为“world”

在此示例中,您可以看到以任何方式都需要覆盖 QPainterDevice 架构。

您可能还注意到“paintEvent”中的“事件”被静音并且不直接使用,但是执行一个序列 QPainter 是必不可少的。

于 2013-01-01T03:47:22.490 回答
1

这个播放列表包含最好的 Qt 教程,从教程 74 开始对你有用(Qpainter 和 QPen),教程 75 是如何使用 QRect 绘制矩形。

于 2012-12-31T13:44:29.290 回答
0

覆盖小部件的paintEvent() 函数使您可以自定义小部件,并且该函数会定期调用以重绘小部件。因此,任何绘图都应在此函数中进行。然而,覆盖 paintEvent() 可能会导致一些性能问题。我更喜欢使用 QGraphicsScene 和 QGraphicsView 然后我会在场景中添加一个矩形,这是做这种绘图的常用方法。请检查 GraphicsView 框架

http://qt-project.org/doc/qt-4.8/graphicsview.html

于 2012-12-31T20:44:33.790 回答