Development/Tutorials/Saving and loading (fa): Difference between revisions

From KDE TechBase
(Using xsd instead of dtd (not state of the art) / MenuBar tag _before_ ToolBar tag as requested by xsd)
No edit summary
 
(6 intermediate revisions by one other user not shown)
Line 1: Line 1:
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Saving_and_loading}}
 


{{TutorialBrowser (fa)|
{{TutorialBrowser (fa)|
Line 25: Line 25:
===main.cpp===
===main.cpp===
<div dir="ltr">
<div dir="ltr">
<code cppqt n>
<syntaxhighlight lang="cpp-qt" line>
#include <KApplication>
#include <KApplication>
#include <KAboutData>
#include <KAboutData>
Line 48: Line 48:
   return app.exec();
   return app.exec();
}
}
</code>
</syntaxhighlight>
</div>
</div>
‏<tt>main.cpp</tt> نسبت به آموزش قبل هیچ تغییری نکرده فقط tutorial3ها به tutorial4 تغییر داده‌شده‌اند.
‏<tt>main.cpp</tt> نسبت به آموزش قبل هیچ تغییری نکرده فقط tutorial3ها به tutorial4 تغییر داده‌شده‌اند.
Line 54: Line 54:
===mainwindow.h===
===mainwindow.h===
<div dir="ltr">
<div dir="ltr">
<code cppqt n>
<syntaxhighlight lang="cpp-qt" line>
#ifndef MAINWINDOW_H
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#define MAINWINDOW_H
Line 82: Line 82:


#endif
#endif
</code>
</syntaxhighlight>
</div>
</div>
از آنجایی که می‌خواهیم قابلیت‌های ذخیره و بازیابی فایل‌ها را به برنامه بیافزاییم، باید توابعی اضافه کنیم که این کارها را برایمان انجام دهند. چون این توابع از طریق مکانیزم [http://doc.trolltech.com/latest/signalsandslots.html signal/slot] مربوط به Qt فراخوانی می‌شوند، باید آن‌ها را به عنوان slot معرفی کنیم؛ که در سطر ۱۹ همین اتفاق می‌افتد. به علاوه، چون در این کلاس slot تعریف می‌کنیم، باید ماکروی [http://doc.trolltech.com/latest/qobject.html#Q_OBJECT <tt>Q_OBJECT</tt>] را به تعریف آن اضافه کنیم.
از آنجایی که می‌خواهیم قابلیت‌های ذخیره و بازیابی فایل‌ها را به برنامه بیافزاییم، باید توابعی اضافه کنیم که این کارها را برایمان انجام دهند. چون این توابع از طریق مکانیزم [http://doc.trolltech.com/latest/signalsandslots.html signal/slot] مربوط به Qt فراخوانی می‌شوند، باید آن‌ها را به عنوان slot معرفی کنیم؛ که در سطر ۱۹ همین اتفاق می‌افتد. به علاوه، چون در این کلاس slot تعریف می‌کنیم، باید ماکروی [http://doc.trolltech.com/latest/qobject.html#Q_OBJECT <tt>Q_OBJECT</tt>] را به تعریف آن اضافه کنیم.
Line 90: Line 90:
===mainwindow.cpp===
===mainwindow.cpp===
<div dir="ltr">
<div dir="ltr">
<code cppqt n>
<syntaxhighlight lang="cpp-qt" line>
#include "mainwindow.h"
#include "mainwindow.h"


Line 202: Line 202:
}
}
}
}
</code>
</syntaxhighlight>
</div>
</div>


===tutorial4ui.rc===
===tutorial4ui.rc===
<div dir="ltr">
<div dir="ltr">
<code xml n>
<syntaxhighlight lang="xml" line>
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<gui name="tutorial4"
<gui name="tutorial4"
Line 228: Line 228:


