본문 바로가기
QT

QT08. 파일 및 인쇄

by 정양섭 2022. 3. 9.

1. 파일

파일은 cfile.cpp와 cfile.h에 다음과 같이 타입별로 Read함수와 Write함수를 제작하여 넣어두었습니다.

이 함수들을 이용하여 이용하여 파일에 저장하고, 읽으면 됩니다.

 

graphicobj.cpp 파일을 열어 다음과 같이 Read 함수와 Write 함수를 만듭니다.

void GraphicObj::Read(CFile &file)
{
    file.Read(m_nDrawType);
    file.Read(m_rectPos);
    file.Read(m_nLineColor);
    file.Read(m_nFaceColor);
}

void GraphicObj::Write(CFile &file)
{
    file.Write(m_nDrawType);
    file.Write(m_rectPos);
    file.Write(m_nLineColor);
    file.Write(m_nFaceColor);
}

graphicobjlist.cpp 파일을 열어 다음과 같이 Read 함수와 Write 함수를 만듭니다.

void GraphicObjList::Read(CFile &file)
{
    GraphicObj *pObj;
    Delete();
    int nCount;
    file.Read(nCount);
    for (int i = 0; i < nCount; i++)
    {
        pObj = new GraphicObj();
        pObj->Read(file);
        Add(pObj);
    }
}

void GraphicObjList::Write(CFile &file)
{
    GraphicObj *pObj;
    int nCount = m_Array.count();
    file.Write(nCount);
    for (int i = 0; i < nCount; i++)
    {
        pObj = m_Array.at(i);
        pObj->Write(file);
    }
}

imagefile.cpp 파일을 열어 다음과 같이 Read 함수와 Write 함수를 만듭니다.

mdiview.cpp 파일을 열어 다음과 같이 loadFile함수와 saveFile함수를 만듭니다.

bool MdiView::loadFile(const QString &fileName)
{
    CFileException Except;
    CFile file;
    if(!file.Open(fileName, CFile::modeRead | CFile::shareDenyNone, &Except)){
        return false;
    }

    CString strVersion;
    file.Read(strVersion);
    m_ImageFile.Read(file);
    file.Close();
    return true;
}

bool MdiView::saveFile(const QString &fileName)
{
    CFileException Except;
    CFile file;
    if(!file.Open(fileName, CFile::modeWrite, &Except)){
        return false;
    }
    CString strVersion = "1.0";
    file.Write(strVersion);
    m_ImageFile.Write(file);
    file.Close();
    return true;
}

mdichild.cpp 파일을 열어 loadFile함수를 찾아 다음과 같이 입력합니다.

    m_pView->loadFile(fileName);
    m_pView->resize(m_pView->m_ImageFile.m_nWidth, m_pView->m_ImageFile.m_nHeight);
    m_pView->update();

loadFile : 파일을 읽습니다.

resize : 화면크기에 맞추어 View크기를 설정합니다.

update : 화면을 업데이트 합니다. 내부적으로 paintEvent함수를 호출하여 화면에 파일로 부터 읽은 내용을 그립니다.

 

saveAs함수와 saveFile함수를 찾아 다음과 같이 입력합니다.

"Image File(*.img)"

 

    m_pView->saveFile(fileName);

 

mainwindow.cpp를 열어 open 함수를 찾아 다음과 같이 수정하여 확장자 img 파일만 열도록 합니다.

"Image File(*.img)"

 

이제 수정한 경우 창을 닫을때 저장할 것인지 묻도록 구성해보겠습니다. 현재는 아래와 같이 묻는 부분을 삭제하여 종료시 무조건 묻도록 되어 있습니다.

mdiview.h 파일을 열어 m_bModified 라는 변수를 선언하고 그 변수를 얻는 isModified()라는 함수를 만듭니다.

    bool isModified(){return m_Modified;}

 

    bool m_bModified = false;

 

내용에 변경이 발생할 경우 다음과 같이 m_bModified 변수에 true라고 입력합니다.

    m_bModified = true;

 

저장시 다음과 같이 m_bModified 변수에 false라고 입력합니다.

    m_bModified = false;

 

mdichild.cpp를 열어 다음과 같이 MdiView의 멤버 함수인 isModified를 호출하여 변경되었는지를 확인하도록 입력합니다.

    if(!m_pView->isModified())

        return true;

 

이제 이미지 파일로 저장해 보겠습니다.

우선 Export와 이후에 인쇄에서 사용하기 위해 Print라는 메뉴를 하나생성하겠습니다.

