GUI الواجهة الرسومية

خطوات أساسية لبدء مشروع c++ بواجهة رسومية.

1- إنشاء مشروع واجهة رسومية “الشرح على بيئة تطوير Visual Studio 2013 , Professional”.

مشروع جديد (New Project)

مشروع جديد

 


Visual C++

C++


CRL

CLR


CRL Empty Project

Empty

 


 تسمية المشروع ثم OK

اسم المشروع

 


2- إنشاء أول نافذة : ممكن أن تتم بأكثر من طريقة ، سأكتفي بواحدة

Source File >> ثم زر الفأرة اليمين

Source File


ADD – New item

Add-New item


UI

UI


Widows Form

Widows form


 النتيجة بعد ضغط زر ADD

MyForm


3- فتح صفحة الأكواد التي يتم العمل داخلها 

النقر مرتين على النافذة يفتح ملف .h وهذه الطريقة لكل بقية المكونات الأزرار وغيرها 

نقر


الكود  يظهر بهذا الشكل ، وهذه إحدى الطرق

كود


4- إظها صندوق الأدوات لاستخدامها ، مثل الأزرار Buttons و مربع النص TextBox … الخ

View

عرض


ToolBox

صندوق الأدوات

ToolBox


5- إظهار مربع خصائص المكون  الذي يحوي اسم المكون والخط ووقت الظهور ..الخ، مثل خصائص النافذة .

 في الوضع الافتراضي يكون موجود في الزاوية اليمنى في الأسفل؛ ولكن إن لم يظهر لك :

الزر الأيمن على النافذة – خصائص 

زر أيمن

 


ستظهر على الجانب الأيمن ، قم بتثبيتها حتى تكون ظاهرة دائمًا في أسفل الركن الأيمن

خصائص

تثبيت الخصائص الخصائص ، النتيجة


6- إضافة Label والكتابة فيه .

من صندوق الأدوات ToolBox أختار Label ثم أسحبه إلى داخل النافذة .

ToolBox

Label


أذهب إلى مربع الخصائص عند خاصية Text أكتب ماتشاء وبإمكانك تغيير لون وحجم الخط ولون خلفية المربع …الخ من الخصائص .

الكتابة

Text

 

Hello World

 

تغيير حجم الخط

Font Size

 

النتيجة

Font Size Result


7- إضافة Button وبرمجته .

بنفس طريقة الـ label  نضيف الزر ، وننقر عليه مرتين لفتح صفحة الكود ، وتغيير خصائص الزر مثل اسمه الظاهر بمثل طريقة الـ label عن طريق مربع الخصائص.

Button Button2 Code of Button


سنقوم ببرمجة الزر ، بحيث عند ضغطه ينقلنا لنافذة أخرى 

*تحتاج بدايةً أن تُنشِئ نافذة جديدة بنفس طريقة النافذة الأولى .

أولًا : عمل include للنافذة الجديدة في النافذة الأولى

#include "MyForm1.h"

include Form 1 include Form 2

ثانيًا : كتابة هذا الكود داخل دالة الـ button  ، ومن مسميّات الدوال في الكود والتعليقات الموجودة بإمكانك فهم الكود .

// creat a new form of MyForm1
  MyForm1^ frm = gcnew MyForm1();
  this->Hide(); //Hide MyForm "The Start Form"
  frm->ShowDialog(); // Show MyForm1

Button Code 1 Button Code 2


8- في النافذة الأخرى سنضع 2 من الأزرار  واحد Exit يخرج من البرنامج والآخر  Restart ويعيد تشغيل البرنامج من البداية .

البداية مع Exit .

 //Exit Button
 Application::Exit();

ExitExit Button

زر إعادة التشغيل 

 //Start Again Button
 Application::Restart();

Restart

 


9- تشغيل البرنامج 

عند عمل build سيظهر لك هذا الخطأ ، سببه هو أنه يجب أن تعيّن Main Form وهي تقابل Main Function نقطة بداية البرنامج .

Error 1 error LNK1561: entry point must be defined 

الحل:

أولًا : أفتح ملف cpp للنافذة الأولى ، موجود في الناحية اليمنى ؛ ثم أكتب بداخله هذا الكود ، وأكتب اسم مشروعك بدل كلمة “اسم المشروع الموجودة” 

using namespace System;
using namespace System::Windows::Forms;