</gui>
</gui>
</code>
</syntaxhighlight>
</div>
</div>
این فایل هم دقیقا مشابه <tt>tutorial3ui.rc</tt> از آموزش ۳ است. تنها نام آن را به tutorial4 تغییر داده‌ایم. نیازی به هیچ‌گونه اطلاعات اضافی از <tt>KStandardAction</tt>ها در این فایل نیست. جای هر یک از گزینه‌ها در منوها را به طور خودکار KDE تنظیم می‌کند.
این فایل هم دقیقا مشابه <tt>tutorial3ui.rc</tt> از آموزش ۳ است. تنها نام آن را به tutorial4 تغییر داده‌ایم. نیازی به هیچ‌گونه اطلاعات اضافی از <tt>KStandardAction</tt>ها در این فایل نیست. جای هر یک از گزینه‌ها در منوها را به طور خودکار KDE تنظیم می‌کند.
Line 237: Line 237:
نخستین کاری که انجام می‌دهیم، اضافه‌کردن
نخستین کاری که انجام می‌دهیم، اضافه‌کردن
<div dir="ltr">
<div dir="ltr">
<code cppqt>
<syntaxhighlight lang="cpp-qt">
fileName(QString())
fileName(QString())
</code>
</syntaxhighlight>
</div>
</div>
به تعریف تابع سازنده‌ی <tt>MainWindow</tt> در سطر ۱۶ است. با این کار، اطمینان حاصل می‌کنیم که <tt>fileName</tt> از همان ابتدا تهی است.
به تعریف تابع سازنده‌ی <tt>MainWindow</tt> در سطر ۱۶ است. با این کار، اطمینان حاصل می‌کنیم که <tt>fileName</tt> از همان ابتدا تهی است.
Line 250: Line 250:
اولین تابعی که می‌نویسیم، تابع <tt>newFile()</tt> است.
اولین تابعی که می‌نویسیم، تابع <tt>newFile()</tt> است.
<div dir="ltr">
<div dir="ltr">
<code cppqt>
<syntaxhighlight lang="cpp-qt">
void MainWindow::newFile()
void MainWindow::newFile()
{
{
Line 256: Line 256:
   textArea->clear();
   textArea->clear();
}
}
</code>
</syntaxhighlight>
</div>
</div>
‏<tt>fileName.clear()</tt> مقدار متغیر <tt>fileName</tt> را تهی قرار می‌دهد. این کار، نمودی از این حقیقت است که فایل هنوز بر روی دیسک وجود ندارد. آن‌گاه <tt>textArea->clear()</tt> کادر متنی وسط پنجره را خالی می‌کند. این همان تابعی است که به clearAction در آموزش ۳ پیوند زدیم.
‏<tt>fileName.clear()</tt> مقدار متغیر <tt>fileName</tt> را تهی قرار می‌دهد. این کار، نمودی از این حقیقت است که فایل هنوز بر روی دیسک وجود ندارد. آن‌گاه <tt>textArea->clear()</tt> کادر متنی وسط پنجره را خالی می‌کند. این همان تابعی است که به clearAction در آموزش ۳ پیوند زدیم.
Line 268: Line 268:
اعلان تابع به این صورت است:
اعلان تابع به این صورت است:
<div dir="ltr">
<div dir="ltr">
<code cppqt>
<syntaxhighlight lang="cpp-qt">
void MainWindow::saveFileAs(const QString &outputFileName)
void MainWindow::saveFileAs(const QString &outputFileName)
</code>
</syntaxhighlight>
</div>
</div>


سپس شیء <tt>KSaveFile</tt> خود را می‌سازیم و باز می‌کنیم:
سپس شیء <tt>KSaveFile</tt> خود را می‌سازیم و باز می‌کنیم:
<div dir="ltr">
<div dir="ltr">
<code cppqt>
<syntaxhighlight lang="cpp-qt">
KSaveFile file(outputFileName);
KSaveFile file(outputFileName);
file.open();
file.open();
</code>
</syntaxhighlight>
</div>
</div>


