دعم الاتجاه من اليسار الى اليمين
#1
السلام عليكم
نريد ان نناقش الموضوع بشكل جدي ومن زاوية اخرى
لان دعم الاتجاه من اليمين الى اليسار صار يسبب لي الصداع والارق مع الدلفي .
كلكم تعرفون طبعاً هذا الكود لقلب الاشياء من اليمين الى اليسار كما بالشكل التالي :
كود :
const
WS_EX_NOINHERITLAYOUT = $00100000; // Disable inheritence of mirroring by children
WS_EX_LAYOUTRTL = $00400000; // Right to left mirroring

Procedure SetWinControlBiDi(Control: TWinControl);
var
ExStyle: Longint;
begin
ExStyle := GetWindowLong(Control.Handle, GWL_EXSTYLE);
SetWindowLong(Control.Handle, GWL_EXSTYLE, ExStyle or WS_EX_RTLREADING or WS_EX_RIGHT
   or WS_EX_LAYOUTRTL or WS_EX_NOINHERITLAYOUT );
end;

Procedure TForm1.FormCreate(Sender: TObject);
begin
SysLocale.MiddleEast := True;
SetWinControlBiDi(PageControl1);
end;
هذا الكود يعمل احيانا واحيانا اخرى ومع مكونات لا يعمل .
واحيانا يعمل على الاصدارة 2010 ولا يعمل على الاصدارة 2007
الخلاصة
ما الذي يجعل الادوات تتجه من اليسار الى اليمين هل هو كود برمجي ام شئ اخر
وماذا تعني هذه التوابث بالضبط كما بالشكل التالي :
كود :
WS_EX_NOINHERITLAYOUT = $00100000; // Disable inheritence of mirroring by children
WS_EX_LAYOUTRTL = $00400000; // Right to left mirroring
باختصار شديد ما بداية الطريق لكيفية التحكم بالادوات
احيانا اقوم باستخدام هذا الكود على اداة TabPage او ListBox فتحدث تقنية المراءة ولكنها تظهر الكتابة مقلوبة ايضا
انظروا للشكل التالي
إقتباس :http://www4.0zz0.com/2010/10/15/14/470616830.jpg
فهل هناك طريقة لحل هذه المشكلة ...؟
بين الانسان والكفر ترك الصلاة فمن تركها فقد كفر .
الرد
#2
وعليكم السلام ورحمة الله وبركاته
إقتباس :بمعى نريد ان نناقش الموضوع بطريقة فنية اي ما الذي يحدث عند استخدام هذا الكود
إنها توابع Windows API
حاول ألا تتعامل مع الإجراءات والتوابع والثوابت على أنها "كود" أنسخه وألصقه ويعمل عمله!
ألق نظرة على ملفات الـ Help في دلفي مع الترجمة شيئا فشيئا يتضح الغرض منها
أول خطوة، طالع هذه جيدا:
كود :
http://msdn.microsoft.com/en-us/library/ms633584(VS.85).aspx
بالتوفيق.
الرد
#3
السلام عليكم

إقتباس :اولا لا يقل لي احد ان هذا الموضوع نوقش هنا لانني بحثث عنه ولم اجده
لا تعليق Smile


من جهة ويندوز، المكونات المرئية في ويندوز يمكن تقسيمها إلى:
1- النافذة Window وتفرعاتها من متحكمات وهي معدودة وتسمى Predefined Controls وتشملButton, ListBox, ComboBox, Edit, Scrollbar, Static، وهي التي قامت دلفي بتغليفها في وحدة StdCtrls.pas كما نجدها في شريط المكونات في صفحة Standard.

2- نوافذ الحوار Common Dialogs مثل OpenDialog و SaveDialog ، ونجد تغليفها في وحدة Dialogs.pas وأيقوناتها في صفحة Dialogs في شريط المكونات.

3 – متحكمات أخرى مثل لوائح الأوامر Menues

4- متحكات عامة Common Controls مثل TreeView و ListView و ProgressBar ، و نجد تغليفها في وحدة ComCtrls.pas كما أن أيقوناتها في صفحة Win32 في شريط المكونات.

