스크리블 예제
Scribble 예제는 애플리케이션의 위젯에 대해 생성된 이벤트를 수신하기 위해 QWidget 의 이벤트 핸들러 중 일부를 재구현하는 방법을 보여줍니다.
마우스 이벤트 핸들러를 재구현하여 그리기를 구현하고, 페인트 이벤트 핸들러를 재구현하여 애플리케이션을 업데이트하고, 크기 조정 이벤트 핸들러를 재구현하여 애플리케이션의 모양을 최적화합니다. 또한 애플리케이션을 종료하기 전에 닫기 이벤트를 가로채기 위해 닫기 이벤트 핸들러를 다시 구현합니다.
이 예제에서는 QPainter 를 사용하여 실시간으로 이미지를 그리고 위젯을 다시 칠하는 방법도 보여줍니다.
사용자는 Scribble 애플리케이션을 사용하여 이미지를 그릴 수 있습니다. File 메뉴를 통해 사용자는 기존 이미지 파일을 열고 편집하고 이미지를 저장한 후 애플리케이션을 종료할 수 있습니다. 그림을 그리는 동안 Options 메뉴를 통해 사용자는 펜 색상과 펜 너비를 선택하고 화면을 지울 수 있습니다. 또한 Help 메뉴는 특히 Scribble 예제 및 Qt 전반에 대한 정보를 사용자에게 제공합니다.
이 예제는 두 가지 클래스로 구성됩니다:
ScribbleArea
는 QImage 를 표시하고 사용자가 그 위에 그림을 그릴 수 있도록 하는 사용자 정의 위젯입니다.MainWindow
는ScribbleArea
위에 메뉴를 제공합니다.
ScribbleArea
클래스를 살펴보는 것으로 시작하겠습니다. 그런 다음 ScribbleArea
을 사용하는 MainWindow
클래스를 살펴보겠습니다.
ScribbleArea 클래스 정의
class ScribbleArea : public QWidget { Q_OBJECT public: ScribbleArea(QWidget *parent = nullptr); bool openImage(const QString &fileName); bool saveImage(const QString &fileName, const char *fileFormat); void setPenColor(const QColor &newColor); void setPenWidth(int newWidth); bool isModified() const { return modified; } QColor penColor() const { return myPenColor; } int penWidth() const { return myPenWidth; } public slots: void clearImage(); void print(); protected: void mousePressEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void paintEvent(QPaintEvent *event) override; void resizeEvent(QResizeEvent *event) override; private: void drawLineTo(const QPoint &endPoint); void resizeImage(QImage *image, const QSize &newSize); bool modified = false; bool scribbling = false; int myPenWidth = 1; QColor myPenColor = Qt::blue; QImage image; QPoint lastPoint; };
ScribbleArea
클래스는 QWidget 에서 상속합니다. mousePressEvent()
, mouseMoveEvent()
및 mouseReleaseEvent()
함수를 재구현하여 그림을 구현합니다. paintEvent()
함수를 재구현하여 낙서 영역을 업데이트하고 resizeEvent()
함수를 재구현하여 그림을 그리는 QImage 이 언제든지 위젯만큼 커지도록 합니다.
openImage()
함수는 파일에서 낙서 영역으로 이미지를 로드하여 사용자가 이미지를 편집할 수 있도록 하고, save()
함수는 현재 표시된 이미지를 파일에 쓰고, clearImage()
함수는 낙서 영역에 표시된 이미지를 지웁니다. 실제로 그림을 그리려면 drawLineTo()
함수가 필요하고, QImage 의 크기를 변경하려면 resizeImage()
이 필요합니다. print()
슬롯은 인쇄를 처리합니다.
또한 다음과 같은 비공개 변수가 필요합니다:
modified
낙서 영역에 표시된 이미지에 저장되지 않은 변경 사항이 있는 경우true
입니다.scribbling
는 사용자가 낙서 영역 내에서 마우스 왼쪽 버튼을 누르고 있는 동안true
입니다.penWidth
및penColor
은 애플리케이션에서 사용되는 펜의 현재 설정된 너비와 색상을 유지합니다.image
사용자가 그린 이미지를 저장합니다.lastPoint
는 마지막 마우스 누름 또는 마우스 이동 이벤트에서 커서의 위치를 유지합니다.
ScribbleArea 클래스 구현
ScribbleArea::ScribbleArea(QWidget *parent) : QWidget(parent) { setAttribute(Qt::WA_StaticContents); }
생성자에서 위젯에 Qt::WA_StaticContents 속성을 설정하여 위젯 내용이 왼쪽 상단 모서리에 루팅되고 위젯의 크기가 조정될 때 변경되지 않음을 나타냅니다. Qt는 이 속성을 사용하여 크기 조정 시 페인트 이벤트를 최적화합니다. 이것은 순전히 최적화이며 콘텐츠가 정적이고 왼쪽 상단 모서리에 루팅된 위젯에만 사용해야 합니다.
bool ScribbleArea::openImage(const QString &fileName) { QImage loadedImage; if (!loadedImage.load(fileName)) return false; QSize newSize = loadedImage.size().expandedTo(size()); resizeImage(&loadedImage, newSize); image = loadedImage; modified = false; update(); return true; }
openImage()
함수에서는 지정된 이미지를 로드합니다. 그런 다음 비공개 resizeImage()
함수를 사용하여 로드된 QImage 의 크기를 양방향으로 위젯만큼 크도록 조정하고 image
멤버 변수를 로드된 이미지로 설정합니다. 마지막으로 QWidget::update()를 호출하여 다시 그리기를 예약합니다.
bool ScribbleArea::saveImage(const QString &fileName, const char *fileFormat) { QImage visibleImage = image; resizeImage(&visibleImage, size()); if (visibleImage.save(fileName, fileFormat)) { modified = false; return true; } return false; }
saveImage()
함수는 실제 image
의 보이는 부분만 덮는 QImage 객체를 생성하고 QImage::save()를 사용하여 저장합니다. 이미지가 성공적으로 저장되면 저장되지 않은 데이터가 없으므로 낙서 영역의 modified
변수를 false
으로 설정합니다.
void ScribbleArea::setPenColor(const QColor &newColor) { myPenColor = newColor; } void ScribbleArea::setPenWidth(int newWidth) { myPenWidth = newWidth; }
setPenColor()
및 setPenWidth()
함수는 현재 펜 색상과 너비를 설정합니다. 이 값은 향후 그리기 작업에 사용됩니다.
void ScribbleArea::clearImage() { image.fill(qRgb(255, 255, 255)); modified = true; update(); }
공개 clearImage()
슬롯은 낙서 영역에 표시된 이미지를 지웁니다. RGB 값(255, 255, 255)에 해당하는 흰색으로 전체 이미지를 채우기만 하면 됩니다. 이미지를 수정할 때 평소와 같이 modified
을 true
으로 설정하고 다시 칠하기 일정을 잡습니다.
void ScribbleArea::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { lastPoint = event->position().toPoint(); scribbling = true; } } void ScribbleArea::mouseMoveEvent(QMouseEvent *event) { if ((event->buttons() & Qt::LeftButton) && scribbling) drawLineTo(event->position().toPoint()); } void ScribbleArea::mouseReleaseEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton && scribbling) { drawLineTo(event->position().toPoint()); scribbling = false; } }
마우스 누르기 및 마우스 놓기 이벤트의 경우 QMouseEvent::button() 함수를 사용하여 어떤 버튼이 이벤트를 발생시켰는지 확인합니다. 마우스 이동 이벤트의 경우 QMouseEvent::buttons()를 사용하여 현재 누르고 있는 버튼(OR 조합)을 찾습니다.
사용자가 마우스 왼쪽 버튼을 누르면 마우스 커서 위치를 lastPoint
에 저장합니다. 또한 사용자가 현재 낙서를 하고 있다는 사실도 기록합니다. ( scribbling
변수는 동일한 위젯에서 마우스 이동 및 마우스 놓기 이벤트가 항상 마우스 누르기 이벤트 앞에 있다고 가정할 수 없으므로 필요합니다.)
사용자가 왼쪽 버튼을 누른 상태에서 마우스를 움직이거나 버튼을 놓으면 비공개 drawLineTo()
함수를 호출하여 그림을 그립니다.
void ScribbleArea::paintEvent(QPaintEvent *event) { QPainter painter(this); QRect dirtyRect = event->rect(); painter.drawImage(dirtyRect, image, dirtyRect); }
paintEvent() 함수를 다시 구현할 때는 낙서 영역에 QPainter 을 생성하고 이미지를 그리기만 하면 됩니다.
이 시점에서 왜 QImage 에 그림을 그리고 QImage 을 paintEvent()
에 화면에 복사하는 대신 위젯에 직접 그리지 않는지 궁금하실 것입니다. 여기에는 적어도 세 가지 좋은 이유가 있습니다:
- 창 시스템에서는 언제든지 위젯을 다시 그릴 수 있어야 합니다. 예를 들어 창이 최소화되었다가 다시 복원되는 경우 창 시스템이 위젯의 내용을 잊어버리고 페인트 이벤트를 보낼 수 있습니다. 다시 말해, 창 시스템이 이미지를 기억하는 데 의존할 수 없다는 뜻입니다.
- Qt는 일반적으로
paintEvent()
외부에서 페인트하는 것을 허용하지 않습니다. 특히 마우스 이벤트 핸들러에서는 페인트할 수 없습니다. (하지만 Qt::WA_PaintOnScreen 위젯 속성을 사용하면 이 동작을 변경할 수 있습니다.) - 제대로 초기화하면 QImage 은 각 색상 채널(빨강, 녹색, 파랑, 알파)에 8비트를 사용하도록 보장되지만 QWidget 은 모니터 구성에 따라 색 농도가 낮아질 수 있습니다. 즉, 24비트 또는 32비트 이미지를 로드하여 QWidget 에 칠한 다음 QWidget 을 다시 QImage 에 복사하면 일부 정보가 손실될 수 있습니다.
void ScribbleArea::resizeEvent(QResizeEvent *event) { if (width() > image.width() || height() > image.height()) { int newWidth = qMax(width() + 128, image.width()); int newHeight = qMax(height() + 128, image.height()); resizeImage(&image, QSize(newWidth, newHeight)); update(); } QWidget::resizeEvent(event); }
사용자가 낙서 애플리케이션을 시작하면 크기 조정 이벤트가 생성되고 이미지가 생성되어 낙서 영역에 표시됩니다. 사용자가 메인 창의 크기를 조정할 때 항상 이미지의 크기를 조정하지 않도록 이 초기 이미지를 애플리케이션의 메인 창과 낙서 영역보다 약간 크게 만듭니다(이는 매우 비효율적일 수 있음). 그러나 기본 창이 이 초기 크기보다 커지면 이미지의 크기를 조정해야 합니다.
void ScribbleArea::drawLineTo(const QPoint &endPoint) { QPainter painter(&image); painter.setPen(QPen(myPenColor, myPenWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); painter.drawLine(lastPoint, endPoint); modified = true; int rad = (myPenWidth / 2) + 2; update(QRect(lastPoint, endPoint).normalized() .adjusted(-rad, -rad, +rad, +rad)); lastPoint = endPoint; }
drawLineTo()
에서 마지막으로 마우스를 누르거나 마우스를 움직였을 때 마우스가 있던 지점에서 선을 그리고 modified
을 true로 설정하고 다시 그리기 이벤트를 생성한 다음 lastPoint
을 업데이트하여 다음에 drawLineTo()
이 호출될 때 떠났던 지점에서 계속 그리도록 합니다.
update()
함수를 매개변수 없이 호출할 수도 있지만, 위젯이 완전히 다시 칠해지는 것을 방지하기 위해 쉬운 최적화를 위해 낙서 내부의 직사각형이 업데이트되어야 함을 지정하는 QRect 을 전달합니다.
void ScribbleArea::resizeImage(QImage *image, const QSize &newSize) { if (image->size() == newSize) return; QImage newImage(newSize, QImage::Format_RGB32); newImage.fill(qRgb(255, 255, 255)); QPainter painter(&newImage); painter.drawImage(QPoint(0, 0), *image); *image = newImage; }
QImage 에는 이미지 크기를 조정할 수 있는 좋은 API가 없습니다. QImage::copy () 함수가 있지만 이미지를 확장하는 데 사용하면 새 영역을 검은색으로 채우는 반면, 우리는 흰색을 원합니다.
따라서 요령은 적절한 크기의 새로운 QImage 을 만들고 흰색으로 채운 다음 QPainter 을 사용하여 이전 이미지를 그 위에 그리는 것입니다. 새 이미지에는 QImage::Format_RGB32 형식이 지정되며, 이는 각 픽셀이 0xffRRGGBB로 저장됨을 의미합니다(여기서 RR, GG 및 BB는 빨강, 녹색 및 파랑 색상 채널이고 ff는 16진수 값 255).
인쇄는 print()
슬롯에서 처리합니다:
void ScribbleArea::print() { #if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printdialog) QPrinter printer(QPrinter::HighResolution); QPrintDialog printDialog(&printer, this);
필요한 출력 형식에 맞는 고해상도 QPrinter 객체를 구성하고, 사용자에게 페이지 크기를 지정하고 페이지에서 출력 형식을 지정하도록 요청하는 QPrintDialog를 사용합니다.
대화 상자가 수락되면 페인트 장치로 인쇄하는 작업을 수행합니다:
if (printDialog.exec() == QDialog::Accepted) { QPainter painter(&printer); QRect rect = painter.viewport(); QSize size = image.size(); size.scale(rect.size(), Qt::KeepAspectRatio); painter.setViewport(rect.x(), rect.y(), size.width(), size.height()); painter.setWindow(image.rect()); painter.drawImage(0, 0, image); } #endif // QT_CONFIG(printdialog) }
이런 방식으로 이미지를 파일로 인쇄하는 것은 단순히 Q프린터에 그림을 그리기만 하면 됩니다. 페인트 장치에 그림을 그리기 전에 페이지의 사용 가능한 공간에 맞게 이미지의 크기를 조정합니다.
메인창 클래스 정의
class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); protected: void closeEvent(QCloseEvent *event) override; private slots: void open(); void save(); void penColor(); void penWidth(); void about(); private: void createActions(); void createMenus(); bool maybeSave(); bool saveFile(const QByteArray &fileFormat); ScribbleArea *scribbleArea; QMenu *saveAsMenu; QMenu *fileMenu; QMenu *optionMenu; QMenu *helpMenu; QAction *openAct; QList<QAction *> saveAsActs; QAction *exitAct; QAction *penColorAct; QAction *penWidthAct; QAction *printAct; QAction *clearScreenAct; QAction *aboutAct; QAction *aboutQtAct; };
MainWindow
클래스는 QMainWindow 에서 상속합니다. QWidget 에서 closeEvent() 핸들러를 다시 구현합니다. open()
, save()
, penColor()
및 penWidth()
슬롯은 메뉴 항목에 해당합니다. 또한 네 개의 비공개 함수를 만듭니다.
부울 maybeSave()
함수를 사용하여 저장되지 않은 변경 사항이 있는지 확인합니다. 저장되지 않은 변경 사항이 있는 경우 사용자에게 이러한 변경 사항을 저장할 수 있는 기회를 제공합니다. 이 함수는 사용자가 Cancel 을 클릭하면 false
을 반환합니다. saveFile()
함수를 사용하여 사용자가 현재 낙서 영역에 표시된 이미지를 저장할 수 있도록 합니다.
MainWindow 클래스 구현
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), scribbleArea(new ScribbleArea(this)) { setCentralWidget(scribbleArea); createActions(); createMenus(); setWindowTitle(tr("Scribble")); resize(500, 500); }
생성자에서 MainWindow
위젯의 중앙 위젯을 만드는 낙서 영역을 만듭니다. 그런 다음 관련 액션과 메뉴를 만듭니다.
void MainWindow::closeEvent(QCloseEvent *event) { if (maybeSave()) event->accept(); else event->ignore(); }
닫기 이벤트는 일반적으로 사용자가 File|Exit 또는 X 제목 표시줄 버튼을 클릭하여 닫으려는 위젯으로 전송됩니다. 이벤트 핸들러를 다시 구현하면 애플리케이션을 닫으려는 시도를 가로챌 수 있습니다.
이 예제에서는 닫기 이벤트를 사용하여 사용자에게 저장되지 않은 변경 사항을 저장하도록 요청합니다. 이를 위한 로직은 maybeSave()
함수에 있습니다. maybeSave()
이 true를 반환하면 수정 사항이 없거나 사용자가 성공적으로 저장한 것이므로 이벤트를 수락합니다. 그러면 애플리케이션이 정상적으로 종료될 수 있습니다. maybeSave()
이 false를 반환하면 사용자가 Cancel 을 클릭한 것이므로 이벤트를 '무시'하고 애플리케이션은 영향을 받지 않습니다.
void MainWindow::open() { if (maybeSave()) { QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), QDir::currentPath()); if (!fileName.isEmpty()) scribbleArea->openImage(fileName); } }
open()
슬롯에서는 새 이미지가 낙서 영역에 로드되기 전에 먼저 사용자에게 현재 표시된 이미지에 대한 수정 사항을 저장할 기회를 제공합니다. 그런 다음 사용자에게 파일을 선택하도록 요청하고 ScribbleArea
에 파일을 로드합니다.
void MainWindow::save() { QAction *action = qobject_cast<QAction *>(sender()); QByteArray fileFormat = action->data().toByteArray(); saveFile(fileFormat); }
save()
슬롯은 사용자가 Save As 메뉴 항목을 선택한 다음 형식 메뉴에서 항목을 선택하면 호출됩니다. 가장 먼저 해야 할 일은 QObject::sender()를 사용하여 어떤 액션이 신호를 보냈는지 알아내는 것입니다. 이 함수는 발신자를 QObject 포인터로 반환합니다. 발신자가 액션 객체라는 것을 알고 있으므로 QObject 을 안전하게 캐스팅할 수 있습니다. C 스타일 캐스팅이나 C++ static_cast<>()
을 사용할 수도 있었지만 방어적인 프로그래밍 기법으로 qobject_cast()을 사용했습니다. 객체의 유형이 잘못된 경우 널 포인터가 반환된다는 장점이 있습니다. 널 포인터로 인한 크래시는 안전하지 않은 형변환으로 인한 크래시보다 진단하기가 훨씬 쉽습니다.
액션이 생성되면 QAction::data()를 사용하여 선택한 형식을 추출합니다. (액션이 생성되면 QAction::setData()를 사용하여 액션에 첨부된 자체 사용자 지정 데이터를 QVariant 으로 설정합니다. 자세한 내용은 createActions()
을 참조하세요.)
이제 형식을 알았으니 비공개 saveFile()
함수를 호출하여 현재 표시된 이미지를 저장합니다.
void MainWindow::penColor() { QColor newColor = QColorDialog::getColor(scribbleArea->penColor()); if (newColor.isValid()) scribbleArea->setPenColor(newColor); }
penColor()
슬롯을 사용하여 QColorDialog 을 통해 사용자로부터 새 색상을 검색합니다. 사용자가 새 색상을 선택하면 해당 색상을 낙서 영역의 색상으로 만듭니다.
void MainWindow::penWidth() { bool ok; int newWidth = QInputDialog::getInt(this, tr("Scribble"), tr("Select pen width:"), scribbleArea->penWidth(), 1, 50, 1, &ok); if (ok) scribbleArea->setPenWidth(newWidth); }
penWidth()
슬롯에서 새 펜 너비를 검색하려면 QInputDialog 을 사용합니다. QInputDialog 클래스는 사용자로부터 단일 값을 가져오는 간단한 편의 대화 상자를 제공합니다. QLabel 과 QSpinBox 을 결합한 정적 QInputDialog::getInt() 함수를 사용합니다. QSpinBox 은 낙서 영역의 펜 너비로 초기화되며, 1에서 50까지의 범위를 허용하고 1단계(위쪽 및 아래쪽 화살표가 값을 1씩 늘리거나 줄인다는 의미)로 설정할 수 있습니다.
부울 ok
변수는 사용자가 OK 을 클릭하면 true
으로, Cancel 을 누르면 false
으로 설정됩니다.
void MainWindow::about() { QMessageBox::about(this, tr("About Scribble"), tr("<p>The <b>Scribble</b> example shows how to use QMainWindow as the " "base widget for an application, and how to reimplement some of " "QWidget's event handlers to receive the events generated for " "the application's widgets:</p><p> We reimplement the mouse event " "handlers to facilitate drawing, the paint event handler to " "update the application and the resize event handler to optimize " "the application's appearance. In addition we reimplement the " "close event handler to intercept the close events before " "terminating the application.</p><p> The example also demonstrates " "how to use QPainter to draw an image in real time, as well as " "to repaint widgets.</p>")); }
about()
슬롯을 구현하여 이 예제에서 표시하려는 내용을 설명하는 메시지 상자를 만듭니다.
void MainWindow::createActions() { openAct = new QAction(tr("&Open..."), this); openAct->setShortcuts(QKeySequence::Open); connect(openAct, &QAction::triggered, this, &MainWindow::open); const QList<QByteArray> imageFormats = QImageWriter::supportedImageFormats(); for (const QByteArray &format : imageFormats) { QString text = tr("%1...").arg(QString::fromLatin1(format).toUpper()); QAction *action = new QAction(text, this); action->setData(format); connect(action, &QAction::triggered, this, &MainWindow::save); saveAsActs.append(action); } printAct = new QAction(tr("&Print..."), this); connect(printAct, &QAction::triggered, scribbleArea, &ScribbleArea::print); exitAct = new QAction(tr("E&xit"), this); exitAct->setShortcuts(QKeySequence::Quit); connect(exitAct, &QAction::triggered, this, &MainWindow::close); penColorAct = new QAction(tr("&Pen Color..."), this); connect(penColorAct, &QAction::triggered, this, &MainWindow::penColor); penWidthAct = new QAction(tr("Pen &Width..."), this); connect(penWidthAct, &QAction::triggered, this, &MainWindow::penWidth); clearScreenAct = new QAction(tr("&Clear Screen"), this); clearScreenAct->setShortcut(tr("Ctrl+L")); connect(clearScreenAct, &QAction::triggered, scribbleArea, &ScribbleArea::clearImage); aboutAct = new QAction(tr("&About"), this); connect(aboutAct, &QAction::triggered, this, &MainWindow::about); aboutQtAct = new QAction(tr("About &Qt"), this); connect(aboutQtAct, &QAction::triggered, qApp, &QApplication::aboutQt); }
createAction()
함수에서는 메뉴 항목을 나타내는 액션을 생성하고 이를 적절한 슬롯에 연결합니다. 특히 Save As 하위 메뉴에 있는 액션을 만듭니다. QImageWriter::supportedImageFormats ()를 사용하여 지원되는 형식의 목록을 가져옵니다( QList<QByteArray>).
그런 다음 목록을 반복하여 각 형식에 대한 액션을 만듭니다. 파일 형식으로 QAction::setData()를 호출하여 나중에 QAction::data()로 검색할 수 있도록 합니다. 액션의 텍스트에서 "..."를 잘라내어 파일 형식을 추론할 수도 있었지만, 그렇게 하면 세련되지 못했을 것입니다.
void MainWindow::createMenus() { saveAsMenu = new QMenu(tr("&Save As"), this); for (QAction *action : std::as_const(saveAsActs)) saveAsMenu->addAction(action); fileMenu = new QMenu(tr("&File"), this); fileMenu->addAction(openAct); fileMenu->addMenu(saveAsMenu); fileMenu->addAction(printAct); fileMenu->addSeparator(); fileMenu->addAction(exitAct); optionMenu = new QMenu(tr("&Options"), this); optionMenu->addAction(penColorAct); optionMenu->addAction(penWidthAct); optionMenu->addSeparator(); optionMenu->addAction(clearScreenAct); helpMenu = new QMenu(tr("&Help"), this); helpMenu->addAction(aboutAct); helpMenu->addAction(aboutQtAct); menuBar()->addMenu(fileMenu); menuBar()->addMenu(optionMenu); menuBar()->addMenu(helpMenu); }
createMenu()
함수에서는 이전에 만든 형식 액션을 saveAsMenu
에 추가한 다음 나머지 액션과 saveAsMenu
하위 메뉴를 File, Options 및 Help 메뉴에 추가합니다.
QMenu 클래스는 메뉴 모음, 컨텍스트 메뉴 및 기타 팝업 메뉴에서 사용할 수 있는 메뉴 위젯을 제공합니다. QMenuBar 클래스는 풀다운 QMenu목록이 있는 가로 메뉴 바를 제공하며, 마지막에는 QMainWindow::menuBar() 함수를 사용하여 검색하는 File 및 Options 메뉴를 MainWindow
의 메뉴 바에 넣습니다.
bool MainWindow::maybeSave() { if (scribbleArea->isModified()) { QMessageBox::StandardButton ret; ret = QMessageBox::warning(this, tr("Scribble"), tr("The image has been modified.\n" "Do you want to save your changes?"), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); if (ret == QMessageBox::Save) return saveFile("png"); else if (ret == QMessageBox::Cancel) return false; } return true; }
mayBeSave()
에서 저장되지 않은 변경 사항이 있는지 확인합니다. 변경 사항이 있는 경우 QMessageBox 을 사용하여 사용자에게 이미지가 수정되었다는 경고와 함께 수정 사항을 저장할 수 있는 기회를 제공합니다.
QColorDialog 및 QFileDialog 과 마찬가지로 QMessageBox 을 만드는 가장 쉬운 방법은 정적 함수를 사용하는 것입니다. QMessageBox 은 심각도(질문, 정보, 경고 및 심각)와 복잡도(필요한 응답 버튼의 수)라는 두 축을 따라 배열된 다양한 메시지를 제공합니다. 여기서는 메시지가 다소 중요하므로 warning()
함수를 사용합니다.
사용자가 저장을 선택하면 비공개 saveFile()
함수를 호출합니다. 간단하게 PNG를 파일 형식으로 사용하며, 사용자는 언제든지 Cancel 을 눌러 다른 형식을 사용하여 파일을 저장할 수 있습니다.
maybeSave()
함수는 사용자가 Cancel 을 클릭하면 false
을 반환하고, 그렇지 않으면 true
을 반환합니다.
bool MainWindow::saveFile(const QByteArray &fileFormat) { QString initialPath = QDir::currentPath() + "/untitled." + fileFormat; QString fileName = QFileDialog::getSaveFileName(this, tr("Save As"), initialPath, tr("%1 Files (*.%2);;All Files (*)") .arg(QString::fromLatin1(fileFormat.toUpper())) .arg(QString::fromLatin1(fileFormat))); if (fileName.isEmpty()) return false; return scribbleArea->saveImage(fileName, fileFormat.constData()); }
saveFile()
에서는 파일 이름 제안과 함께 파일 대화 상자를 표시합니다. 정적 QFileDialog::getSaveFileName() 함수는 사용자가 선택한 파일 이름을 반환합니다. 파일이 존재할 필요는 없습니다.
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.