حالا که فایلمان باز شده و آماده‌ی نوشتن است، باید نوشته‌های درون کادر متنی را به قالبی درآوریم که بتوان آن را در فایل نوشت. برای این کار، یک {{qt|QByteArray}} می‌سازیم و آن را با متن ساده‌ی درون کادر متن پر می‌کنیم:
حالا که فایلمان باز شده و آماده‌ی نوشتن است، باید نوشته‌های درون کادر متنی را به قالبی درآوریم که بتوان آن را در فایل نوشت. برای این کار، یک {{qt|QByteArray}} می‌سازیم و آن را با متن ساده‌ی درون کادر متن پر می‌کنیم:
<div dir="ltr">
<div dir="ltr">
<code cppqt>
<syntaxhighlight lang="cpp-qt">
QByteArray outputByteArray;
QByteArray outputByteArray;
outputByteArray.append(textArea->toPlainText().toUtf8());
outputByteArray.append(textArea->toPlainText().toUtf8());
</code>
</syntaxhighlight>
</div>
</div>
حالا با استفاده از تابع <tt>KSaveFile::write()</tt>، آرایه‌ی ساخته شده را در فایل می‌نویسیم. اگر از یک <tt>QFile</tt> استفاده می‌کردیم، تغییرات بلافاصله در فایل ذخیره می‌شدند. با این کار، اگر در میانه‌ی نوشتن مشکلی پیش بیاید، فایل خراب می‌شود. به همین دلیل، <tt>KSaveFile</tt> ابتدا در یک فایل موقتی می‌نویسد و سپس هنگامی که <tt>KSaveFile::finalize()</tt> را صدا می‌زنید، تغییرات در فایل واقعی اعمال می‌شوند.
حالا با استفاده از تابع <tt>KSaveFile::write()</tt>، آرایه‌ی ساخته شده را در فایل می‌نویسیم. اگر از یک <tt>QFile</tt> استفاده می‌کردیم، تغییرات بلافاصله در فایل ذخیره می‌شدند. با این کار، اگر در میانه‌ی نوشتن مشکلی پیش بیاید، فایل خراب می‌شود. به همین دلیل، <tt>KSaveFile</tt> ابتدا در یک فایل موقتی می‌نویسد و سپس هنگامی که <tt>KSaveFile::finalize()</tt> را صدا می‌زنید، تغییرات در فایل واقعی اعمال می‌شوند.
<div dir="ltr">
<div dir="ltr">
<code cppqt>
<syntaxhighlight lang="cpp-qt">
file.write(outputByteArray);
file.write(outputByteArray);
file.finalize();
file.finalize();
file.close();
file.close();
</code>
</syntaxhighlight>
</div>
</div>
در پایان، مقدار عضو داده‌ی <tt>fileName</tt> در کلاس <tt>MainWindow</tt> را به نام فایلی که نوشته‌ها را در آن ذخیره کردیم، تغییر می‌دهیم.
در پایان، مقدار عضو داده‌ی <tt>fileName</tt> در کلاس <tt>MainWindow</tt> را به نام فایلی که نوشته‌ها را در آن ذخیره کردیم، تغییر می‌دهیم.
<div dir="ltr">
<div dir="ltr">
<code cppqt>
<syntaxhighlight lang="cpp-qt">
fileName = outputFileName;
fileName = outputFileName;
</code>
</syntaxhighlight>
</div>
</div>


Line 308: Line 308:


<div dir="ltr">
<div dir="ltr">
<code cppqt>
<syntaxhighlight lang="cpp-qt">
void MainWindow::saveFileAs()
void MainWindow::saveFileAs()
{
{
   saveFileAs(KFileDialog::getSaveFileName());
   saveFileAs(KFileDialog::getSaveFileName());
}
}
</code>
</syntaxhighlight>
</div>
</div>


Line 321: Line 321:


<div dir="ltr">
<div dir="ltr">
<code cppqt>
<syntaxhighlight lang="cpp-qt">
void MainWindow::saveFile()
void MainWindow::saveFile()
{
{
Line 333: Line 333:
   }
   }
}
}
</code>
</syntaxhighlight>
</div>
</div>


Line 344: Line 344:
اول باید از کاربر بپرسیم نام فایلی که می‌خواهد باز کند چیست. این کار را با استفاده از تابع دیگری از <tt>KFileDialog</tt> انجام می‌دهیم؛ این بار <tt>getOpenFileName()</tt>:
اول باید از کاربر بپرسیم نام فایلی که می‌خواهد باز کند چیست. این کار را با استفاده از تابع دیگری از <tt>KFileDialog</tt> انجام می‌دهیم؛ این بار <tt>getOpenFileName()</tt>:
<div dir="ltr">
<div dir="ltr">
<code cppqt>
<syntaxhighlight lang="cpp-qt">
QString fileNameFromDialog = KFileDialog::getOpenFileName();
QString fileNameFromDialog = KFileDialog::getOpenFileName();
</code>
</syntaxhighlight>
</div>
</div>