المكونات المرئية في دلفي بعضها تغليف لما هو لمكونات أصلية متوفرة في ويندوز، كما سبق سرده، وبعضها من إنشاء مكتبة دلفي بناء على مكونات أساسية في ويندوز. ويمكن أن نقسمها إلى ثلاث أقسام:
1- مكونات أصلية في ويندوز، مثل TEdit و TButton و TListBox
2- مكونات أصلية في ويندوز مع بعض التحسينات أو التعديلات مثل TBitBtn و TCheckListBox
3- مكونات ليست في ويندوز وتم إنشاؤها من قبل مكتبة دلفي مثل TGroupBox و TPanel
يمكن أن تكون بعض المكونات عبارة عن تركيب من مكونين أو أكثر مثل TPageControl أو LabeledEdit1

الآن نأتي لمسألة دعم التحويل من اليمين إلى اليسار رؤية و كتابة.
سنلاحظ في دلفي أن المكونات المرئية التي لا تدعم تحويل الاتجاه أغلبها ما تم إدراجه تحت Common Controls أي التي نراها في صفحة Win32 .

يفترض في دلفي فيما يخص واجهة الاستخدام أن تقوم بدعم وتغليف معظم الخصائص الأساسية التي تقدمها ويندوز، يبدو أن دعم الاتجاه من اليمين لليسار ليست من أولى وأهم اهتمامات دلفي، لذلك نلجأ لمخاطبة ويندوز مباشرة وإستدعاء الدوال الخاصة بها. من ضمن هذه الدوال دالة SetWindowLong
نستخدم هذه الدالة لتحديد الخصائص التي نريدها لعنصر ما. عادة قبل أن نستدعي هذه الدالة نقوم بجلب الخصائص الحالية للعنصر من خلال الدالة GetWindowLong ونحفظ قيمتها في متغير. ثم نستدعي SetWindowLong ونمرر لها قيمة الخصائص السابقة + الخصائص الجديدة التي نريدها في العنصر مثل خاصية WS_EX_RIGHT أو WS_EX_RTLREADING.

المشكلة (على الأقل بالنسبة لي) أن تطبيق هذه الدالة على عناصر واجهة الاستخدام لاتعطي دائما نفس النتائج المتوقعة، وتختلف تصرفاتها بين عنصر وآخر كما بعض العناصر تستجيب لخاصية ما بينما عنصر آخر لا يتأثر بها.