[STAThread]
void Main(array<String^>^ args)
{
 Application::EnableVisualStyles();
 Application::SetCompatibleTextRenderingDefault(false);

اسم المشروع::MyForm form;
 Application::Run(%form);
}

مكان ملف cpp في الجانب الأيمن
Cpp Place

الكود

Codeثانيًا : أذهب إلى خصائص المشروع وأتبع الآتي 

Properties>>Configuration Properties->Linker->System
Select Windows (/SUBSYSTEM:WINDOWS) for SubSystem.
Advanced->Entry Point, type in Main >>hit OK.

Project FolderخصائصConfLinkerSystemW-subsAdvancedMainOK

أعمل Build مرة أخرى ثم Run ستجد أن البرنامج يعمل معك .

في هذا المثال لم أقم بتغيير أسماء النوافذ التي يقترحها البرنامج مثل MyForm ، لذلك عندما تغيّر أسماءها قد لاتعمل معك بعض أكوادي لاختلاف المسميّات ، وأنا أقترح عليك أن لاتغيّر الأسماء بالنسبة لي كانت تسبب مشاكل في الربط .

 

هناك اختلافات عند العمل مع visual studio 2008 ، بإمكانك مراسلتي إذا كنت تعمل على هذه النسخة ؛ كذلك لدّي مشروع  أتممته مع مجموعتي في الجامعة بواجهة رسومية يحوي LinkedList و Stack و Queue بإمكانك مراسلتي أيضًا إذا أحتجت مساعدة قد يكون لدي إجابة أو مررت على نفس الخطأ ؛ أنا أكتب هذا الكلام لأنني رأيت خلال تطوير مشاريع الواجهة الرسومية بالـ c++ أن المصادر شحيحة جدًّا ، لذلك لاأحب أن يواجه غيري صعوبات قد أكون اعرف لها حلًّا .

Advertisements

القراءة والكتابة في Text file

-أكتب برنامج يكتب في text file ثم يقرأ ماتمت كتابته .

الحل:

#include <iostream>
#include <fstream> //must include
#include <string>
using namespace std;

int main()
{

 int num;
/*---------------Write------------------------*/
 ofstream myfile("example.txt"); //create a text file automatically
 if (myfile.is_open())
 {
 //write on a text file
 myfile << "This is a line.\n";
 myfile << "This is another line.\n";

 //read data from user then write it on the file
 cout << "Enter a number: ";
 cin >> num;
 myfile << num;
 myfile.close();
 }
 else cout << "Unable to open file";

/*---------------Read------------------------*/
 string line;
 ifstream Read("example.txt" , ios::in);
 if (Read.is_open())
 {
 while (getline(Read,line))
 {
 cout << line << '\n';
 }
 Read.close();
 }
 else cout << "Unable to open file";

 system("pause");
 return 0;
}

-مايتم كتابته يبقى في الملف بعد الـ run ولكن عند عمل run مرة أخرى يكتب على البيانات السابقة .

– مكان الملف النصّي :

 المستندات documents

بيئة التطوير مثلًا visual studio

ملف المشاريع projects 

 ملف المشروع الذي أنشاته ، ثم بداخله ستجد ملف يحمل نفس اسم المشروع ستجد بداخله هذا الـ text file .

 

Template Class

أنشِئ Class :

اسمه: Addition

المتغيرات : elem1 ,elem2

يحوي : parameterized constructor و دالة لحساب مجموع العنصرين  و دالة لطباعة محتوى  .

-أجعل هذا الـ class يستقبل أي نوع من البيانات ، بمعنى يمكنه جمع أي عددين سواءً int أو double أو أي نوع آخر .

الحل:

جعل الـ class يستقبل أي نوع من البيانات يعني استخدام مفهوم template .

//main.cpp
#include <iostream>
using namespace std;
#include <string>

template <typename T>
class Addition
{

 T elem1;
 T elem2;

public:

 Addition(T val1, T val2);
 T calc();
 void print();

};


template <typename T> Addition<T>::Addition(T val1, T val2)
{
 elem1 = val1;
 elem2 = val2;
}

template <typename T> T Addition<T>::calc()
{
 return elem1 + elem2;
}

template <typename T> void Addition<T>::print()
{
 cout << "Result is: " << calc() << endl;

}