حالا از کتاب‌خانه‌ی KIO استفاده می‌کنیم تا فایل را دریافت کنیم. KIO به ما امکان می‌دهد فایل را به صورت یک QFile دریافت کنیم؛ حتی اگر فایل در یک ارتباط راه دور مانند یک FTP قرار داشته باشد. تابع <tt>download</tt> از {{class|NetAccess}} را به صورت زیر فرا می‌خوانیم:
حالا از کتاب‌خانه‌ی KIO استفاده می‌کنیم تا فایل را دریافت کنیم. KIO به ما امکان می‌دهد فایل را به صورت یک QFile دریافت کنیم؛ حتی اگر فایل در یک ارتباط راه دور مانند یک FTP قرار داشته باشد. تابع <tt>download</tt> از {{class|NetAccess}} را به صورت زیر فرا می‌خوانیم:
<div dir="ltr">
<div dir="ltr">
<code cppqt>
<syntaxhighlight lang="cpp-qt">
KIO::NetAccess::download(fileNameFromDialog, tmpFile, this)
KIO::NetAccess::download(fileNameFromDialog, tmpFile, this)
</code>
</syntaxhighlight>
</div>
</div>
اولین آرگومان، نام فایلی است که می‌خواهیم دریافت کنیم. دومی یک متغیر QString است که پس پایان دریافت، مکان کپی موقت فایل را در خود خواهد داشت. از این به بعد با همین <tt>tmpFile</tt> سر و کار خواهیم داشت.
اولین آرگومان، نام فایلی است که می‌خواهیم دریافت کنیم. دومی یک متغیر QString است که پس پایان دریافت، مکان کپی موقت فایل را در خود خواهد داشت. از این به بعد با همین <tt>tmpFile</tt> سر و کار خواهیم داشت.
Line 359: Line 359:
خروجی تابع، بسته به موفقیت آمیز بودن یا نبودن عملیات، <tt>true</tt> یا <tt>false</tt> خواهد بود. اگر عملیات با شکست مواجه شد، پیامی حاوی خطای رخ داده نمایش می‌دهیم:
خروجی تابع، بسته به موفقیت آمیز بودن یا نبودن عملیات، <tt>true</tt> یا <tt>false</tt> خواهد بود. اگر عملیات با شکست مواجه شد، پیامی حاوی خطای رخ داده نمایش می‌دهیم:
<div dir="ltr">
<div dir="ltr">
<code cppqt>
<syntaxhighlight lang="cpp-qt">
KMessageBox::error(this, KIO::NetAccess::lastErrorString());
KMessageBox::error(this, KIO::NetAccess::lastErrorString());
</code>
</syntaxhighlight>
</div>
</div>


Line 368: Line 368:
یک QFile می‌سازیم و فایل موقتی که <tt>NetAccess::download()</tt> ساخته را به تابع سازنده‌اش رد می‌کنیم. هم‌چنین مشخص می‌کنیم که فایل به صورت «فقط خواندنی» باز شود.
یک QFile می‌سازیم و فایل موقتی که <tt>NetAccess::download()</tt> ساخته را به تابع سازنده‌اش رد می‌کنیم. هم‌چنین مشخص می‌کنیم که فایل به صورت «فقط خواندنی» باز شود.
<div dir="ltr">
<div dir="ltr">
<code cppqt>
<syntaxhighlight lang="cpp-qt">
QFile file(tmpFile);
QFile file(tmpFile);
file.open(QIODevice::ReadOnly);
file.open(QIODevice::ReadOnly);
</code>
</syntaxhighlight>
</div>
</div>


Line 377: Line 377:


<div dir="ltr">
<div dir="ltr">
<code cppqt>
<syntaxhighlight lang="cpp-qt">
textArea->setPlainText(QTextStream(&file).readAll());
textArea->setPlainText(QTextStream(&file).readAll());
</code>
</syntaxhighlight>
</div>
</div>


سپس مسیر فایل بازشده را در <tt>fileName</tt> نگه‌داری می‌کنیم:
سپس مسیر فایل بازشده را در <tt>fileName</tt> نگه‌داری می‌کنیم:
<div dir="ltr">
<div dir="ltr">
<code cppqt>
<syntaxhighlight lang="cpp-qt">
fileName = fileNameFromDialog;
fileName = fileNameFromDialog;
</code>
</syntaxhighlight>
</div>
</div>


و نهایتا فایل موقتی که <tt>NetAccess::download()</tt> ساخته است را پاک می‌کنیم:
و نهایتا فایل موقتی که <tt>NetAccess::download()</tt> ساخته است را پاک می‌کنیم:
<div dir="ltr">
<div dir="ltr">
<code cppqt>
<syntaxhighlight lang="cpp-qt">
KIO::NetAccess::removeTempFile(tmpFile);
KIO::NetAccess::removeTempFile(tmpFile);
</code>
</syntaxhighlight>
</div>
</div>


