littlerabbit
abolfazlerfani wrote:
در مورد منو بايد بگويم که آنها در حالت عادي يکي از انعطاف پذيرترين ابزار برنامه نويسي هستند اما اگر نخواهيم وارد مباحث پيشرفته شويم راهي براي تغيير دادن فونت منوهايي که با پرچم MF_STRING (منوهاي عادي- مثل منوهاي وي بي يا منوهاي ويژوال سي) مشخص شده اند وجود ندارد.
تنها راه ساده موجود اين است که فونت تمام منوهاي سيستم را عوض کنيم - از طريق Display Properties \Appearance يا از طريف دستکاvي مستقيم در رجيستري (HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics\MenuFont البته اين مقدار به صورت باينري است نه رشته اي- حالا مشکلي پيش ميايد و آن مساله عوض شدن فونت در کل سيستم است -اين براي امثال من که ترجيح ميدهم همه چيز توسط خودم انتخاب شود کمي ناخوشايند است که يک برنامه تنظيمات سيستم مرا به هم بريزد-
راه ديگري هم هست که متاسفانه بدون ترس از Crash در برنامه هاي ويژوال بيسيک نميتوان از آن استفاده کرد
توابع API منو تنها دو تابع دارند که ميتواند اطلاعات مربوط به يک منو و آيتم هاي آن را بگيرد اما هيچکدام راهي براي تغيير فونت ارايه نداده اند.(همه توابع ديگر نيز توسط اين دو تابع قابل جايگزيني هستند منتها با کمي دردسر بيشتر ) يکي GetMenuInfo و يکي GetMenuItemInfo .
شايد براي شما هم مساله اين است که برنامه هايي مثل IncrediMail يا Axialis IconWorkshop (که دومي حتي سيستم منوي آن هم دستکاري شده ) چه طور اينکار را ميکنند؟
آنها همه منوهاي خود را با فلگ MF_OWNERDRAW مشخص ميکنند و در هنگام اجراي برنامه به پيغام هاي WM_MEASUREITEM و WM_DRAWITEM جواب ميدهند که اين کار در وي بي امکان ندارد ( در يک تاپيک دوستي ادعا کرده بود که اين کار - پردازش پيغامهاي Custome در وي بي بدون Hook يا SubClass ممکن است اما هيچوقت اين راه را نشان نداد- متاسفانه- ) به هر حال اگر کسي هست که اين مطلب را ميحواند و ميتواند اين کار را بکند (بدون Hook و SubClass ) آنوقت به من هم ياد بدهد (البته بهتر است وقت خودتان را تلف نکنيد!)
حالا ميرويم سراغ دلفي منو و فونت اگر ديده باشيد دلفي ميتواند فونت ها را براي منو عوض کند اين به معناي نقض گفته هاي بالايي نيست. منو هاي دلفي استاندارد نيستند (گر چه دقيقا با منو هاي استاندارد مشابه هستند) حتي خصيصه Handle که در Help دلفي ادعا شده براي استفاده در توابع Api مفيد است به درد اين کار نميخورد مثلا نميتوان توسط توابع AppendMenu يا InsertMenuItem گزينه اي به اين منو ها اضافه کرد.
و اما مشکل اين دوست. اگر تمام کنترل هاي ديگر مثل Command و يا Label درست نمايش داده ميشوند يعني اينکه فونت مربوط به منوها در برنامه شما نميتواند علائم گچپژ را نشان دهد اما فونت مربوط به کنترل ها ميتواند. (ميتوانيد براي رفع اين مشکل از Display Properties \Appearance فونت منوها را عوض کنيد. (احتمالا فونت کنترل ها MS SansSerif است و فونت مربوط به منو ها Tahoma ) اگر مشکلتان حل نشود من متاسفانه راه ديگري بلد نيستم.
درمورد مساله دوم. ميتوانيد يک تابع ساده (با يک Switch ساده) که کل کد هاي معادل دار را به کد معادلشان تبديل کند را بنويسيد و شايد من مشکل شما را درست متوجه نشده ام؟؟
براي درک بيشتر مساله منو هاي Owner Draw يک مثال با دلفي نوشتم که از چند تا Api ساده استفاده ميکند. چون ميخواستم که توابع مربوط به Device Context يا DC را اضافه نکنم از Canvas دلفي استفاده کردم.
تابع اول
اين تابع منوي سيتم يک پنجره را برميگرداند (منوي کنترل هم گفته ميشود) آرگومان اول دستگيره پنجره است و آرگومان دوم اگر True باشد منو به حالت اول برميگردد و اگر False باشد يک کپي از منو به عنوان بازگشتي در اختيار شماست.
اين يکي هم يک گزينه به انتهاي منو اضافه ميکند. hMenu دستگيره منو است (که مثلا با تابع GetSystemMenu ميتواند گرفته شود) آرگومان دوم خصيصه منو را مشخص ميکند (ميتوانيد MSDN را براي همه گزينه ها ببينيد) آرگومان بعدي مشخصه منو که منو با آن شناسايي ميشود و آرگومان سوم متني که در منو نمايش داده ميشود (اگر منو با پرچم MF_STRING ساخته شود)
دو پيغام استاندارد هم استفاده شده يکي WM_MEASUREITEM و يکي WM_DRAWITEM که اولي براي تنظيم مشخصات اوليه مثل اندازه و دومي براي رسم آيتم استفاده ميشود براي توضيحات بيشتر به MSDN مراجعه کنيد .
اينهم کد فرم به صورت کامل. البته مثال فقط طريقه را نشان ميدهد و مطمئنا کار خاصي انجام نميدهد.(اين مثال آيکون برنامه را در سيستم منو به عنوان يک آيتم اضافه ميکند و رويداد آن را مديريت ميکند. FOldAppMessage هم متغيري است که فقط محض احتياط اضافه شده.تا اگر در زنجيره پردازش پيغام تابع ديگري هم هست سرش بي کلاه نماند)
حالا اگر بخواهيد از يک فونت خاص استفاده کنيد يا حتي اگر بخواهيد به صورت نقاشي عمل کنيد کار سختي نيست. يعني مشکل فارسي به راحتي حل ميشود (البته در دلفي و به طرز مشابهي سي ).
موفق باشيد
خرگوش کوچولو
( ;<
abolfazlerfani wrote:
سلام
يه سوال داشتم در مورد اينكه چطور ميشه برنامه اي با منوهاي فارسي طوري طراحي كرد
كه منوها در ساير ويندوزهاي عربي ( و يا اونايي كه فارسيساز دارن) درست نمايش داده بشن؟
من برنامه اي با VB توي ويندوزي با فارسي ساز پارسا 2001 (يا پارسا99) نوشتم.
وقتي اونو توي ويندوز "پايا" و يا در ويندوز عربي ساده (بدون فارسي ساز) نصب ميكنم
حروف "گچپژ" فقط روي button ها و textbox ها و label ها درست نمايش داده ميشه ولي
روي منوها بصورت "؟" نمايش داده ميشه؟
به نظر شما چيكار ميشه كرد.؟
سوال دوم:
دنبال يك تابع ميگردم كه كليد فشرده شده را به فارسي تبديل كنه. يكيشو خودم نوشتم كه خيلي مبتدي و ساده است و فقط با پارسا 99 درست كار ميكنه.
لطفا اگه ممكنه منو راهنمايي كنيد.
متشكرم.
url]http://abolfazlerfani.persianblog.com [/url]
در مورد منو بايد بگويم که آنها در حالت عادي يکي از انعطاف پذيرترين ابزار برنامه نويسي هستند اما اگر نخواهيم وارد مباحث پيشرفته شويم راهي براي تغيير دادن فونت منوهايي که با پرچم MF_STRING (منوهاي عادي- مثل منوهاي وي بي يا منوهاي ويژوال سي) مشخص شده اند وجود ندارد.
تنها راه ساده موجود اين است که فونت تمام منوهاي سيستم را عوض کنيم - از طريق Display Properties \Appearance يا از طريف دستکاvي مستقيم در رجيستري (HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics\MenuFont البته اين مقدار به صورت باينري است نه رشته اي- حالا مشکلي پيش ميايد و آن مساله عوض شدن فونت در کل سيستم است -اين براي امثال من که ترجيح ميدهم همه چيز توسط خودم انتخاب شود کمي ناخوشايند است که يک برنامه تنظيمات سيستم مرا به هم بريزد-
راه ديگري هم هست که متاسفانه بدون ترس از Crash در برنامه هاي ويژوال بيسيک نميتوان از آن استفاده کرد
توابع API منو تنها دو تابع دارند که ميتواند اطلاعات مربوط به يک منو و آيتم هاي آن را بگيرد اما هيچکدام راهي براي تغيير فونت ارايه نداده اند.(همه توابع ديگر نيز توسط اين دو تابع قابل جايگزيني هستند منتها با کمي دردسر بيشتر ) يکي GetMenuInfo و يکي GetMenuItemInfo .
شايد براي شما هم مساله اين است که برنامه هايي مثل IncrediMail يا Axialis IconWorkshop (که دومي حتي سيستم منوي آن هم دستکاري شده ) چه طور اينکار را ميکنند؟
آنها همه منوهاي خود را با فلگ MF_OWNERDRAW مشخص ميکنند و در هنگام اجراي برنامه به پيغام هاي WM_MEASUREITEM و WM_DRAWITEM جواب ميدهند که اين کار در وي بي امکان ندارد ( در يک تاپيک دوستي ادعا کرده بود که اين کار - پردازش پيغامهاي Custome در وي بي بدون Hook يا SubClass ممکن است اما هيچوقت اين راه را نشان نداد- متاسفانه- ) به هر حال اگر کسي هست که اين مطلب را ميحواند و ميتواند اين کار را بکند (بدون Hook و SubClass ) آنوقت به من هم ياد بدهد (البته بهتر است وقت خودتان را تلف نکنيد!)
حالا ميرويم سراغ دلفي منو و فونت اگر ديده باشيد دلفي ميتواند فونت ها را براي منو عوض کند اين به معناي نقض گفته هاي بالايي نيست. منو هاي دلفي استاندارد نيستند (گر چه دقيقا با منو هاي استاندارد مشابه هستند) حتي خصيصه Handle که در Help دلفي ادعا شده براي استفاده در توابع Api مفيد است به درد اين کار نميخورد مثلا نميتوان توسط توابع AppendMenu يا InsertMenuItem گزينه اي به اين منو ها اضافه کرد.
و اما مشکل اين دوست. اگر تمام کنترل هاي ديگر مثل Command و يا Label درست نمايش داده ميشوند يعني اينکه فونت مربوط به منوها در برنامه شما نميتواند علائم گچپژ را نشان دهد اما فونت مربوط به کنترل ها ميتواند. (ميتوانيد براي رفع اين مشکل از Display Properties \Appearance فونت منوها را عوض کنيد. (احتمالا فونت کنترل ها MS SansSerif است و فونت مربوط به منو ها Tahoma ) اگر مشکلتان حل نشود من متاسفانه راه ديگري بلد نيستم.
درمورد مساله دوم. ميتوانيد يک تابع ساده (با يک Switch ساده) که کل کد هاي معادل دار را به کد معادلشان تبديل کند را بنويسيد و شايد من مشکل شما را درست متوجه نشده ام؟؟
براي درک بيشتر مساله منو هاي Owner Draw يک مثال با دلفي نوشتم که از چند تا Api ساده استفاده ميکند. چون ميخواستم که توابع مربوط به Device Context يا DC را اضافه نکنم از Canvas دلفي استفاده کردم.
تابع اول
کد:
function GetSystemMenu(hWnd: HWND; bRevert: BOOL): HMENU; stdcall;
function GetSystemMenu; external 'user32.dll' name 'GetSystemMenu';
اين تابع منوي سيتم يک پنجره را برميگرداند (منوي کنترل هم گفته ميشود) آرگومان اول دستگيره پنجره است و آرگومان دوم اگر True باشد منو به حالت اول برميگردد و اگر False باشد يک کپي از منو به عنوان بازگشتي در اختيار شماست.
کد:
function AppendMenu(hMenu: HMENU; uFlags, uIDNewItem: UINT; lpNewItem: PChar): BOOL; stdcall;
function AppendMenu; external 'user32.dll' name 'AppendMenuA';
اين يکي هم يک گزينه به انتهاي منو اضافه ميکند. hMenu دستگيره منو است (که مثلا با تابع GetSystemMenu ميتواند گرفته شود) آرگومان دوم خصيصه منو را مشخص ميکند (ميتوانيد MSDN را براي همه گزينه ها ببينيد) آرگومان بعدي مشخصه منو که منو با آن شناسايي ميشود و آرگومان سوم متني که در منو نمايش داده ميشود (اگر منو با پرچم MF_STRING ساخته شود)
دو پيغام استاندارد هم استفاده شده يکي WM_MEASUREITEM و يکي WM_DRAWITEM که اولي براي تنظيم مشخصات اوليه مثل اندازه و دومي براي رسم آيتم استفاده ميشود براي توضيحات بيشتر به MSDN مراجعه کنيد .
اينهم کد فرم به صورت کامل. البته مثال فقط طريقه را نشان ميدهد و مطمئنا کار خاصي انجام نميدهد.(اين مثال آيکون برنامه را در سيستم منو به عنوان يک آيتم اضافه ميکند و رويداد آن را مديريت ميکند. FOldAppMessage هم متغيري است که فقط محض احتياط اضافه شده.تا اگر در زنجيره پردازش پيغام تابع ديگري هم هست سرش بي کلاه نماند)
کد:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
DelphiCanvas : TCanvas;
FOldAppMessage : TMessageEvent;
procedure OnWM_MEASUREITEM(var Msg : TMessage);message WM_MEASUREITEM;
procedure OnWM_DRAWITEM(var Msg : TMessage);message WM_DRAWITEM;
procedure OnAppMessage (var Msg: TMsg; var Handled: Boolean);
public
{ Public declarations }
end;
var
Form1: TForm1;
const
SC_NEWITEM = 200;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var
SysMnu : HMENU;
begin
SysMnu:=GetSystemMenu(Handle,False);
AppendMenu(SysMnu,MF_SEPARATOR,SC_NEWITEM+1,nil);
AppendMenu(SysMnu,MF_OWNERDRAW ,SC_NEWITEM,nil);
FOldAppMessage:=Application.OnMessage;
Application.OnMessage:=OnAppMessage;
DelphiCanvas:=TCanvas.Create;
end;
procedure TForm1.OnWM_MEASUREITEM(var Msg : TMessage);
var
MeItem : PMeasureItemStruct;
begin
inherited;
if Msg.WParam<>0 then
Exit;
MeItem:=Pointer(Msg.LParam);
if MeItem^.itemID<>SC_NEWITEM then
Exit;
MeItem^.itemHeight:=Application.Icon.Height;
end;
procedure TForm1.OnWM_DRAWITEM(var Msg : TMessage);
var
MePaint : PDrawItemStruct;
Rect : TRect;
begin
inherited;
if Msg.WParam<>0 then
Exit;
MePaint:=Pointer(Msg.LParam);
if MePaint^.itemID<>SC_NEWITEM then
Exit;
DelphiCanvas.Handle:=MePaint^.hDC;
Rect:=MePaint^.rcItem;
if (MePaint^.itemState and ODS_SELECTED)<>0 then
begin
DelphiCanvas.Brush.Color:=clMaroon ;
DelphiCanvas.FillRect(Rect);
DelphiCanvas.Draw(Rect.Left-(Application.Icon.Width div 2)+(Rect.Right-Rect.Left) div 2 ,
Rect.Top,Application.Icon);
end
else
begin
DelphiCanvas.Brush.Color:=clMenu ;
DelphiCanvas.FillRect(Rect);
DelphiCanvas.Draw(Rect.Left-(Application.Icon.Width div 2)+(Rect.Right-Rect.Left) div 2 ,
Rect.Top,Application.Icon);
end;
end;
procedure TForm1.OnAppMessage(var Msg: TMsg; var Handled: Boolean);
begin
Handled:=False;
if Msg.message=WM_SYSCOMMAND then
begin
if (Msg.wParam and $FFFFFFFF ) =SC_NEWITEM then
ShowMessage('You click on my delphi icon. what you want?');
end;
if Assigned(FOldAppMessage) then
FOldAppMessage(Msg,Handled);
end;
end.
حالا اگر بخواهيد از يک فونت خاص استفاده کنيد يا حتي اگر بخواهيد به صورت نقاشي عمل کنيد کار سختي نيست. يعني مشکل فارسي به راحتي حل ميشود (البته در دلفي و به طرز مشابهي سي ).
موفق باشيد
خرگوش کوچولو
( ;<