void main()
{
 Addition<int> ADD1st(9, 8);

 cout << "int type| ";
 ADD1st.print();

 Addition<double> ADD2nd(1.2 , 6.2);
 cout << "double type| ";
 ADD2nd.print();

 Addition<string> ADD3rd("HE", "llo");
 cout << "string type| ";
 ADD3rd.print();

 system("pause");
}

 

Operator Overloading

أنشِئ Class :

اسمهFraction

المتغيرات numerator , denominator

يحوي : default constructor و  set & get و  overloading functions للعمليات التالية :

جمع ، أقل من ، ضرب >> as global functions .

قسمة ، إسناد “=”  >> as member functions .

قراءة وطباعة .

-في main قم باختبار كل الـ operator overloading functions .

الحل:

مفهوم operator overloading هو أن نعيد تعريف الـ built-in operator حتى نتمكن من تطبيقها على الـ objects كأن نجمع 2 objects أو نضربهما ..الخ .

نلاحظ في السؤال أنه لم يتم التوضيح بالنسة لعملية القراءة cin والطباعة cout ماإذا كانت member or global لأنها في الواقع لايمكن ان تكون سوى global أي friend .

-يجب أن نراعي في الحل قوانين ضرب وجمع وقسمة ومقارنة الكسور .

 

//.h
#include <iostream>
using namespace std;

class Fraction
{
private:
 int numerator;
 int denominator;

public:
 Fraction(){ numerator = 0; denominator = 0; }

 void setNumerator(int num)
 {
 numerator = num;
 }
 void setDenominator(int num)
 {
 denominator = num;
 }
 int getNumerator()
 {
 return numerator;
 }
 int getDenominator()
 {
 return denominator;
 }

 //global means (friend) "optional"
 friend Fraction operator +(Fraction &obj1, Fraction &obj2);
 friend bool operator < (Fraction &obj1, Fraction &obj2);
 friend Fraction operator *(Fraction &obj1, Fraction &obj2);

 //member function "optional"
 void operator = (Fraction &obj);
 Fraction operator /(Fraction &obj);

 //must be friend
 friend ostream& operator << (ostream& outs, const Fraction& ob);
 friend istream& operator>>(istream& inc, Fraction& ob);

};
-----------------------------------------------------------
//.cpp
#include "Fraction.h"
#include <iostream>
using namespace std;

Fraction operator +(Fraction &obj1, Fraction &obj2)
{
 Fraction obj3;
 obj3.denominator = obj1.denominator * obj2.denominator;
 obj3.numerator = (obj1.numerator*obj2.denominator) + (obj2.numerator*obj1.denominator);
 return obj3;
}

bool operator < (Fraction &obj1, Fraction &obj2)
{
 if ((obj1.numerator / obj1.denominator) < (obj2.numerator / obj2.denominator))

 return true;

 else return false;
}

Fraction operator *(Fraction &obj1, Fraction &obj2)
{
 Fraction obj3;
 obj3.denominator = obj1.denominator*obj2.denominator;
 obj3.numerator = obj1.numerator*obj2.numerator;
 return obj3;
}

void Fraction::operator = (Fraction &obj)
{
 numerator = obj.numerator;
 denominator = obj.denominator;
}

Fraction Fraction::operator/(Fraction &obj)
{
 Fraction obj3;
 obj3.denominator = denominator*obj.numerator;
 obj3.numerator = numerator*obj.denominator;
 return obj3;
}

ostream& operator << (ostream& outs, const Fraction& ob)
{
 outs << "The result is: ";
 outs << ob.numerator << "/" << ob.denominator << endl;
 return outs;
}

istream& operator >> (istream& inc, Fraction& ob)
{
 cout << "Enter the number numerator: ";
 inc >> ob.numerator;
 cout << "Enter the number denominator: ";
 inc >> ob.denominator;
 return inc;
}
---------------------------------------------------
//main.cpp
#include <iostream>
using namespace std;
#include "Fraction.h"
int main() {

 Fraction f1, f2;

 cin >> f1;
 cin >> f2;

 cout << " << operator:\n";
 cout << f1 << f2;

 cout << " + operator: ";
 Fraction f3 = (f1 + f2);
 cout << f3;

 cout << " < operator: ";
 cout << (f1<f2) << endl;

 cout << " * operator: ";
 Fraction f4 = f1*f2;
 cout << f4;

 cout << " = operator: ";
 Fraction f5 = f1;
 cout << f5;

 cout << " / operator: ";
 cout << (f1 / f2);



 system("pause");
 return 0;
}