Line 400: Line 400:
===CMakeLists.txt===
===CMakeLists.txt===
<div dir="ltr">
<div dir="ltr">
<code ini n>
<syntaxhighlight lang="ini" line>
project(tutorial4)
project(tutorial4)
   
   
Line 419: Line 419:
install(FILES tutorial4ui.rc  
install(FILES tutorial4ui.rc  
         DESTINATION ${DATA_INSTALL_DIR}/tutorial4)
         DESTINATION ${DATA_INSTALL_DIR}/tutorial4)
</code>
</syntaxhighlight>
</div>
</div>


Line 427: Line 427:


<div dir="ltr">
<div dir="ltr">
<code>
<syntaxhighlight lang="text">
  mkdir build && cd build
  mkdir build && cd build
  cmake .. -DCMAKE_INSTALL_PREFIX=$HOME
  cmake .. -DCMAKE_INSTALL_PREFIX=$HOME
  make install
  make install
  $HOME/bin/tutorial4
  $HOME/bin/tutorial4
</code>
</syntaxhighlight>
</div>
</div>



Latest revision as of 15:46, 15 July 2012


ذخیره و بازیابی
سری آموزشی   آموزش مقدماتی
پیش‌نیازها   آموزش ۳ - KActionها
پس از این   آموزش ۵ - استفاده از KCmdLineArgs
مطالعه‌ی بیشتر   KIO::NetAccess QFile

چکیده

حالا یک ویرایشگر متن ساده داریم، ولی هنوز کار به‌دردبخوری انجام نمی‌دهد. یک ویرایشگر متن باید حداقل بتواند فایل‌ها را از دیسک بخواند، فایل‌هایی که شما ساخته یا ویراسته‌اید را ذخیره کند و همین‌طور فایل جدید بسازد.

‏KDE برای کار با فایل‌ها کلاس‌هایی دارد که کار را برای برنامه‌نویسان بسیار آسان می‌سازد. کتاب‌خانه‌ی KIO به شما امکان می‌دهد به سادگی به فایل‌ها دسترسی پیدا کنید. هم‌چنین با کمک KIO می‌توانید از کادرهای استاندارد بازکردن و ذخیره‌سازی فایل‌ها در برنامه‌تان استفاده کنید.

کدهای منبع

main.cpp

#include <KApplication>
#include <KAboutData>
#include <KCmdLineArgs>

#include "mainwindow.h"

int main (int argc, char *argv[])
{
  KAboutData aboutData( "tutorial4", "tutorial4",
        ki18n("Tutorial 4"), "1.0",
        ki18n("A simple text area which can load and save."),
        KAboutData::License_GPL,
        ki18n("Copyright (c) 2007 Developer") );
  KCmdLineArgs::init( argc, argv, &aboutData );
  KApplication app;

  MainWindow* window = new MainWindow();

  window->show();

  return app.exec();
}

main.cpp نسبت به آموزش قبل هیچ تغییری نکرده فقط tutorial3ها به tutorial4 تغییر داده‌شده‌اند.

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <KXmlGuiWindow>
#include <KTextEdit>

class MainWindow : public KXmlGuiWindow
  Q_OBJECT

{
  public:
    MainWindow(QWidget *parent=0);

  private:
    KTextEdit* textArea;
    void setupActions();
	QString fileName; //new

  private slots:
	void newFile(); //new
	void openFile(); //new
	void saveFile(); //new
	void saveFileAs(); //new
	void saveFileAs(const QString &outputFileName); //new
};

#endif

از آنجایی که می‌خواهیم قابلیت‌های ذخیره و بازیابی فایل‌ها را به برنامه بیافزاییم، باید توابعی اضافه کنیم که این کارها را برایمان انجام دهند. چون این توابع از طریق مکانیزم signal/slot مربوط به Qt فراخوانی می‌شوند، باید آن‌ها را به عنوان slot معرفی کنیم؛ که در سطر ۱۹ همین اتفاق می‌افتد. به علاوه، چون در این کلاس slot تعریف می‌کنیم، باید ماکروی Q_OBJECT را به تعریف آن اضافه کنیم.

هم‌چنین در طول برنامه، باید نام فایلی که کاربر باز کرده‌است را بدانیم؛ بنابراین متغیر {qt|QString} fileName را اعلان می‌کنیم.

mainwindow.cpp

#include "mainwindow.h"

