در جلسهٔ قبل این آموزش پروژهٔ کوچکی را با نام کیوتپد «CutePad» آغاز کردیم که یک نرمافزار ساده برای ویرایش متون و پروندههای متنی بود، این پروژه فعلاً کار خاصی انجام نمیدهد، فقط یک پنجره با ظاهری ساده را برای پروژهٔ کیوت خود توسط سی-میک ایجاد کردیم تا پروژه را برای ادامه کار شروع کرده باشیم. برای استفاده از کدهای این نوشته توصیه می:نم که در ابتدا کد منبع پروژه در جلسهٔ قبل را از طریق گیتهاب دریافت و بارگیری کنید، اگر هم از قسمت قبل این پروژه را دریافت کردهاید نیز آن مجدداً بگشایید تا بتوانید از آن استفاده کنید. گفتنی است اگر از طریق گیتهاب میخواهید کدها را بارگیری کنید، بهتر است مشخص کنید که اولین ارسال یا «Commit» را دریافت کنید و یا اینکه تغییراتی را که در این جلسه اعمال کردیم را نیز دریافت کنید. همچنین برای رفع این موضوع کمی اینترنت را جستجو کنید به پاسخ سوال میرسید. با این حال پروندهٔ فشرده و آرشیوی از کد جلسهٔ قبل را میتوانید ازاین پیوند دریافت کنید.
در این جلسه قصد دارم چند کد جدید را نیز آموزش دهم، مانند شیوهٔ کار با پروندهها در کیوت که بسیار ساده است. در سی++ روش خاصی برای کار با پرونده وجود دارد، امّا در این جا از روش مخصوص کیوت استفاده خواهیم کرد. در این قسمت کدهای دیگر مربوط به خروج از پنجره و برنامه را نیز خواهیم نوشت. همچنین در آخر یک پروندهٔ میانبر برای نرمافزار مینویسیم که با قرار دادن آن در پوشه نرمافزارهای کاربردی در توزیع خود میتوانید به آن از طریق فهرست نرمافزارهای میزکار خود دسترسی داشته باشید. این کار را زمانی انجام میدهیم که نرمافزار به صورت کامل نوشته شود. زمانی که این پروژه را به صورت کامل نوشتیم، میتوانیم نرمافزار جدیدی را توسعه دهیم. در آخرین جلسات به آموزش ساخت یک نرمافزار برای سیستمعامل اندروید و نحوهٔ اجرا و تنظیم آن خواهیم پرداخت. برخلاف اکثر مطالب آموزش برنامهنویسی اندروید که از جاوا و سیستمعاملهای دیگری چون ویندوز و اواس ده استفاده میکنند، آموزش برنامهنویسی در اندروید را با استفاده از گنو/لینوکس انجام داده و مراحل نصب شبیهساز غیر متنباز و غیر رایگاه ولی رایگاه برای استفادهٔ شخصی «Gemymotion» و استفاده از آن در کیوت را نیز آموزش خواهیم داد زیرا که SDK خود اندروید در گنو/لینوکس کندتر است. (نمایی از یک بازی ساده نوشته شده توسط کیوت اجرا شده در جمیموشن و اندروید ۵/۱ را مشاهده میکنید.)
مقدمات و برخی توضیحات
در ابتدا از برخی مبانی کار میگوییم تا به قسمت نوشتن کدهای نرمافزار کیوت-پد برسیم. تمامی این موارد به کلاسهایی اختصاص دارد که در این مثال و این جلسه استفاده میشوند. این مسائل برای این در ابتدا گفته میشوند که در هنگامی که کدها را مشاهده میکنید، مشکلی نداشته باشید، با این حال همانطور که در قسمت اول و جلسهٔ مقدمه ذکر کردم، باید به زبان سی++ مسلط باشید و اگر نه نمیتوانید درک درستی از کدهای زیر داشته باشید. کدهایی که از کلاسهای کیوت استفاده میکنند را توضیح میدهم ولی قصد ما از این مطلب آشنایی شما با نحوهٔ نوشتن کد در کیوت و یا مدیریت پروژه، اجرا و استفاده از کلاسها است و نه آموزش زبان سی++ از پایه.
QFile:
این کلاس برای گشودن یک پرونده بهکار میرود و در این پروژه قصد داریم از آن استفاده کنیم تا پروندههای متنی را بگشاییم. این کلاس تنها به آدرس پرونده نیاز دارد تا بتواند آن را برای ما نمایش دهد. بعد از آن که این کلاس تعریف شد، باید آن را به QTextStream نسبت دهیم، البته در این موقع باید قبل نام کلاس یک & بنویسیم.
QTextStream:
از این کلاس قبلاً استفاده کردهایم، این کلاس برای ایجاد یک جریان متنی کاربرد دارد، این جریان متنی را میتوان به طرف خروجی هدایت کرد یا به یک پرونده. گفتنی است اگر با استفاده از ین کلاس و کلاس قبلی پروندهٔ dev/random/ را بگشایید، مقداری متن تصادفی تولید خواهد شد که برای برخی کاربردها بسیار مناسب است.
QFileDialog:
همانطور که از نامش پیداست برای گشودن برخی کادرهای محاورهای که مرتبط با گشودن و ذخیرهٔ پرونده هستند، استفاده میشود. اگر میخواهید دیگر کادرهای محاورهای را باز کنید، کلاس مخصوص به خود را دارند که در جلسهٔ بعد توضیح خواهم داد.
QFileInfo:
برای نمایش برخی اطلاعات از پروندهها به کار میرود، مثلاً نام پرونده چیست یا برخی اطلاعات دیگر مانند تاریخ و … . در این پروژه از این کلاس استفاده کردهایم تا نام پرونده را بدون در نظر گرفتن آدرسش در نوار عنوان نمایش دهیم. همچون برخی ویرایشگرهای متن مرسوم که نام پرونده را در نوار عنوان به نمایش میگزارند.
مثالی ساده:
به مثال زیر اگر توجه کنید، در آن از کلاس QFile استفاده شده است، در این مثال پروندهای گشوده میشود، مقادیری در آن ذخیره شده و سپس برنامه بسته میشود.
#include <QTextStream> #include <QFile> int main() { QFile data("myfile"); if (data.open(QFile::WriteOnly)) { QTextStream out(&data); out << "You make me want to be a better man." << endl; } }
در داخل متغیر myfile باید آدرس دقیق پرونده را وارد کنید. سپس اگر وارد پروندهٔ فوق شوید مقادیری که در زیر نوشته شده را در آن مشاهده خواهید کرد.
out << "You make me want to be a better man." << endl;
در این کد مشخص شده است که پرونده را برای نوشتن نیاز دارد و در همان شرط عمل گشودن پرونده انجام شده است. سپس QTextSream را به سادگی out نام نهاده و متنی را به آن نسبت داده است.
if (data.open(QFile::WriteOnly)) { QTextStream out(&data); out << "You make me want to be a better man." << endl; }
کد بالا کد سادهای بود، متن زیر را که به زبان مجارستانی است را میخواهیم به صورت UTF-8 باز کنیم. UTF-8 را برای خط و زبانهای غیر لاتین و انگلیسی به کار میبرند.
S a régi szeretőmér mit nem cselekednék, tengerből a vizet kanállal lemerném. S a tenger fenekéről apró gyöngyöt szednék, s a régi szeretőmnek gyöngykoszorút kötnék.
کدهایی که برای گشودن این متن استفاده میشود همانند کد قبلی است، با این تفوات که در زمان ساخت جریان متنی «QTextStream» باید مشخص شود که متن باید به چه شکلی گشوده یا ذخیره شود.
#include <QTextStream> #include <QFile> int main() { QFile data("szerelem"); QString line; if (data.open(QFile::ReadOnly)) { QTextStream in(&data); QTextStream out(stdout); out.setCodec("UTF-8"); in.setCodec("UTF-8"); do { line = in.readLine(); out << line << endl; } while (!line.isNull()); } }
حال بیایید نرمافزاری بنویسیم که بتواند همانند دستور «cat» ، خودش متن پروندهای که نام و آدرسش در مقابلش نوشته شده را باز کند و در خروجی نمایش دهد. برای اینکار باید از پارامترهایی که در برنامه هستند استفاده کنیم. ابتدا پوشهای با نام دلخواه ایجاد کنید، سپس در داخل آن پروندهای با نام «kat.cpp» یا هرچه که دوست دارید ساخته و در آن کدهای زیر را وارد کنید. (بهتر است نام پوشه را نیز kat بگزارید)
#include <QTextStream> #include <QFile> int main(int argc, const char* argv[]) { QFile data(argv[1]); QString line; if (data.open(QFile::ReadOnly)) { QTextStream in(&data); QTextStream out(stdout); out.setCodec("UTF-8"); in.setCodec("UTF-8"); do { line = in.readLine(); out << line << endl; } while (!line.isNull()); } }
در دستورات بالا از از پارامترهای داخل تابع اصلی برای شناسایی مقادیری که بعد از نام دستور میآید استفاده کردهایم. argc در اینجا تعداد عبارات نوشته شده بعد از برنامه را مشخص میکند و argv آرایهای است که مقادیر را نگاه می دارد. خانهٔ شمارهٔ ۰ این آرایه را نام نرمافزار و مابقی را عبارات و پارامترها پر میکنند. ما در این جا به یک عبارت نیاز داریم و فقط از شمارهٔ یک استفاده کردهام.
int main(int argc, const char* argv[])
حال با استفاده از دستورات زیر نرمافزار را کامپایل کنید، وارد پوشهٔ پروژه شده و داخل آن دستورات زیر را برای ساخت پروندههای مورد نیاز برای پروژه وارد کنید. سپس با استفاده از دستور make آن را کامپایل خواهیم کرد.
qmake -project qmake make
حال که نرمافزار کامپایل شده است اگر نام پوشه شما هر چه باشد، مثلا kat نام پروندهٔ اجرایی نیز به همین نام خواهد بود. آن را با دستور زیر به این شکل اجرا کنید، محتویات پروندهٔ تنظیمات پروژه را نمایش خواهد داد.
ehsan@ETARCH ~/kat % ./kat kat.pro ###################################################################### # Automatically generated by qmake (3.0) Sat Sep 19 18:17:43 2015 ###################################################################### TEMPLATE = app TARGET = kat INCLUDEPATH += . # Input SOURCES += kat.cpp
اگر این کد را نوشتهاید، توانستهاید یکی از دتورات گنو/لینوکس را تنها با ۲۲ خط دستور سی++ و کیوت بنویسید. در داخل نرمافزاری که مینویسیم نیز از چنین قابلیتی استفاده خواهیم کرد تا در هنگام نوشتن عبارتی بعد از نام برنامه، بتوانیم آن را بگشاییم.
نوشتن کدهای برنامه
ابتدا، پروژه را باید با استفاده از دستور زیر از پایگاه اینترنتی گیتهاب دریافت کنید، سپس با استفاده از محیط توسعه کیوت، آن را بگشاید. برای گشودن آن پرونده تنظیمات سی-میک را باید انتخاب کنید.
ehsan@ETARCH ~ % git clone https://github.com/journalehsan/CutePad.git
حال که پروژهٔ کیوتپد بارگیری شده است و برای استفاده آماده است آن را میگشاییم. بعد از گشودن آن مجددا در سمت چپ فهرستی از پروندههای مورد نظر که به صورت جداگانه در پوشههای سرآیند و منبع قرار دارند را مشاهده میکنید. برخی از تغییرات را داخل کلاس «Actions» انجام میدهیم. ابتدا پروندهٔ سرآیند آن را باز کنید و در آن دستورات زیر را جایگزین دستورات قبلی کنید.
#ifndef ACTIONS_H #define ACTIONS_H #include <QtCore/QString> #include <QTextStream> #include <QFile> class Actions{ friend class MainWin; public: QString actionOenFile(QString strFileName,QString strFileCodec = "UTF-8"); bool actionSaveFile(QString strFileName,QString strFileCodec = "UTF-8"); Actions(); ~Actions(); private: QString globalFileName; }; #endif //ACTIONS_H
سپس باید در داخل، پروندهٔ منبع کلاس «Actions»، توابعی را که مشخص کردهایم را تعریف کنیم، برای تعریف آن پروندهٔ منبع را باز کنید و در آن کدها و دستورات زیر را وارد کنید. در این مرحله فعلاً کد مربوط به گشودن و پروندهٔ جدید را مینویسیم.
#include "actions.h" #include "main_win.h" #include <QObject> #include <QTextStream> #include <QFile> #include <QFileDialog> QString Actions::actionOenFile(QString strFileName, const char strFileCodec[]) { qDebug("Open Action Called!"); //define qfile QFile flOpenedFileName(strFileName); //check read only if (!flOpenedFileName.open(QIODevice::ReadOnly | QIODevice::Text)){ qDebug("Read Only"); } //Open from text stream QTextStream txtStreamOpen(&flOpenedFileName); txtStreamOpen.setCodec(strFileCodec); QString fileData = txtStreamOpen.readAll(); //flush flOpenedFileName.flush(); flOpenedFileName.close(); return fileData; } bool Actions::actionSaveFile(QString strFileName, QString strFileCodec) { qDebug("Save Action Called!"); } Actions::Actions(){ qDebug("Actions started!"); } Actions::~Actions(){ qDebug("Actions gone!"); }
کدها و خطوط زیر را نیز در داخل پروندهٔ منبع پنجره اصلی یعنی پروندهٔ «main_win.cpp» بنویسید. در اینجا کدهایی را برای فراخوانی تابع بالا لازم است را مینویسیم. کدهای زیر از کدهای جلسهٔ قبلی نیز تشکیل شده است، در ادامهٔ نوشته کدهای جدید را بیشتر توضیح خواهم داد.
#include "main_win.h" //Define Actions ad a instance Actions *actionsInstance; //Global Variables QString strFileName; //for title anme QString urlGlobalFilePath; // MainWin::MainWin(QMainWindow *parent) : QMainWindow(parent){ //setup windows widget this->setWindowTitle(qApp->applicationName()); this->setWindowIcon(QIcon::fromTheme("accessories-text-editor")); this->setMinimumSize(820,650); //setup main and actions //File menu MainMenu *menuFile; menuFile = new MainMenu(this); menuFile->setTitle("File"); this->menuBar()->addMenu(menuFile); //new action actionNewFile = new QAction(this); actionNewFile->setText("&New"); actionNewFile->setIcon(QIcon::fromTheme("document-new")); menuFile->addAction(actionNewFile); //open action actionOpenFile = new QAction(this); actionOpenFile->setText("&Open"); actionOpenFile->setIcon(QIcon::fromTheme("document-open")); menuFile->addAction(actionOpenFile); //save action actionSaveFile = new QAction(this); actionSaveFile->setText("&Save"); actionSaveFile->setIcon(QIcon::fromTheme("document-save")); menuFile->addAction(actionSaveFile); //Text Editor for plain text plainTextEditor = new QPlainTextEdit(this); //tabs this->setDocumentMode(true); //centeral widget this->setCentralWidget(plainTextEditor); //Toolbar & Actions mainToolBar = new QToolBar(this); mainToolBar->addAction(actionNewFile); mainToolBar->addAction(actionOpenFile); mainToolBar->addAction(actionSaveFile); this->addToolBar(mainToolBar); //Tabs this->setDocumentMode(true); //connect actions to Actios Class's Functions QObject::connect(actionNewFile, SIGNAL(triggered(bool)), this, SLOT(slotNewFile())); QObject::connect(actionOpenFile, SIGNAL(triggered(bool)), this, SLOT(slotOpenFile())); QObject::connect(actionSaveFile, SIGNAL(triggered(bool)), this, SLOT(slotSaveFile())); } MainWin::~MainWin() { } void MainWin::slotNewFile() { //exec new option plainTextEditor->setPlainText(""); } void MainWin::slotOpenFile() { //exec open fuction actionsInstance = new Actions; //action define qDebug("Openning File....."); QString urlHomePath = QDir::homePath(); //Home Folder //Open File Dialog QString filePath; filePath = QFileDialog::getOpenFileName(this,"Open Text File:",urlHomePath,"TXT Files(*.txt);;All Files(*.*)"); //call open action if (filePath !="" || QFile::exists(filePath) ){ QString strPlainData = actionsInstance->actionOenFile(filePath,"utf-8"); plainTextEditor->setPlainText(strPlainData); //change title QFileInfo fileInfo(filePath); QString fileName(fileInfo.fileName()); this->setWindowTitle(fileName); strFileName = fileName; } else{ //cancel open file qDebug("Open File Canceled!"); this->setWindowTitle("CutePad"); } } void MainWin::slotSaveFile() { //exec save function actionsInstance = new Actions; //define variables if (actionsInstance->actionSaveFile("strSFileName","strSFileCodec")){ qDebug("File Saved!"); } }
پروندهٔ سرآیند کلاس پنجرهٔ اصلی را نیز با مقادیر زیر مجدداً پر کنید و مقادیر قبلی را پاک کنید، یعنی مقادیر زیر را جایگزین مقادیر قبلی کنید. در این پرونده برخی تغییرات کوچک اعمال شده و یا برخی ایرادها و موارد اضافی که وجود داشت از کدهای فعلی نسبت به کدهای قبلی حذف و رفع شدهاند.
#ifndef MAIN_WIN_H #define MAIN_WIN_H #include <QtWidgets/QtWidgets> #include <QtCore/QDebug> #include <QtGui/QIcon> #include <QtCore/QObject> #include "actions.h" #include "main_menu.h" class MainWin : public QMainWindow { Q_OBJECT public: MainWin(QMainWindow *parent = 0); ~MainWin(); private: //TextBox QPlainTextEdit *plainTextEditor; //Layouts & Toolbar QToolBar *mainToolBar; //Actions QAction *actionOpenFile; QAction *actionNewFile; QAction *actionSaveFile; QAction *actionQuitApp; QAction *actionCloseFile; private slots: void slotNewFile(); void slotOpenFile(); void slotSaveFile(); }; #endif //MAIN_WIN_H
حال برای عمل ایجاد پروندهٔ جدید کدها آماده است، کدهایی که برای ایجاد پنجرهٔ جدید برای این گزینه نوشته شدهاند، کدهای زیر هستند. در این کد ما یک تابع تعریف کردهایم و آن را در قسمت «private_slot» قرار دادیم. اگر تعریف تابع در داخل این قسمت نباشد، دستور «connect» با خطا مواجه میشود. همواره هر تابع اسلات «Slot» را در آن بخش از سرآیند تعریف کنید.
void MainWin::slotNewFile() { //exec new option plainTextEditor->setPlainText(""); }
همانطور که مشاهده میکنید کدی که در بالا برای ایجاد پنجرهٔ جدید نوشتهایم، خیلی ابتدایی است و تنها متنی که داخل کادر متنی قرار دارد را پاک میکند، با این وجود به همین کد در این جلسه کفایت میکنیم و در قسمتهای آینده آن را توسعه خواهیم داد. امّا کدی که برای دکمهٔ گشودن نوشتهایم را تقریبا کامل کردهایم. این کد در دو بخش نوشته شده است. ابتدا کادر گشودن پرونده و دیگر تنظیمات مورد نیاز را در یک تابع نوشته و در تابع دیگر فرآیند گشودن پرونده و متن پرونده را به صورت کامل نوشتهایم. کد تابع اول که برای رویداد کلیک گزینهٔ گشودن در نوار ابزار است، شامل کدهای زیر میشود. در این قسمت کدک پرونده را «utf-8» قرار میدهیم که توسط متغیری که آِن را در تابع به عنوان پارامتر تعریف کردهایم، تنظیم خواهد شد.
QString strPlainData = actionsInstance->actionOenFile(filePath,"utf-8");
با این وجود اگر تابع را به صورت دیگری فراخوانی کنیم، کُدک «Encoding» پرونده تغییر خواهد یافت که البته در این قسمت نیاز به تغییر کد نداریم و فقط هنگام فراخوانی تابع باید، متن «utf-8» را به متن دیگری تغییر دهیم.
void MainWin::slotOpenFile() { //exec open fuction actionsInstance = new Actions; //action define qDebug("Openning File....."); QString urlHomePath = QDir::homePath(); //Home Folder //Open File Dialog QString filePath; filePath = QFileDialog::getOpenFileName(this,"Open Text File:",urlHomePath,"TXT Files(*.txt);;All Files(*.*)"); //call open action if (filePath !="" || QFile::exists(filePath) ){ QString strPlainData = actionsInstance->actionOenFile(filePath,"utf-8"); plainTextEditor->setPlainText(strPlainData); //change title QFileInfo fileInfo(filePath); QString fileName(fileInfo.fileName()); this->setWindowTitle(fileName); strFileName = fileName; } else{ //cancel open file qDebug("Open File Canceled!"); this->setWindowTitle("CutePad"); } }
در این کد ما از کلاس «QFileDialog» استفاده کرده و با آن توانستیم بفهمیم که شاخه خانگی کاربر جاری چه شاخهای است. سپس آن را به شاخهٔ پیشفرض کلاس «QFileDialog» نسبت دادیم تا برای اولین بار در همان شاخه گشوده شود. قسمتی را برای مشخص کردن اینکه پرونده فقط خواندنی است یا نه مشخص کردهایم، در صورت فقط خواندنی بودن پرونده گشوده شده، قابلیت ذخیره را غیر فعال خواهیم کرد که فعلاً به یک پیام ساده توسط «qDebug» بسنده کردهایم. در داخل کلاس «QFiileDialog» همانطور که مشخص است، تابع اجرای کادری را که برای گشودن پرونده است نوشته و در آن نوع قالبها مشخص شدهاند. در آخر گفتیم اگر آدرس پرونده با مقدار رشتهٔ تهی”” مساوی نبود و پرونده نیز وجود داشت، آدرس پرونده را به تابع بعدی که برای بیرون کشیدن دادهها است ارجاه داده و آن تابع را فراخوانی کند، بعد از آن خروجی تابع دوم را دریافت میکند و از طریق کادر متنی به نمایش در میآورد. کد تابع دوم نیز به شکل زیر است.
QString Actions::actionOenFile(QString strFileName, QString strFileCodec) { qDebug("Open Action Called!"); //define qfile QFile flOpenedFileName(strFileName); //check read only if (!flOpenedFileName.open(QIODevice::ReadOnly | QIODevice::Text)){ qDebug("Read Only"); } //Open from text stream QTextStream txtStreamOpen(&flOpenedFileName); QString fileData = txtStreamOpen.readAll(); //flush flOpenedFileName.flush(); flOpenedFileName.close(); return fileData; }
در این کد ما از یک تابع جدید استفاده کردهایم که «QFile» نام دارد، (توضیحات مرتبط را در ابتدای مقاله مطالعه کنید) در این کد، این تابع را تعریف کردهایم، سپس آدرسی را به آن نسبت داده تا بتواند این پرونده را بگشاییم.
QFile flOpenedFileName(strFileName);
در کد بالا روش تعریف این کلاس را مشاهده میکنید، همانطور که ملاحظه میکنید، کدی که برای نوشتن آن به کار رفته است بسیار آسان است، بعد از آن باید یک جریان متنی ایجاد کنیم، QFile را برایش تعریف کرده و از آن استفاده کنید تا بتوانید جریان متنی را از سوی پرونده به سمت یک متغیر رشتهای ایجاد کنید.
//Open from text stream QTextStream txtStreamOpen(&flOpenedFileName); QString fileData = txtStreamOpen.readAll();
در آخر نیز پرونده را بسته و همه چیز را پاک میکنیم. معمولا وقتی پروندهای گشوده میشود، فضایی از حافظه داخلی و جانبی درگیر می شوند که با این دستورات که در زیر میآید، آنان آزاد خواهند شد. در هر بار گشودن پرونده این کار را انجام دهید، در سی++ نیز پروندهها را بعد از گشودن میبندند در کیوت هم باید چنین کرد.
//flush flOpenedFileName.flush(); flOpenedFileName.close();
در آخر اطلاعات خوانده شده را در تابع به خروجی باز میگرداند، تا در صورتی که تابع فراخوانی شد به عنوان خروجی، اطلاعات داخل متن را در یک متغیر رشتهای برگرداند. به این شکل ما تابعی نوشتهایم که در آن تابع برخی کدها قرار دارد، بخش اصلی کد را به یک تابع سپردهایم که کارهایی را انجام میدهد و سپس خروجی را مجدداً به آن یکی تابع میدهد که کارش را ادامه دهد.
return fileData;
پایان جلسهٔ پنجم
تقریباً این قسمت را به دلیل اینکه مباحث مطرح شده از این سنگینتر نشود، تمام میکنم. کدهایی که در این جلسه نوشته شدهاند را نیز میتوانید از طریق گیتهاب دریافت کنید. برای بارگیری آن از طریق خط فرمان دستور زیر را در پوشههای دلخواه اجرا کنید تا پروژه مجدداً بارگیری شود، اگر پروژه را از قبل داشتید نیز مقادیر جدید را دریافت کنید. گیتهاب بهترین مکانی است که میتوانم کدها را در آن به اشتراک بگزارم به دلیل اینکه این پروژه یک پروژهٔ دنبالهدار و ادامه دار است و در هر قسمت کامل میشود، برای راحتی کار خودم و شما از گیت و گیتهاب استفاده کردهام. با این حال در هر جلسه پروندهٔ فشردهای از کدهای جلسهٔ قبل را نیز برای کسانی که کدهای جلسهٔ قبل را ندارند، قرار خواهم داد.
git clone https://github.com/journalehsan/CutePad.git
در آخر ظاهر نرمافزار به شکل زیر خواهد بود. همانطور که مشخص است از توزیع کیدیای استفاده میکنم، با این وجود اگر این کدها را در گنوم یا حتی سیستمعامل دیگری نیز اجرا کنید، نتیجهٔ مشابهی را مشاهده خواهید کرد به غیر از اینکه نقشکها و ظاهر نرمافزار شما به ظاهر سیستمعامل و میزکار خودتان نزدیکتر خواهد بود.
نرمافزار بعد از کامپایل تغییر خاصی از نظر ظاهری با جلسهٔ چهارم یا قبل نداشته است، فقط گزینههای جدید «New» و گشودن «Open» در نوار ابزار و منو میتوانند کارهایی را انجام دهند، مثلاً متونی را که در کادر متنی قرار دارند را پاک کنند یا اینکه پروندهای را با استفاده از پنجره و کادر محاورهای گشودن پرونده، باز کرده و نمایش دهد. به صورت پیشفرض فعلاً از UTF-8 استفاده میشود در آینده از یک گزینهٔ جدید استفاده میکنیم تا مشخص کنیم که همواره پروندهها در چه حالتی گشوده و نمایش داده شود. مثلاً اگر گزینهٔ عربی در ویندوز را انتخاب کنید، میتوانید برخی زیرنویسهایی که در این حالت ذخیره شدهاند را گشوده و با UTF-8 مجدداً ذخیره کنید، البته نرمافزاری جداگانه با استفاده از کیوت و کیو-میک نوشتهام، که در آیندهای نزدیک با انتقال کامل پروژه از کیو-میک به سی-میک، آموزش این پروژهرا نیز شاید در جلسهای خواهیم نوشت و نرمافزار مذکور را با هم ارتقاء خواهیم داد.
اگر پیشنهادی دارید که میتواند در جلسهٔ بعدی به کار گیریم یا اینکه برای پروژه و نرمافزار بعد از اتمام این پروژه و نرمافزار پیشنهادی دارید، پیشنهاد خود را با ما در میان بگزارید. همچنین اگر در مورد نرمافزاری که برای اندروید خواهیم نوشت نیز نظری دارید، آن را مطرح کنید تا موضوع نرمافزاری که برای اندروید مینویسیم از پیش مشخص باشد.