Polymorphism

أنشِئ Class :

اسمه: novel

المتغيرات : ntype, nprice

يحوي : دالة تقوم بعمل return لسعر الرواية وهو 30 بشكل عام ، ودالة تقوم بعمل return لنوع الرواية وهو general ودالة لطباعة المعلومات .

هذا الـ Class  هو Base Class  ، والتالية هي  Derived Classes  : “مفهوم الوراثة

الـ  Classes التالية لديها مثل متغيرات الـ Class الأب ، ولكن تعريفات(وليست أسماء) أخرى للدوال عن تلك الموجودة في الـ class الأب !

الـ Class الأول  :

اسمه: Agatha

يحوي : يختلف بأن سعر الرواية هو 15 ونوعها mystery .

الـ Class الثاني:

اسمه: McGraw

 يحوي : تختلف فقط في سعر الرواية هو 20 أما النوع لايختلف عن النوع العام general .

الـ Class الثالث:

اسمه: Signed

 يحوي : تختلف فقط في نوع الرواية هو signed أما السعر لايختلف عن السعر العام 30.

أكتب هذه الـ Classes بحيث في main عندما تُنشِئ pointer من نوع novel  وتجعله يشير لأنواع مختلفة من الـ objects يعرض معلومات صحيحة لكل نوع ، بمعنى عندما تجعله يشير للـ object من نوع Signed وتقوم بتعبئة معلوماته عن طريق الدوال ثم تطبع المعلومات نجد أن النوع ليس general وإنما signed.  “مفهوم الـ polymorphism”

الحل:

#include <iostream>
#include <string>
using namespace std;

class novel
{
public:
 double nprice;
 string ntype;

 virtual double price(){ return 30; }
 virtual string type(){ return "general"; }

 void display()
 {
 cout << "Novel price= " << nprice << endl;
 cout << "Novel type= " << ntype << endl;
 }
};
//-----------------------------------------------------//
class Agatha :public novel
{
public:
 double price(){ return 15; }
 string type(){ return "mystery"; }
};
//----------------------------------------------------//
class McGraw :public novel
{
public:
 double price(){ return 20; }
};
//----------------------------------------------------//
class Signed :public novel
{
public: string type(){ return "signed"; }
};
//----------------------------------------------------//
void main()
{
 Agatha a;
 McGraw m;
 Signed s;
 novel *n;

 n = &a;
 //fill info
 n->nprice = n->price();
 n->ntype = n->type();
 //print
 n->display();

 n = &m;
 n->nprice = n->price();
 n->ntype = n->type();
 n->display();

 n = &s;
 n->nprice = n->price();
 n->ntype = n->type();
 n->display();

 system("pause");
}

السطر 11 و 12 : كلمة virtual هي التي تسمح لي بإعطاء تعريفات اخرى للدوال في الـ classes الأخرى 

Inheritance الوراثة

أنشِئ Class :

اسمه: publication

المتغيرات : title , price

يحوي :  Parameterized constructor  و  default constructor و دالة تقرأ من المستخدم  البيانات للمتغيرات  وتخزنها و أخيرًا دالة طباعة.

هذا الـ Class  هو Base Class  ، والتالية هي  Derived Classes  : “مفهوم الوراثة “

الـ Class الأول  :

اسمه: Book 

المتغيرات : Pagecount

يحوي :  Parameterized constructor يقوم بعمل initialize لـ Data Member متضمنة الـ Data Member للـ Base Class  و دالة تقرأ من المستخدم  البيانات للمتغيرات وتخزنها و أخيرًا دالة طباعة.

 

الـ Class الثاني :

اسمه: Tape

المتغيرات : PlayingTinM “Playing Time in minute” .

يحوي :  Parameterized constructor يقوم بعمل initialize لـ Data Member متضمنة الـ Data Member للـ Base Class  و دالة تقرأ من المستخدم  البيانات للمتغيرات وتخزنها و أخيرًا دالة طباعة.

-قم بفصل الـ Class interface  في header file و Class implementation في cpp file

الحل: 

//publication.h

#include <iostream>
#include <string>
using namespace std;

#ifndef CLASS_PUBLICATION
#define CLASS_PUBLICATION

class publication
{
private:
 string title;
 float price;
public:

 publication();
 publication(string t, float p);
 void getdata();
 void putdata() const;
};