#include <KApplication>
#include <KAction>
#include <KLocale>
#include <KActionCollection>
#include <KStandardAction>
#include <KFileDialog> //new
#include <KMessageBox> //new
#include <KIO/NetAccess> //new
#include <KSaveFile> //new
#include <QTextStream> //new

MainWindow::MainWindow(QWidget *parent)
  : KXmlGuiWindow(parent),
	fileName(QString()) //new
{
  textArea = new KTextEdit;
  setCentralWidget(textArea);

  setupActions();
}

void MainWindow::setupActions()
{
  KAction* clearAction = new KAction(this);
  clearAction->setText(i18n("Clear"));
  clearAction->setIcon(KIcon("document-new"));
  clearAction->setShortcut(Qt::CTRL + Qt::Key_W);
  actionCollection()->addAction("clear", clearAction);
  connect(clearAction, SIGNAL(triggered(bool)),
          textArea, SLOT(clear()));

  KStandardAction::quit(kapp, SLOT(quit()),
                        actionCollection());

  KStandardAction::open(this, SLOT(openFile()),
                        actionCollection()); //new

  KStandardAction::save(this, SLOT(saveFile()),
                        actionCollection()); //new

  KStandardAction::saveAs(this, SLOT(saveFileAs()),
						actionCollection()); //new

  KStandardAction::openNew(this, SLOT(newFile()),
						actionCollection()); //new

  setupGUI();
}

//New from here on

void MainWindow::newFile()
{
	fileName.clear();
	textArea->clear();
}

void MainWindow::saveFileAs(const QString &outputFileName)
{
	KSaveFile file(outputFileName);
	file.open();

	QByteArray outputByteArray;
	outputByteArray.append(textArea->toPlainText().toUtf8());
	file.write(outputByteArray);
	file.finalize();
	file.close();

	fileName = outputFileName;
}

void MainWindow::saveFileAs()
{
	saveFileAs(KFileDialog::getSaveFileName());
}
 
void MainWindow::saveFile()
{
	if(!fileName.isEmpty())
	{
		saveFileAs(fileName);
	}
	else
	{
		saveFileAs();
	}
}
 
void MainWindow::openFile()
{
	QString fileNameFromDialog = KFileDialog::getOpenFileName();
 
	QString tmpFile;
	if(KIO::NetAccess::download(fileNameFromDialog, tmpFile,
			this))
	{
		QFile file(tmpFile);
		file.open(QIODevice::ReadOnly);
		textArea->setPlainText(QTextStream(&file).readAll());
		fileName = fileNameFromDialog;
		 
		KIO::NetAccess::removeTempFile(tmpFile);
	}
	else
	{
		KMessageBox::error(this,
			KIO::NetAccess::lastErrorString());
	}
}

tutorial4ui.rc

<?xml version="1.0" encoding="UTF-8"?>
<gui name="tutorial4"
     version="1"
     xmlns="http://www.kde.org/standards/kxmlgui/1.0"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://www.kde.org/standards/kxmlgui/1.0
                         http://www.kde.org/standards/kxmlgui/1.0/kxmlgui.xsd" >

  <MenuBar>
    <Menu name="file" >
      <Action name="clear" />
    </Menu>
  </MenuBar>

  <ToolBar name="mainToolBar" >
    <text>Main Toolbar</text>
    <Action name="clear" />
  </ToolBar>

</gui>

این فایل هم دقیقا مشابه tutorial3ui.rc از آموزش ۳ است. تنها نام آن را به tutorial4 تغییر داده‌ایم. نیازی به هیچ‌گونه اطلاعات اضافی از KStandardActionها در این فایل نیست. جای هر یک از گزینه‌ها در منوها را به طور خودکار KDE تنظیم می‌کند.

شرح

خوب. پس می‌خواهیم برنامه‌ای بنویسم که ذخیره و بازیابی انجام دهد. این کار در mainwindow.cpp اتفاق می‌افتد.

نخستین کاری که انجام می‌دهیم، اضافه‌کردن

fileName(QString())

به تعریف تابع سازنده‌ی MainWindow در سطر ۱۶ است. با این کار، اطمینان حاصل می‌کنیم که fileName از همان ابتدا تهی است.

افزودن actionها

در اینجا، ارائه‌ی یک رابط بیرونی به کاربران برنامه، اولین کاری خواهد بود که می‌خواهیم انجام دهیم. رابط کاربر برنامه به کاربران اجازه می‌دهد به برنامه بگویند فایل را باز کن، ذخیره کن یا فایل جدیدی بساز. به مانند گزینه‌ی quit در آموزش ۳، از KStandardActionها استفاده می‌کنیم. در طول سطرهای ۳۷ تا ۴۷ actionهای جدید را به منو اضافه می‌کنیم و هر کدام را به slot مناسبی که در فایل سرایند تعریف کرده‌ایم، پیوند می‌دهیم.