mainwindow.h를 열어 saveAs로 찾기를 하여 그 아래에 다음과 같이 입력합니다.

    void exportImage();

    void print();

 

다음찾기를 하여 그 아래에 다음과 같이 입력합니다.

    QAction *exportImageAct;

    QAction *printAct;

 

mainwindow.cpp를 열어 saveAs로 찾기를 하여 그 아래에 다음과 같이 두개의 함수를 추가합니다.

void MainWindow::exportImage()
{
    MdiChild *child = activeMdiChild();
    if(!child)
        return;
    child->exportImage();
}

void MainWindow::print()
{
    MdiChild *child = activeMdiChild();
    if(!child)
        return;
    if(!child->m_pView)
        return;
    child->m_pView->print();
}

MdiChild에 exportImage 함수를 MdiView에 print함수를 추가하면 에러는 없어질것입니다.

다음찾기를 하여 그 아래에 다음과 같이 입력하여 Mdi 창이 열렸을때만 Enable이 되도록 합니다.

    exportImageAct->setEnabled(hasMdiChild);

    printAct->setEnabled(hasMdiChild);

 

다음찾기를 하여 다음과 같이 입력합니다.

    exportImageAct = new QAction(tr("Export"), this);
    connect(exportImageAct, &QAction::triggered, this, &MainWindow::exportImage);
    fileMenu->addAction(exportImageAct);

    printAct = new QAction(tr("Print"), this);
    connect(printAct, &QAction::triggered, this, &MainWindow::print);
    fileMenu->addAction(printAct);
    fileMenu->addSeparator();

 

단축키를 정의하는 setShortcuts과 Action에 마우스를 올리면 상태 표시줄에 설명을 표시하는 setStatusTip은 필수사항이 아니므로 제외하고 작성했습니다.

mdichild.cpp 파일을 열어 제일 마지막으로 가서 아래와 같이 exportImage함수를 추가하여 작성합니다.

#include <QFileDialog>
void MdiChild::exportImage()
{
    CString strPathFile = curFile.replace(".img", ".png");
    strPathFile = QFileDialog::getSaveFileName(this, tr("Export"),
                         strPathFile, "Graphic Files(*.png|*.bmp|*.jpg|*.gif)");
    m_pView->exportImage(strPathFile);
}

 

대화상자를 호출하여 저장할 파일을 얻고 MdiView의 exportImage를 호출하도록 구성했습니다.

MdiView에 exportImage를 추가하면 에러는 없어질 것입니다.

exportImage함수를 mdichild.h에 선언한 부분은 설명하지 않아도 알것입니다.

mdiview.cpp를 열어 제일 마지막에 다음과 같이 두개의 함수를 추가하여 작성합니다.

void MdiView::exportImage(CString strPathFile)
{
    QImage *pImage = new QImage(m_ImageFile.m_nWidth, m_ImageFile.m_nHeight, QImage::Format_RGB32);
    if(!pImage)
        return;
    QPainter painter(pImage);
    Draw(&painter);
    pImage->save(strPathFile);
}

void MdiView::print()
{
}
설정한 그림크기로 이미지를 생성하고

    QImage *pImage = new QImage(m_ImageFile.m_nWidth, m_ImageFile.m_nHeight, QImage::Format_RGB32);

그 이미지에서 painter를 생성합니다.

    QPainter painter(pImage);

Draw 함수를 이용하여 이미지에 그림을 그립니다.

    Draw(&painter);

이미지 파일로 저장합니다.

    pImage->save(strPathFile);

 

위에서 사용한 Draw함수는 paintEvent함수를 다음과 같이 분리하여 작성했습니다.

#include "DrawTools.h"
void MdiView::Draw(QPainter *painter)
{
    CDrawTools drawTools;

    drawTools.DrawRect(painter, 0, 0, m_ImageFile.m_nWidth, m_ImageFile.m_nHeight, m_ImageFile.m_nColor, m_ImageFile.m_nColor);

    m_ImageFile.m_ObjList.Draw(painter);   //작성된 전체 객체 그림
    if(m_pObj)
        m_pObj->Draw(painter);             //작성 중인 객체 그림

/*  drawTools.DrawLine(painter, 100, 100, 200, 200, RGB(255, 0, 0));
    drawTools.DrawRect(painter, 300, 100, 400, 200, RGB(0, 0, 0), RGB(0, 255, 0));
    drawTools.DrawRoundRect(painter, 100, 300, 200, 400, RGB(0, 0, 0), RGB(0, 0, 255));
    drawTools.DrawEllipse(painter, 300, 300, 400, 400, RGB(0, 0, 0), RGB(255, 255, 0));
*/
}