#endif
--------------------------------------------------
//publication.cpp
#include <iostream>
#include <string>
#include "publication.h"
using namespace std;

publication::publication(){ title = ""; price = 0; }
publication::publication(string t, float p){ title = t; price = p; }

void publication::getdata()
{
 cout << "Enter title:"; cin >> title;
 cout << "Enter price: "; cin >> price;
}
void publication::putdata() const
{
 cout << "\nTitle: " << title;
 cout << "\nPrice: " << price << endl;
}
-----------------------------------------------
//book.h
#include <iostream>
#include <string>
#include "publication.h"
using namespace std;


class Book :public publication
{
 int PageCount;
public:
 Book(int, float, string);
 void getdata();
 void putdata()const;

};
----------------------------------
//book.cpp
#include <iostream>
#include <string>
#include "publication.h"
#include "Book.h"
using namespace std;


Book::Book(int Pg, float Price, string T) :PageCount(Pg), publication(T, Price){}
void Book::getdata()
{
 publication::getdata();
 cout << "Enter the Page number: "; cin >> PageCount;
}
void Book::putdata()const
{
 cout << "Page Count: " << PageCount << endl << endl;
}
------------------------------------
//tape.h
#include <iostream>
#include <string>
#include "publication.h"
using namespace std;


class Tape : public publication
{
 float PlayingTinM;
public:
 Tape(float, float, string);
 void getdata();
 void putdata()const;
};
----------------------------------------
//tape.cpp
#include <iostream>
#include <string>
#include "publication.h"
#include "Tape.h"
using namespace std;

Tape::Tape(float PTIM, float Price, string T) :PlayingTinM(PTIM), publication(T, Price){}

void Tape::getdata()
{
 publication::getdata();
 cout << "Enter the Playing Time in miunte: "; cin >> PlayingTinM;
}
void Tape::putdata()const
{
 cout << "the Playing Time in miunte: " << PlayingTinM << endl;
}

 

السطر 7 و 8 و 23 : هذا الـ Directive هو حل لهذا الخطأ

 Error 1 error C2011: ‘publication’ : ‘class’ type redefinition c:\users\amjad\documents\visual studio 2013\projects\myblog\myblog\publication.h 7 1 myBlog

السطر 52 و 88 : طريقة الوراثة بكتابة نوع الوراثة ثم اسم الـ Base Class

السطر 70  و 104 : طريقة عمل initialize لمتغيرات الـ Base Class عن طريق مناداة الـ Constructor للـ Base Class

Cascading

أنشِئ Class :

اسمه: MyAge

المتغيرات : Year , Month , Day

يحوي :  Set functions و Print Function  و  default constructor.

* يجب أن تُكتب الـ functions حتى نستطيع أن نقوم بعمل Cascading Call في Main functions .

-قم بفصل الـ Class interface  في header file و Class implementation في cpp file

الحل:

طريقة كتابة الـ function حتى نستطيع القيام بعمل Cascading Call هي أن

  1. يكون الـ return type لها هو object من نفس نوع الـ Class بهذه الطريقة  ( & ClassName  ) .

  2. أن تكون الـ return value هي pointer للـ object الذي قام باستدعاء هذه الـ function وهو *this .

//.h
#include <iostream>
using namespace std; 

class MyAge
{
public:
 MyAge();
 MyAge &My_yers(int);
 MyAge &My_month(int);
 MyAge &My_day(int);
 void print();


private:
 int year;
 int month;
 int day;

};
------------------------------------------------------
//.cpp
#include <iostream>
#include "MyAge.h"
using namespace std;

MyAge::MyAge(){ year = 0; month = 0; day = 0; } //default constructor

MyAge & MyAge::My_yers(int y)
{
 year = y; //initialize years
 return *this; //return value
}

MyAge & MyAge::My_month(int m)
{
 month = m; //initialize month
 return *this; //return value
}

MyAge & MyAge::My_day(int d)
{
 day = d; //initialize day
 return *this; //return value
}

void MyAge::print()
{
 cout << year << "/" << month << "/" << day << endl; /*ptint out years and months */
}
-----------------------------------------------
//main
#include <iostream>
#include "MyAge.h"
using namespace std;

void main()
{
 MyAge age;

 age.My_yers(2000).My_month(1).My_day(20).print(); //Cascading Call

 system("pause");

}