ساختن یک فایل جدید

اولین تابعی که می‌نویسیم، تابع newFile() است.

void MainWindow::newFile()
{
  fileName.clear();
  textArea->clear();
}

fileName.clear() مقدار متغیر fileName را تهی قرار می‌دهد. این کار، نمودی از این حقیقت است که فایل هنوز بر روی دیسک وجود ندارد. آن‌گاه textArea->clear() کادر متنی وسط پنجره را خالی می‌کند. این همان تابعی است که به clearAction در آموزش ۳ پیوند زدیم.

ذخیره‌کردن یک فایل

saveFileAs(QString)

حالا می‌خواهیم اولین کدی که با فایل‌ها سر و کار دارد، بنویسیم. می‌خواهیم تابعی پیاده‌سازی کنیم که نوشته‌های درون کادر متن را در یک فایل، با نامی که به عنوان پارامتر رد می‌کنیم، ذخیره کند. KDE کلاسی در اختیار ما می‌گذارد که به کمک آن بتوانیم با اطمینان فایلی را ذخیره کنیم. این کلاس KSaveFile نام دارد و از کلاس QFile متعلق به Qt مشتق شده است.

اعلان تابع به این صورت است:

void MainWindow::saveFileAs(const QString &outputFileName)

سپس شیء KSaveFile خود را می‌سازیم و باز می‌کنیم:

KSaveFile file(outputFileName);
file.open();

حالا که فایلمان باز شده و آماده‌ی نوشتن است، باید نوشته‌های درون کادر متنی را به قالبی درآوریم که بتوان آن را در فایل نوشت. برای این کار، یک QByteArray می‌سازیم و آن را با متن ساده‌ی درون کادر متن پر می‌کنیم:

QByteArray outputByteArray;
outputByteArray.append(textArea->toPlainText().toUtf8());

حالا با استفاده از تابع KSaveFile::write()، آرایه‌ی ساخته شده را در فایل می‌نویسیم. اگر از یک QFile استفاده می‌کردیم، تغییرات بلافاصله در فایل ذخیره می‌شدند. با این کار، اگر در میانه‌ی نوشتن مشکلی پیش بیاید، فایل خراب می‌شود. به همین دلیل، KSaveFile ابتدا در یک فایل موقتی می‌نویسد و سپس هنگامی که KSaveFile::finalize() را صدا می‌زنید، تغییرات در فایل واقعی اعمال می‌شوند.

file.write(outputByteArray);
file.finalize();
file.close();

در پایان، مقدار عضو داده‌ی fileName در کلاس MainWindow را به نام فایلی که نوشته‌ها را در آن ذخیره کردیم، تغییر می‌دهیم.

fileName = outputFileName;

saveFileAs()

این تابعی است که اسلات saveAs به آن پیوند خورده‌است. این تابع تنها تابع عمومی saveFileAs(QString) را با مقدار برگشتی تابع KFileDialog::getSaveFileName() به عنوان آرگومان فرا می‌خواند.

void MainWindow::saveFileAs()
{
  saveFileAs(KFileDialog::getSaveFileName());
}

این اولین استفاده‌ی واقعی ما از کتاب‌خانه‌ی KIO است. KFileDialog تعدادی تابع استاتیک در اختیار ما می‌گذارد تا بتوانیم کادرهای محاوره‌ای عمومی فایل (یعنی همان کادرهای Open/Save File) را نمایش دهیم. با فراخوانی KFileDialog::getSaveFileName()، پنجره‌ای باز می‌شود که از آن‌جا کاربر می‌تواند برای فایل خود نامی برگزیند. تابع نام کامل فایل (همراه با مسیر ذخیره‌سازی) برمی‌گرداند. این مقدار بازگشتی، سپس، به تابع saveFileAs(QString) رد می‌شود.

saveFile()

void MainWindow::saveFile()
{
  if(!fileName.isEmpty())
  {
    saveFileAs(fileName);
  }
  else
  {
    saveFileAs();
  }
}