void MdiView::paintEvent(QPaintEvent *event)
{
    QPainter painter;
    painter.begin(this);
    Draw(&painter);
    painter.end();
}

 

2. 인쇄

인쇄 작업은 앞에서 메뉴를 모두 구성해 두었으므로 print 함수만 작성하면 됩니다.

mdiview.h를 열어 다음과 같이 OnPaint라는 함수를 slot으로 선언합니다.

#include <QPrinter>

public slots:
    void OnPrint(QPrinter* pPrinter);

 

QPrinter를 사용하기 위해서는 프로젝트에 다음과 같이 printsupport를 선언해야 사용이 가능합니다.

printsupport

 

mdiview.cpp를 열어 print 함수에 아래와 같이 작성하고, 그 아래에 OnPrint라는 함수를 작성합니다.

#include <QPrintPreviewDialog>
void MdiView::print()
{
    QPrinter             printer( QPrinter::HighResolution );
    QPrintPreviewDialog  preview( &printer, this );
    preview.resize(MainWindow::theMain->size());
    QPoint point = MainWindow::theMain->pos();
    if(point.x() < 0)
        point.setX(0);
    if(point.y() < 0)
        point.setY(0);
    preview.move(point);
    preview.setWindowFlags(preview.windowFlags() & ~Qt::WindowContextHelpButtonHint);
    preview.setWindowTitle(tr("Print preview"));
    connect( &preview, SIGNAL(paintRequested(QPrinter*)), SLOT(OnPrint(QPrinter*)) );
    preview.exec();
}

void MdiView::OnPrint(QPrinter* pPrinter)
{
    QPainter painter;
    painter.begin(pPrinter);

    CSize docSize(m_ImageFile.m_nWidth, m_ImageFile.m_nHeight);

    QRectF pageRect = pPrinter->pageRect(QPrinter::DevicePixel);
    QRectF paperRect = pPrinter->paperRect(QPrinter::DevicePixel);
    double xscale = pageRect.width() / double(docSize.cx);
    double yscale = pageRect.height() / double(docSize.cy);
    double scale = qMin(xscale, yscale);
    painter.translate(paperRect.x() + pageRect.width() / 2,
                      paperRect.y() + pageRect.height() / 2);
    painter.scale(scale, scale);
    CSize sizeReal;
    sizeReal.cx = static_cast<int>(static_cast<double>(docSize.cx));
    sizeReal.cy = static_cast<int>(static_cast<double>(docSize.cy));
    painter.translate(-sizeReal.cx / 2, -sizeReal.cy / 2);

    Draw(&painter);

    painter.end();
}

QPrintPreviewDialog Class는 인쇄 미리보기 대화상자를 띄우는 Class로 미리보기 화면에 표시할 필요가 있을때 및 실제 인쇄를 수행할때(프린터에 그린다고 생각하면 됩니다) paintRequested라는 SIGNAL을 호출하도록 되어 있습니다. 이를 OnPrint라는 SLOT 함수와 연결해주면 됩니다.

OnPrint라는 함수는 QPrinter로 부터 Painter를 얻어 그려야할 영역(미리보기 및 프린터 영역)의 크기를 구해 가운데에 표시하도록 한것입니다.

painter.scale 함수는 확대 또는 축소해서 그려야 할 경우 사용하는 함수이고, painter.translate 함수는 그리기 시작할 시작 위치를 설정하는 함수입니다.

F5를 눌러 프로그램을 실행하여 Image001.img 파일을 열면(기존에 작성해서 저장해 두었다고 가정) 다음과 같이 화면에 나타납니다.

File 메뉴의 부메뉴 Print를 실행하면 다음과 같이 화면에 나타납니다.

 우측 상단의 프린터 아이콘을 실행하면 인쇄 대화상자가 나타나 인쇄를 할 수 있습니다.

 

예제 프로그램

GraphicEditor6.zip
0.08MB

'QT' 카테고리의 다른 글

QT06. 스크롤  (0) 2022.03.17
설치 파일 만들기  (0) 2022.03.12
QT07. 메모리 및 마우스 처리  (0) 2022.03.06
QT05. 대화상자  (0) 2022.03.04
QT04. GUI  (0) 2022.03.01