خاصية WS_EX_LAYOUTRTL تقوم بعملية Mirroring أي عكس الصورة كأن تضعها أم مرآة. لذلك لو طبقتها على الفورم Form سنلاحظ أن أزرار الفورم قد انعكست و أن المكونات فيها قد انعكست أوضاعها، و أن المكون نفسه قد انعكست صورته و إن كان مجسما يصبح ظله على اليمين. وتنعكس أيضا حتى الإحداثيات حيث تنطلق احدثيات X من اليمين فإذا رسمنا نصا مثل:
PHP كود :
Canvas.TextOut(10,10‘Hello’
سيتم رسم النص على اليمين.

المشكلة تزداد سوءا مع المكونات المركبة من قبل دلفي مثل TPageControl أنظر:
http://www.delphi4arab.net/forum/showthr...agecontrol

إقتباس :ونريد ان نعرف ما تعني هذه التوابث بالضبط
هذه ثوابت معرفة في وحدة Windows.pas ولا داعي لتعريفها في تطبيقك لأنه عادة تكون هذه الوحدة ضمن قسم uses
وهي ثوابث رقمية نستخدمها لتمرير قيمها عند استدعاء دوال وينودز.

إقتباس :باختصار شديد نريد بداية الطريق لكيفية التحكم بالادوات
البداية هي معرفة نظام التشغيل وتفصيلاته.
الخلاصة: أن الدعم للعربية ليس مكتملا لجميع عناصر واجهة الاستخدام في ويندوز، وحتى المكتمل منه بعضه ليس مدعوما من قبل دلفي.
إقتباس :فهل هناك طريقة لحل هذه المشكلة ...؟
- مخاطبة القائمين على ويندوز
- مخاطبة القائمين على دلفي
- أن نقوم بأنفسنا ببرمجة وتطوير عناصر ومكونات تدعم الخصائص التي نحتاجها.

ملاحظة: قد أكون مخطئا في بعض النقاط السابقة فلا تبخلوا علينا بأي تصحيح.
الرد
#4
السلام عليكم

كلام جميل وكلام كبير
وشكرا لتفاعلكم مع الموضوع واعذروني لانني مبتدئ في الدلفي ولا استطيع مناقشة الموضوع بعمق .
بالنسبة لرد الاخ kachwahed فعلا الموضوع جيد وقد وجدت نفس التوابث في الوحدة Windows وكنت بصدد الحديث عنها
كود :
{ Window field offsets for GetWindowLong() }
  {$EXTERNALSYM GWL_WNDPROC}
  GWL_WNDPROC = -4;
  {$EXTERNALSYM GWL_HINSTANCE}
  GWL_HINSTANCE = -6;
  {$EXTERNALSYM GWL_HWNDPARENT}
  GWL_HWNDPARENT = -8;
  {$EXTERNALSYM GWL_STYLE}
  GWL_STYLE = -16;
  {$EXTERNALSYM GWL_EXSTYLE}
  GWL_EXSTYLE = -20;
  {$EXTERNALSYM GWL_USERDATA}
  GWL_USERDATA = -21;
  {$EXTERNALSYM GWL_ID}
  GWL_ID = -12;
وأيضاً
كود :
{$EXTERNALSYM WS_EX_RIGHT}
  WS_EX_RIGHT = $1000;
  {$EXTERNALSYM WS_EX_LEFT}
  WS_EX_LEFT = 0;
  {$EXTERNALSYM WS_EX_RTLREADING}
  WS_EX_RTLREADING = $2000;
  {$EXTERNALSYM WS_EX_LTRREADING}
  WS_EX_LTRREADING = 0;
  {$EXTERNALSYM WS_EX_LEFTSCROLLBAR}
  WS_EX_LEFTSCROLLBAR = $4000;
  {$EXTERNALSYM WS_EX_RIGHTSCROLLBAR}
  WS_EX_RIGHTSCROLLBAR = 0;
وسأحاول ان ارى ان كانت وكان الموضوع يستطيع حل المشكلة

وبالنسبة لرد shagrouni فقد افادني حديثك عن الوحدات .
ولكن لي سؤال وهو الا يمكن اعادة استخدام او رسم الخط ليظهر بشكله الصحيح بالنسبة للاداة TlistBox في الحدث OnDrowItem حيث انني طبقت الدالة السابقة وتم تطبيق مبدأ الانعكاس وحدتث خربطة في النص .
اذا تم تصحيح وضع النص تم تصحيح المشكلة ككل .
حيث ان الدالة السابقة تقوم بعملها بشكل جيد في الدلفي 2010 .

وأيضا حاولت ان اقوم بانشاء مكون يقوم بمحاذاة كل الادوات على النموذج فقمت بالتالي:
كود :
procedure TForm1.FormCreate(Sender: TObject);
var
I:integer;
begin
for I := 1 to self.ComponentCount do
if self.Components[I].ClassType.ClassName='TListBox' then
GetWindowLong(???)
end;
اولا بحثث عن اسماء كل المكونات لاحدد ما هي المكونات التي يجب محاذاتها والمشكلة هي في ارسال اسم العنصر او تحويل اسمه والذي هو نص String الى كائن وهو Tobject
وهذه الطريقة ستفيذ في عدم تكرار الكود للتعامل مع كل العتاصر على النموذج
وبالنهاية سأدرس مقترحاتكم واعود قريبا ان شاء الله
بين الانسان والكفر ترك الصلاة فمن تركها فقد كفر .
الرد
#5
إقتباس :if self.Components[I].ClassType.ClassName='TListBox' then
بشكل أبسط:
كود :
if Components[I] is TListBox then
الرد
#6
السلام عليكم

بالنسبة لمكون TListBox و مكون TComboBox
لاحظت أن تغيير خاصية BidoMode لاتؤثر فيهما
هذا أمر غريب، فمنذ بدايات دلفي وحتى وقت قريب لم توجد مشكلة في تغيير اتجات المكونات
الأساسية ومن ضمنها ListBox ، لاأعلم السبب و يتطلب الأمر مزيد من الفحص. أنا أستخدم دلفي 6
وويندوز 7. هل للتحديثات الأخيرة للويندوز هي السبب؟

عموما المكونات الأساسية يمكن تغيير اتجاهها أيضا بإرسال Message نوع BIDIMODECHANGED
PHP كود :
SendMessage(ListBox1.HandleCM_BIDIMODECHANGED00); 
أو بإستخدام التغليف الذي تقوم به دلفي:
PHP كود :
ListBox1.Perform(CM_BIDIMODECHANGED00); 

فيما يخص تغيير نمط Style العنصر من خلال الدالة SetWindowLong ، يلاحظ وجود نوعين من الأنماط:
GWL_STYLE و قيمها تبدأ بـ _WS مثل WS_VISIBLE والنوع الأخر GWL_EXSTYLE وقيمها تبدأ بـ _WS_EX
وهو الذي يهمنا الآن.

نمط Style العنصر يمكن تغييرها من خلال الدالة SetWindowLong ، القيم المسؤولة عن نمط Style
العنصر فيما يخص اتجاهه والكتابة فيه هي التالي:

PHP كود :
WS_EX_RIGHT = $1000الاتجاه لليمين
WS_EX_LEFT 
0الاتجاه لليسار (الافتراضي)
WS_EX_RTLREADING = $2000;  نسق كتابة الأحرف من اليمين لليسار
WS_EX_LTRREADING 
0نسق اجاه الكتابة من اليسار لليمين (الافتراضي)
WS_EX_LEFTSCROLLBAR = $4000لوح التحريك على يسار العنصر
WS_EX_RIGHTSCROLLBAR 
0;لوح التحريك على يمين العنصر  (الافتراضي
وهذه بالنسبة لتأثيرات عكس صورة العنصر

PHP كود :
WS_EX_LAYOUTRTL = $00400000لعكس صورة العنصر 
WS_EX_NOINHERITLAYOUT 
= $00100000لمنع تأثير عكس صورة العنصر على العناصر المتضمنة فيه 

بالنسبة لتأثيرات عكس الصورة نحتاجها لمكونات واجهة الاستخدام من نوع Common Controls لأنه
حسبما يبدو فإن هذه المكونات لاتتأثر بقيم WS_EX_RIGHT.

عند تغيير النمط نمرر مجموع قيم الأنماط المراد تحديدها
نحصل أولا على قيمة الأنماط الحالية في العنصر
PHP كود :
ExStyle  := GetWindowLong(ListBox.HandleGWL_EXSTYLE); 
ثم نعطي القيم الجديدة و التي حاصل مجموع القيمة الحالية + أية قيمة جديدة.
مثلا الكود التالي يجعل من ListBox تتجه من اليمين إلى اليسار:
PHP كود :
SetWindowLong(Control.HandleGWL_EXSTYLEExStyle WS_EX_RIGHT(;
ListBox1.Refresh
(ولكن الأصح أن نستخدم المعامل OR بدلا من المعامل +)

فإذا أردنا أن نعيد الإتجاه ليكون من اليسار لليمين نطرح قيمتها من قيم نمط العنصر:
PHP كود :
SetWindowLong(Control.HandleGWL_EXSTYLEExStyle WS_EX_RIGHT(;
ListBox1.Refresh

ويمكن التأكد من وجود قيمة معينة ضمن نمط العنصر كالتالي:
PHP كود :
ExStyle  := GetWindowLong(ListBox1.HandleGWL_EXSTYLE);

if (
ExStyle and WS_EX_RIGHT) = WS_EX_RIGHT then
  SetWindowLong
(ListBox1.HandleGWL_EXSTYLEExStyle WS_EX_RIGHT)
else
  
SetWindowLong(ListBox1.HandleGWL_EXSTYLEExStyle or WS_EX_RIGHT);

ListBox1.Refresh

يجب أن نلاحظ أنه إذا تم تغيير خاصية BidiMode للعنصر فإن قيمة ExStyle ستتغير فيها، لذا وجب أن
نراعي هذه القيمة عند التعامل مع SetWindowLong.

توجد قيم أخرى يجب الانتباه إليها عند التعامل مع بعض أنواع العناصر، مثلا عنصري: TCheckBox و
TRadioButton من أجل تحويل اتجاههما نحتاج للتعامل مع GWL_STYLE وليس GWL_EXSTYLE مثل
التالي:
PHP كود :
Style := GetWindowLong(CheckBox1.HandleGWL_STYLE);
  
Style := Style or BS_RIGHT or BS_LEFTTEXT;
  
SetWindowLong(CheckBox1.HandleGWL_STYLEStyle);
  
CheckBox1.Refresh
لكن إذا طبق النمط السابق على Button فسيجعل محاذاة الكتابة في الزر على اليمين.

الخلاصة: كل مكون لايوجد له دعم في دلفي فيما يخص ثنائية الاتجاه، فإن الأمر يستدعي تطبيق الدوال
والرسائل المناسبة له. فلا توجد إحرائية موحدة يمكن تطبيقها على الكل.

إقتباس :ولكن لي سؤال وهو الا يمكن اعادة استخدام او رسم الخط ليظهر بشكله الصحيح بالنسبة للاداة TlistBox في الحدث OnDrowItem حيث انني طبقت الدالة السابقة وتم تطبيق مبدأ الانعكاس وحدتث خربطة في النص .
إذا استخدمت Mirroring على ListBox فيجب أن تراعي أن الاحداثيات ستكون من اليمين لليسار عند
الرسم عليه.

و عموما ListBox لايحتاج WS_EX_LAYOUTRTL لتغيير اتجاهه. وكما أسلفت رسالة من نوع BIDIMODECHANGED تكفيه.
الرد
#7
السلام عليكم

إقتباس :بالنسبة لمكون TListBox و مكون TComboBox
لاحظت أن تغيير خاصية BidoMode لاتؤثر فيهما
هذا أمر غريب، فمنذ بدايات دلفي وحتى وقت قريب لم توجد مشكلة في تغيير اتجات المكونات
الأساسية ومن ضمنها ListBox ، لاأعلم السبب و يتطلب الأمر مزيد من الفحص. أنا أستخدم دلفي 6
وويندوز 7. هل للتحديثات الأخيرة للويندوز هي السبب؟

في الدلفي 2010 لا مشكلة وكذلك 2007 مع نظام التشغيل ويندوز اكس بي

اما بخصوص كل الحديث الذي تم ذكره فوق فجزاك الله كل خير وقد قمت بتجريب وتغيير ومحاول كل الطرق ولك تفلح المحاولة

طبعا نجحت على الادوات التي تاتي مع الدلفي مثل TTreeView وكذلك TlistView وغيرها

ولكن لم تنجح مع ادوات من شركة اخرى مثل Alpha Skin فيبدو انها سياسة الشكة نفسها

او هو نتيجة تدخل المبرمج في التحكم بالادوات عن طريق اعادة تعريف الطرق والمناهج لها


اما بخصوص محاولة انشاء مكون يقوم بتغيير اتجاه كل الادوات التي لا تدعم العربي فقد توصلت اخيرا الى الكود بعدة عدة محاولات كما بالشكل التالي :

كود :
Procedure SetWinControlBiDi(Control: TWinControl);
var
ExStyle: Longint;
begin
ExStyle := GetWindowLong(Control.Handle, GWL_EXSTYLE);
SetWindowLong(Control.Handle, GWL_EXSTYLE, ExStyle or WS_EX_RTLREADING or WS_EX_RIGHT
   or WS_EX_LAYOUTRTL or WS_EX_NOINHERITLAYOUT );

end;


procedure TForm1.FormCreate(Sender: TObject);
var
I:integer;
begin

for I := 0 to self.ComponentCount- 1 do
if ((self.Components[I] is TTreeView) or (self.Components[I] is TPageControl))  then
SetWinControlBiDi(Components[I] as TWinControl)


end;


ولكن السؤال هو ما هو الكائن الذي يجب ان يتم وراتثه في انشاء هذا المكون حيث انني لا ارغب في اي احداث ولا اي خصائص

فهل ينفع هذا


كود :
unit Bevel1;

interface

uses
  SysUtils, Classes, Controls, ExtCtrls;

type
  TBevel1 = class(TBevel)
  private
    { Private declarations }
  protected
    { Protected declarations }
  public
    { Public declarations }
  published
    { Published declarations }
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples', [TBevel1]);
end;

end.

عندما اقصد ما الذي تجب وراتتثه فانا اقصد ما هو الكائن المناسب لهذه العملية والذي يكون مثل المكون الخاص بالقوائم او الاتصال حيث ليس له شكل رسومي وانما يكفي استدعاء اجراء فيه فقط
بين الانسان والكفر ترك الصلاة فمن تركها فقد كفر .
الرد
#8
السلام عليكم

من الممكن ان تستخدم هذه الطريقة وترث هذا الصنف

كود :
unit Component1;

interface

uses
  SysUtils, Classes, Controls,forms,windows;

type
  TComponent1 = class(TComponent)
  procedure MyProcedure();
  private
    { Private declarations }
  protected
    { Protected declarations }
  public
    { Public declarations }
  published
    { Published declarations }
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples', [TComponent1]);
end;


Procedure SetWinControlBiDi(Control: TWinControl);
var
ExStyle: Longint;
begin
ExStyle := GetWindowLong(Control.Handle, GWL_EXSTYLE);
SetWindowLong(Control.Handle, GWL_EXSTYLE, ExStyle or WS_EX_RTLREADING or WS_EX_RIGHT
   or WS_EX_LAYOUTRTL or WS_EX_NOINHERITLAYOUT );

end;


procedure TComponent1.MyProcedure;
var
myfrm:Tform;
myint:integer;
begin
myfrm:=(self.Parent as Tform);
myfrm.Caption:='fghfgh';

for I := 0 to self.ComponentCount- 1 do
if ((self.Components[I] is TTreeView) or (self.Components[I] is TPageControl))  then
SetWinControlBiDi(Components[I] as TWinControl)
end;

end.
بين الانسان والكفر ترك الصلاة فمن تركها فقد كفر .
الرد
#9
السلام عليكم

تم اجراء تعديل على الوحدة السابقة فصارت كما بالشكل التالي :

كود :
unit Component1;

interface

uses
  SysUtils, Classes, Controls, forms, windows,ComCtrls,Menus;

type
  TComponent1 = class(TComponent)
  procedure RigthToLeft(Value: Tform);
  private
    { private declarations }
   protected
    { Protected declarations }
  public
    { Public declarations }
  published
    { Published declarations }
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples', [TComponent1]);
end;


Procedure SetWinControlBiDi(Control: TWinControl);
var
ExStyle: Longint;
begin
ExStyle := GetWindowLong(Control.Handle, GWL_EXSTYLE);
SetWindowLong(Control.Handle, GWL_EXSTYLE, ExStyle
or WS_EX_RTLREADING
or WS_EX_RIGHT
or WS_EX_LAYOUTRTL
or WS_EX_NOINHERITLAYOUT );

Control.Invalidate;

end;

procedure TComponent1.RigthToLeft(Value: Tform);
var
myint:integer;
begin
SysLocale.MiddleEast := True;

for myint := 0 to Value.ComponentCount - 1 do
  if ((Value.Components[myint] is TTreeView)      or
     (Value.Components[myint]  is TPageControl)   or
     (Value.Components[myint]  is TListView))     then
  begin
SetWinControlBiDi(Value.Components[myint] as TWinControl);
  end;

end;

end.


حيث صار لها اجراء يمرر له بارمتر يحتوي النموذج الذي نعمل عليه وقد جربتها وهي تعمل على احسن ما يرام

حيث يتم اختبار الادوات التي لا تدعم الاتجاه من اليمين الى اليسار كما بالشكل التالي :

كود :
if ((Value.Components[myint] is TTreeView)      or
     (Value.Components[myint]  is TPageControl)   or
     (Value.Components[myint]  is TListView))     then

اذا كانت احدى الادوات التالية تم تطبيق مبداء المراءة عليها
بين الانسان والكفر ترك الصلاة فمن تركها فقد كفر .
الرد


التنقل السريع :


يقوم بقرائة الموضوع: بالاضافة الى ( 1 ) ضيف كريم