در این تابع چیز چندان جالب توجهی وجود ندارد؛ فقط منقطی که بر اساس آن تصمیم بگیریم پنجره‌ی ذخیره‌ی فایل را نمایش بدهیم یا نه. اگر fileName خالی نباشد، در این صورت فایل با همان نام fileName ذخیره خواهد شد. در غیر این صورت پنجره‌ی ذخیره‌ی فایل برای کاربر به نمایش در می‌آید تا بتواند نامی انتخاب کند.

بازکردن یک فایل

در پایان، باید به برنامه قابلیت بازیابی فایل‌ها بدهیم. همه‌ی کد این کار در تابع MainWindow::openFile() قرار گرفته است.

اول باید از کاربر بپرسیم نام فایلی که می‌خواهد باز کند چیست. این کار را با استفاده از تابع دیگری از KFileDialog انجام می‌دهیم؛ این بار getOpenFileName():

QString fileNameFromDialog = KFileDialog::getOpenFileName();

حالا از کتاب‌خانه‌ی KIO استفاده می‌کنیم تا فایل را دریافت کنیم. KIO به ما امکان می‌دهد فایل را به صورت یک QFile دریافت کنیم؛ حتی اگر فایل در یک ارتباط راه دور مانند یک FTP قرار داشته باشد. تابع download از NetAccess را به صورت زیر فرا می‌خوانیم:

KIO::NetAccess::download(fileNameFromDialog, tmpFile, this)

اولین آرگومان، نام فایلی است که می‌خواهیم دریافت کنیم. دومی یک متغیر QString است که پس پایان دریافت، مکان کپی موقت فایل را در خود خواهد داشت. از این به بعد با همین tmpFile سر و کار خواهیم داشت.

خروجی تابع، بسته به موفقیت آمیز بودن یا نبودن عملیات، true یا false خواهد بود. اگر عملیات با شکست مواجه شد، پیامی حاوی خطای رخ داده نمایش می‌دهیم:

KMessageBox::error(this, KIO::NetAccess::lastErrorString());

در غیر این صورت، به باز کردن فایل ادامه می‌دهیم.

یک QFile می‌سازیم و فایل موقتی که NetAccess::download() ساخته را به تابع سازنده‌اش رد می‌کنیم. هم‌چنین مشخص می‌کنیم که فایل به صورت «فقط خواندنی» باز شود.

QFile file(tmpFile);
file.open(QIODevice::ReadOnly);

برای نمایش محتویات فایل، باید از یک QTextStream استفاده کنیم. با رد کردن اشاره‌گر file به تابع سازنده‌ی QTextStream یک نمونه می‌سازیم و سپس تابع readAll() آن را فراخوانی می‌کنیم تا نوشته‌ها را از فایل بخوانیم. سپس آن را به تابع setPlainText() مربوط به کادر متنی رد می‌کنیم.

textArea->setPlainText(QTextStream(&file).readAll());

سپس مسیر فایل بازشده را در fileName نگه‌داری می‌کنیم:

fileName = fileNameFromDialog;

و نهایتا فایل موقتی که NetAccess::download() ساخته است را پاک می‌کنیم:

KIO::NetAccess::removeTempFile(tmpFile);

ساخت، نصب و اجرا

CMakeLists.txt

project(tutorial4)
 
find_package(KDE4 REQUIRED)
include_directories(${KDE4_INCLUDES})
 
set(tutorial4_SRCS 
  main.cpp
  mainwindow.cpp
)
 
kde4_add_executable(tutorial4 ${tutorial4_SRCS})
 
target_link_libraries(tutorial4 ${KDE4_KDEUI_LIBS} 
                                ${KDE4_KIO_LIBS})
 
install(TARGETS tutorial4 DESTINATION ${BIN_INSTALL_DIR})
install(FILES tutorial4ui.rc 
        DESTINATION ${DATA_INSTALL_DIR}/tutorial4)

چون حالا از کتاب‌خانه‌ی KIO استفاده می‌کنیم، باید به CMake بگوییم آن را هم با برنامه‌مان لینک کند. این کار را با رد کردن ${KDE4_KIO_LIBS} به تابع target_link_libraries() انجام می‌دهیم.

با این فایل، می‌توانید برنامه را درست مانند آموزش ۳ بسازید. برای اطلاعات بیشتر، به آموزش ۳ مراجعه کنید.

 mkdir build && cd build
 cmake .. -DCMAKE_INSTALL_PREFIX=$HOME
 make install
 $HOME/bin/tutorial4

به پیش

حالا می‌توانید به سوی آموزش KCmdLineArgs پیش بروید.