Qt는 예제를 실행해볼 수 있는 Demo 를 제공해준다.
다음 위치에 실행 프로그램이 있다. Qt > 4.7.2(버전) > bin > qtdemo.exe
많은 예제들이 있는데 그중 Painter Paths 를 따라해보며 그림 그리는 것을 익혀보려고 한다.
아래에 있는 Launch 버튼을 누르면 실제로 실행하며 테스트해볼 수 있다.
나는 가장 상단 왼쪽에 있는 두 개의 도형(사각형, 둥근 모서리 사각형)과 Qt글자 도형을 테스트해보려고 한다.
Demo 실행 프로그램 하단 우측에 Documentation 버튼을 누르면 예제코드를 볼 수 있다.
<Qt로 도형 그리기>
예제에서는 콤보박스에서 각종 설정이 가능하다. (테두리 색, 도형 채워지는 색, 그라데이션, 펜의 두께..)
나는 콤보박스나 버튼, 이벤트 처리 부분은 생략하고 그림 그리는 것만 실행해보았다.
QPainterPath 클래스
#include <QPainterPath>
해당 오브젝트는 그래픽 빌딩 블럭들로 구성되어있다. ( 사각형, 타원, 선, 곡선 등..)
또한 filling, outlining, clipping 옵션이 있다.
보통의 drawing operations 보다 painter paths의 주요 장점은 복잡한 모양을 한번만 생성하면 된다는 것이다.
처음에 한 번 생성하고 QPainter::drawPath() 함수를 호출하여 여러번 그릴 수 있다.
예제 코드
구조
RenderArea Class : custom widget displaying a single painter path
Window Class : the application main window displaying several RenderArea widgets, and allowing the user to manipulate the painter paths' filling, pen, color and rotation angle
//window.h
#include <QWidget>
#include "renderArea.h"
class Window : public QWidget
{
Q_OBJECT
public :
Window();
private :
enum { NumRenderAreas = 3 };
RenderArea *renderAreas[NumRenderAreas];
};
window 클래스는 QWidget을 상속받았다.
우리가 filling, color를 업데이트하기 위해서는 slots를 실행해야만 한다.
그 이유는 QComboBox는 argument로 전달된 값을 signal로 전달하지 않는다.
//window.cpp
#include <QtGui>
#include <math.h>
#include "window.h"
Window::Window()
{
setFixedSize(400,200);
QPainterPath rectPath;
rectPath.moveTo(20.0 , 30.0);
rectPath.lineTo(80.0, 30.0);
rectPath.lineTo(80.0, 70.0);
rectPath.lineTo(20.0, 70.0);
rectPath.closeSubpath();
QPainterPath roundRectPath;
roundRectPath.moveTo(80.0, 35.0);
roundRectPath.arcTo(70.0, 30.0, 10.0, 10.0, 0.0, 90.0);
roundRectPath.lineTo(25.0, 30.0);
roundRectPath.arcTo(20.0, 30.0, 10.0, 10.0, 90.0, 90.0);
roundRectPath.lineTo(20.0, 65.0);
roundRectPath.arcTo(20.0, 60.0, 10.0, 10.0, 180.0, 90.0);
roundRectPath.lineTo(75.0, 70.0);
roundRectPath.arcTo(70.0, 60.0, 10.0, 10.0, 270.0, 90.0);
roundRectPath.closeSubpath();
QPainterPath textPath;
QFont timesFont("Times", 40);
timesFont.setStyleStrategy(QFont::ForceOutline);
textPath.addText(10, 70, timesFont, tr("hy"));
renderAreas[0] = new RenderArea(rectPath);
renderAreas[1] = new RenderArea(roundRectPath);
renderAreas[2] = new RenderArea(textPath);
Q_ASSERT(NumRenderAreas == 3 );
QGridLayout *topLayout = new QGridLayout;
for(int i=0; i<NumRenderAreas; ++i)
topLayout->addWidget(renderAreas[i], i/3, i%3);
QGridLayout *mainLayout = new QGridLayout;
mainLayout->addLayout(topLayout, 0, 0, 1, 4);
setLayout(mainLayout);
setWindowTitle(tr("Painter Paths"));
}
void Q_ASSERT (bool test)
: 만약 test가 false일 경우, 소스 코드파일 이름과 line number를 포함한 경고 메시지를 출력한다.
예제 )
// File : div.cpp
#include <QtGlobal>
int divide(int a, int b)
{
Q_ASSERT( b != 0 )
return a / b;
}
If b is Zero, the Q_ASSERT statement 는 qFatal()함수를 사용해서 다음과 같은 메시지를 출력할 것이다.
ASSERT : "b==0" in file div.cpp, lin 7
//renderArea.h
#include <QWidget>
#include <QSize>
#include <QPainter>
class RenderArea : public QWidget
{
Q_OBJECT
public :
RenderArea(const QPainterPath &path, QWidget *parent = 0);
QSize minimumSizeHint() const;
QSize sizeHint() const;
public slots :
void setFillRule(Qt::FillRule rule);
void setFillGradient(const QColor &color1, const QColor &color2);
void setPenWidth(int width);
void setPenColor(const QColor &color);
void setRotationAngle(int degrees);
protected :
void paintEvent(QPaintEvent *event);
private :
QPainterPath path;
QColor fillColor1;
QColor fillColor2;
int penWidth;
QColor penColor;
int rotationAngle;
};
//renderArea.cpp
#include "renderArea.h"
RenderArea::RenderArea(const QPainterPath &path, QWidget *parent)
: QWidget(parent), path(path)
{
penWidth = 2;
rotationAngle = 0;
setBackgroundRole(QPalette::Base);
penColor = QColor::QColor(255,0,0,255); // red // rgb
fillColor1 = QColor::QColor(255,255,255,255); //
fillColor2 = QColor::QColor(255,255,255,255);
// QColor::fromCmykF(iny cyan, megenta, yellow, black, int alpha-channel)
update();
}
QSize RenderArea::minimumSizeHint() const
{
return QSize(50,50);
}
QSize RenderArea::sizeHint() const
{
return QSize(100,100);
}
void RenderArea::setFillRule(Qt::FillRule rule)
{
path.setFillRule(rule);
update();
}
void RenderArea::setFillGradient(const QColor &color1, const QColor &color2)
{
fillColor1 = color1;
fillColor2 = color2;
update();
}
void RenderArea::setPenWidth(int width)
{
penWidth = width;
update();
}
void RenderArea::setPenColor(const QColor &color)
{
penColor = color;
update();
}
void RenderArea::setRotationAngle(int degrees)
{
rotationAngle = degrees;
update();
}
void RenderArea::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.scale(width() / 100.0, height()/100.0 );
painter.translate(50.0, 50.0);
painter.rotate(-rotationAngle);
painter.translate(-50.0, -50.0);
painter.setPen(QPen(penColor, penWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
QLinearGradient gradient(0,0,0,100);
gradient.setColorAt(0.0, fillColor1);
gradient.setColorAt(1.0, fillColor2);
painter.setBrush(gradient);
painter.drawPath(path);
update();
}
//main.cpp
#include <QApplication>
#include <QStyleFactory>
#include "window.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Window window;
window.show();
return app.exec();
}
내가 작성한 코드(위의 코드)에는 없지만 예제 코드에서 흥미로웠던 점은
사용자가 QComboBox에서 menu 옵션 선택을 변경하였을 때
signal을 slot에게 주는 코드 구현 부분이다.
connect(penColorComboBox, SIGNAL(activated(int)), this, SLOT(penColorChanged())); void Window::penColorChanged() { QColor color = qvariant_cast<QColor>(currentItemData(penColorComboBox)); for(int i=0; i < NumRenderAreas; ++i) renderArea[i]->setPenColor(color); }