2012-12-31 70 views
9

我会如何绘制一个矩形?Qt初学者QPainter和QRect

我试过两种不同的方法;

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 *?

+7

为什么你期望一个随机命名的函数被调用来做任何事情?你的第一种方法很好。不命名参数你不需要(但)是既合法又惯用的C++。 – Mat

+0

好吧,如果我没有参数,是否有可能获得第一种方法工作,但其余的保持不变? – Ash

+0

不,无论您是否使用该参数都是必需的。我不明白你为什么要删除它 - 它不会让你忽略它。 – Mat

回答

10

paint事件是当一个小部件需要重画时由paint系统调用的方法。这就是为什么简单地命名你自己的方法不起作用。它从未被涂料系统所调用。你真的应该使用QPaintEvent。它给你需要绘制的矩形。这个矩形将基于小部件的大小,所以不要在绘画事件中使用显式矩形,而要将小部件设置为合适的大小。如果您想您的油漆逻辑分隔成另一种方法Paint事件会产生应你的widget不断移动,缩放等,现在

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) 
+0

哇感谢提示:)你是一个明星!这正是我正在寻找的! – Ash

+1

虽然您的第一个解决方案看起来很优雅,但您的解决方案实际上只是翻译从事件继承的区域,并且只是增加堆栈上的调用,用户应该始终在函数外部设置“数据”,所以我认为这是双倍通话,没有用处。抱歉不同意你的第一个解决方案。您的第二个简单解决方案看起来不错 – RTOSkit

1

This playlist包含最好的Qt教程,开始教程74将对你有用(Qpainter和QPen),教程75是如何使用QRect绘制矩形。

+0

谢谢,我来看看。 – Ash

2

您的paintEvent()需要的任何数据都应该作为包含类的字段来访问,在您的情况下,应为MyWidget的专用字段。这些私人字段可通过“设置者”暴露给MyWidget的客户端,该设置者在调用update(),MyWidget之前设置数据值,这将触发paintEvent()的呼叫。

+0

+1正确的概念! – RTOSkit

0

重写小部件的的paintEvent()功能,可以自定义窗口小部件并此功能定期调用重新绘制控件。因此任何绘图都应该在这个函数中进行。但是重写paintEvent()可能会导致一些性能问题。我宁愿使用QGraphicsScene和QGraphicsView,然后我会添加一个矩形到场景中,这是做这种绘画的常用方法。请检查GraphicsView框架

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

1

除了@Mat告诉你:“事件”是推出一个画家的正确方法。
QPainter只能在QPaintEvent事件后携带可以绘制对象的安全区域后触发。

所以,你必须找到另一种策略来运输你的数据,以帮助 我会提出一种简单的方法,它可以调整到很多情况。

widget.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; 
} 

widget.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 

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

window.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 

的main.cpp

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

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

正如可以在代码被执行的定时器,物体外看到“ Widget“

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

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

您也可能会注意到“的paintEvent”内“事件”被压制,不能直接使用,但它是必不可少的执行顺序的QPainter。

+0

我很抱歉,如果某些论证看起来有重新排序,我昨天开始在22:00 CET写回复,但之后我必须去吃晚饭“新年”,刚才我回来了,并发表完整回复。我没有看到别人写过......对不起。祝大家快乐! – RTOSkit

+1

新年快乐!谢谢你的帮助 :) – Ash