SDI Application


لاحظ إن ال Application عبارة عن
1 – Main Window
2 – MenuBar بتشمل File, Edit, Help menus
3- ToolBar 2
الأول هو fileToolBar وفيه new, open and save
التانى هو editToolBar وفيه cut, copy and paste
4- TextEdit
5- StatusBar
هنحتاج نعمل 3 ملفات لل Application
1- mainwindow.h فيه ال class design
2- mainwindow.cpp فيه ال class implementation
3- main.cpp فيه ال entry point لل Application
mainwindow.h
بداية قبل اى شئ
كود:
#ifndef MAINWINDOW_H #define MAINWINDOW_H
#include <QMainWindow>
عشان نورثها لل mainwindow class
كود:
class MainWindow : public QMainWindow
كود:
class QAction; class QMenu; class QTextEdit;
هنعمل فى ال class دا Override لل virtual closeEvent method وهى method بت fired كل ميحصل محاولة ل قفل ال window فإحنا هنعمل ليها new definition عشان نستخدم ال
famous message “you wanna quit !? “
ال class هيكون ليه slots خاصة فيه يبقة لازم نعرف الmacro Q_OBJECT!
ال slots هتكون إيه ؟
newFile, save, saveAs, about, documentWasModified
ال newFile هنستخدمها عشان نبدأ فى new file
ال save/save as عشان نحفظ الملف بيهم
ال about هنستخدمها عشان نظهر window بتتكلم عن البرنامج وهناك هنستخدم qtabout الموجودة فى Qapplication!
ال documentWasModified عشان تشير هل الملف اتعدل فيه ولا لأ عشان نستخدم save or not MSG
ندخل فى ميثودز ال class نفسها بقة
1- init()
2- createActions()
3- createMenus()
4- createToolBars()
5- createStatusBar()
6- bool maybeSave()
7- loadFile()
8- bool saveFile()
9- setCurrentFile()
10- QString strippedName()
11- QMainWindow findMainWindow()
احنا ممكن نخلى ال GUI فى ال Constructor بس المشكلة الوحيدة هى إننا عندنا 2 Constructors فمش عايزين نكرر نفسنا فنعمل ميثود لل init window
strippedName بترجع لينا اسم الفيل بدون ال full name
ال fields
كود:
QTextEdit *textEdit; QString curFile; bool isUntitled; QMenu *fileMenu; QMenu *editMenu; QMenu *helpMenu; QToolBar *fileToolBar; QToolBar *editToolBar; QAction *newAct; QAction *openAct; QAction *saveAct; QAction *saveAsAct; QAction *closeAct; QAction *exitAct; QAction *cutAct; QAction *copyAct; QAction *pasteAct; QAction *aboutAct; QAction *aboutQtAct
وهى عبارة عن الActions/Menus/ToolBars
isUntitled لتشير هل الملف لسه اول مرة ومش اتحفظ بإسم ولا لأ
curFile لتشير للملف الحالى
وبكدا يبقة خلص ال header
الصورة النهائية ليه
كود:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> class QAction; class QMenu; class QTextEdit; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(); MainWindow(const QString &fileName); protected: void closeEvent(QCloseEvent *event); private slots: void newFile(); void open(); bool save(); bool saveAs(); void about(); void documentWasModified(); private: void init(); void createActions(); void createMenus(); void createToolBars(); void createStatusBar(); void readSettings(); void writeSettings(); bool maybeSave(); void loadFile(const QString &fileName); bool saveFile(const QString &fileName); void setCurrentFile(const QString &fileName); QString strippedName(const QString &fullFileName); MainWindow *findMainWindow(const QString &fileName); QTextEdit *textEdit; QString curFile; bool isUntitled; QMenu *fileMenu; QMenu *editMenu; QMenu *helpMenu; QToolBar *fileToolBar; QToolBar *editToolBar; QAction *newAct; QAction *openAct; QAction *saveAct; QAction *saveAsAct; QAction *closeAct; QAction *exitAct; QAction *cutAct; QAction *copyAct; QAction *pasteAct; QAction *aboutAct; QAction *aboutQtAct; }; #endif
كود:
<!DOCTYPE RCC><RCC version="1.0"> <qresource> <file>images/copy.png</file> <file>images/cut.png</file> <file>images/new.png</file> <file>images/open.png</file> <file>images/paste.png</file> <file>images/save.png</file> </qresource> </RCC>
هنحتاج نستخدم QtGui عشان ال widgets وال windows وهنحتاج نعمل include لل mainwindow.h
كود:
#include <QtGui> #include "mainwindow.h"
v
كود:
oid MainWindow::init() { setAttribute(Qt::WA_DeleteOnClose); isUntitled = true; textEdit = new QTextEdit; setCentralWidget(textEdit); createActions(); createMenus(); createToolBars(); createStatusBar(); readSettings(); connect(textEdit->document(), SIGNAL(contentsChanged()), this, SLOT(documentWasModified())); }
نعمل QtextEdit Object ونخليه فى سنتر الويندو لأن فوقه ال menu/toolbars وتحته ال statusbar
createActions و createMenus و createToolsBars و createStatusBar بتنشئ لينا ال Actions/Menus/Toolbars/StatusBar
ال Actions
كود:
void MainWindow::createActions() { newAct = new QAction(QIcon(":/images/new.png"), tr("&New"), this); newAct->setShortcut(tr("Ctrl+N")); newAct->setStatusTip(tr("Create a new file")); connect(newAct, SIGNAL(triggered()), this, SLOT(newFile())); openAct = new QAction(QIcon(":/images/open.png"), tr("&Open..."), this); openAct->setShortcut(tr("Ctrl+O")); openAct->setStatusTip(tr("Open an existing file")); connect(openAct, SIGNAL(triggered()), this, SLOT(open())); saveAct = new QAction(QIcon(":/images/save.png"), tr("&Save"), this); saveAct->setShortcut(tr("Ctrl+S")); saveAct->setStatusTip(tr("Save the document to disk")); connect(saveAct, SIGNAL(triggered()), this, SLOT(save())); saveAsAct = new QAction(tr("Save &As..."), this); saveAsAct->setStatusTip(tr("Save the document under a new name")); connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAs())); closeAct = new QAction(tr("&Close"), this); closeAct->setShortcut(tr("Ctrl+W")); closeAct->setStatusTip(tr("Close this window")); connect(closeAct, SIGNAL(triggered()), this, SLOT(close())); exitAct = new QAction(tr("E&xit"), this); exitAct->setShortcut(tr("Ctrl+Q")); exitAct->setStatusTip(tr("Exit the application")); connect(exitAct, SIGNAL(triggered()), qApp, SLOT(closeAllWindows())); cutAct = new QAction(QIcon(":/images/cut.png"), tr("Cu&t"), this); cutAct->setShortcut(tr("Ctrl+X")); cutAct->setStatusTip(tr("Cut the current selection's contents to the " "clipboard")); connect(cutAct, SIGNAL(triggered()), textEdit, SLOT(cut())); copyAct = new QAction(QIcon(":/images/copy.png"), tr("&Copy"), this); copyAct->setShortcut(tr("Ctrl+C")); copyAct->setStatusTip(tr("Copy the current selection's contents to the " "clipboard")); connect(copyAct, SIGNAL(triggered()), textEdit, SLOT(copy())); pasteAct = new QAction(QIcon(":/images/paste.png"), tr("&Paste"), this); pasteAct->setShortcut(tr("Ctrl+V")); pasteAct->setStatusTip(tr("Paste the clipboard's contents into the current " "selection")); connect(pasteAct, SIGNAL(triggered()), textEdit, SLOT(paste())); aboutAct = new QAction(tr("&About"), this); aboutAct->setStatusTip(tr("Show the application's About box")); connect(aboutAct, SIGNAL(triggered()), this, SLOT(about())); aboutQtAct = new QAction(tr("About &Qt"), this); aboutQtAct->setStatusTip(tr("Show the Qt library's About box")); connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt())); cutAct->setEnabled(false); copyAct->setEnabled(false); connect(textEdit, SIGNAL(copyAvailable(bool)), cutAct, SLOT(setEnabled(bool))); connect(textEdit, SIGNAL(copyAvailable(bool)), copyAct, SLOT(setEnabled(bool))); }
كود:
newAct = new QAction(QIcon(":/images/new.png"), tr("&New"), this); newAct->setShortcut(tr("Ctrl+N")); newAct->setStatusTip(tr("Create a new file")); connect(newAct, SIGNAL(triggered()), this, SLOT(newFile()));
setStatusTip وهى ال text اللى هيظهر فى ال statusBar كل ماتمر على الnew Action
نربط ال triggered SIGNAL مع ال newFile SLOT ب Connect والsender هنا هيكون newAction وال receiver هيكون ال main window
لاحظ
كود:
aboutQtAct = new QAction(tr("About &Qt"), this); aboutQtAct->setStatusTip(tr("Show the Qt library's About box")); connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
ال Copy/Cut/Paste stuff انت مش ليك دعوة بيهم كل اللى عليك تربط ال Action بال textEdit وتستخدم ال slot المناسبة سواء copy, cut or paste
Keep it simple !
ال setEnabled اعتقد واضحة وهى إنك تقدر ت trigger ال Action او لأ وبتاخد true/false
كود:
void MainWindow::about() { QMessageBox::about(this, tr("About SDI"), tr("The <b>SDI</b> example demonstrates how to write single " "document interface applications using Qt.")); }
إنشاء ال menus
كود:
void MainWindow::createMenus() { fileMenu = menuBar()->addMenu(tr("&File")); fileMenu->addAction(newAct); fileMenu->addAction(openAct); fileMenu->addAction(saveAct); fileMenu->addAction(saveAsAct); fileMenu->addSeparator(); fileMenu->addAction(closeAct); fileMenu->addAction(exitAct); editMenu = menuBar()->addMenu(tr("&Edit")); editMenu->addAction(cutAct); editMenu->addAction(copyAct); editMenu->addAction(pasteAct); menuBar()->addSeparator(); helpMenu = menuBar()->addMenu(tr("&Help")); helpMenu->addAction(aboutAct); helpMenu->addAction(aboutQtAct); }
وفى كل menu عملتها تضيف ال Actions الخاصة بيها بإستخدام addAction ولتضيف separator إستخدام addSeparator method
عمل ال ToolBars بسيط جدا
كود:
void MainWindow::createToolBars() { fileToolBar = addToolBar(tr("File")); fileToolBar->addAction(newAct); fileToolBar->addAction(openAct); fileToolBar->addAction(saveAct); editToolBar = addToolBar(tr("Edit")); editToolBar->addAction(cutAct); editToolBar->addAction(copyAct); editToolBar->addAction(pasteAct);
createStatusBar
كود:
void MainWindow::createStatusBar() { statusBar()->showMessage(tr("Ready")); }
كود:
bool MainWindow::maybeSave() { if (textEdit->document()->isModified()) { QMessageBox::StandardButton ret; ret = QMessageBox::warning(this, tr("SDI"), tr("The document has been modified.\n" "Do you want to save your changes?"), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); if (ret == QMessageBox::Save) return save(); else if (ret == QMessageBox::Cancel) return false; } return true; }
loadFile
كود:
void MainWindow::loadFile(const QString &fileName) { QFile file(fileName); if (!file.open(QFile::ReadOnly | QFile::Text)) { QMessageBox::warning(this, tr("SDI"), tr("Cannot read file %1:\n%2.") .arg(fileName) .arg(file.errorString())); return; } QTextStream in(&file); QApplication::setOverrideCursor(Qt::WaitCursor); textEdit->setPlainText(in.readAll()); QApplication::restoreOverrideCursor(); setCurrentFile(fileName); statusBar()->showMessage(tr("File loaded"), 2000); }
لاحظ موضوع ال Qt::WaitCursor عشان نخلى الcursor باين إن فى بروسس شغالة
ال restoreOverrideCursor بنستعيد الcursor بصورته السابقة.
نخلى إسم ال currentFile هو إسم ال Opened File بإستخدام setCurrentFile ونشير فى ال statusBar ان ال File Loaded بإستخدام ال showMessage.
كود:
QString MainWindow::strippedName(const QString &fullFileName) { return QFileInfo(fullFileName).fileName(); }
setCurrentFile
كود:
void MainWindow::setCurrentFile(const QString &fileName) { static int sequenceNumber = 1; isUntitled = fileName.isEmpty(); if (isUntitled) { curFile = tr("document%1.txt").arg(sequenceNumber++); } else { curFile = QFileInfo(fileName).canonicalFilePath(); } textEdit->document()->setModified(false); setWindowModified(false); setWindowTitle(tr("%1[*] - %2").arg(strippedName(curFile)) .arg(tr("SDI"))); }
عمل Save لل File
كود:
bool MainWindow::saveFile(const QString &fileName) { QFile file(fileName); if (!file.open(QFile::WriteOnly | QFile::Text)) { QMessageBox::warning(this, tr("SDI"), tr("Cannot write file %1:\n%2.") .arg(fileName) .arg(file.errorString())); return false; } QTextStream out(&file); QApplication::setOverrideCursor(Qt::WaitCursor); out << textEdit->toPlainText(); QApplication::restoreOverrideCursor(); setCurrentFile(fileName); statusBar()->showMessage(tr("File saved"), 2000); return true; }
كود:
bool MainWindow::save() { if (isUntitled) { return saveAs(); } else { return saveFile(curFile); }
كود:
bool MainWindow::saveAs() { QString fileName = QFileDialog::getSaveFileName(this, tr("Save As"), curFile); if (fileName.isEmpty()) return false; return saveFile(fileName); }
فى حال لو مش ليه إسم او isUntitled هتدى true هيتم إستدعاء saveAs method وهى هتحفظ ال file ب save file dialog لطيف للمستخدم
بالمناسبة فى حالة ال newFileAction هيتعمل Object جديد من ال mainwindow وهكذا على بعد 40 و 40 من ال x, y اللى بادئ عنهم ال window
كود:
void MainWindow::newFile() { MainWindow *other = new MainWindow; other->move(x() + 40, y() + 40); other->show(); }
كود:
#include <QApplication> #include "mainwindow.h" int main(int argc, char *argv[]) { Q_INIT_RESOURCE(sdi); QApplication app(argc, argv); MainWindow *mainWin = new MainWindow; mainWin->show(); return app.exec(); }
كفاية كلام لحد كدا باقى السورس بسيط
المرة الجاية نبقة نعمل MDI Application
ال source من ال QT Examples فى mainwindow/sdi
ADIOS PPL!
تعليق