PDA

View Full Version : سوال: آیا راهی هست که شکل ظاهری دکمه ای رو خودم طراحی کنم و از TButton هم مشتق بگیرم؟



mbshareat
یک شنبه 27 فروردین 1391, 20:17 عصر
سلام به همه دوستان عزیز.
من می خوام یه دکمه داشته باشم که شکل ظاهریش رو خودم طراحی کنم ولی یه کامپوننت کامل از نوع TGraphicControl نباشه و فقط ترسیم ظاهرش رو تغییر بدم.
در بحث دکمه با کپشن عمودی (http://barnamenevis.org/showthread.php?334215-%DA%A9%D9%BE%D8%B4%D9%86-%D8%B9%D9%85%D9%88%D8%AF%DB%8C-%D8%A8%D8%A7%D8%AA%D9%86&highlight=Button+%2B%D8%B9%D9%85%D9%88%D8%AF%DB%8C ) یه روش اومده ولی به محض کلیک روی دکمه همه چیز خراب میشه و دکمه باز به حالت استاندارد بر می گرده!
ظاهرا WMPaint همه چیز رو به عهده نمی گیره.(دکمه OnPaint نداره!)
من OnPaint رو هم جستجو دادم چیز خاصی گیرم نیومد.
برای توضیح اجمالی باید بگم جناب SAASTN چنین کدی برای ترسیم یک خط بر روی دکمه دارند(البته شما همه کد رو ببینید!):
procedure TVerticalButton.WMPaint(var Message: TWMPaint);
begin
inherited;
FCanvas.Pen.Color := clBlack;
FCanvas.MoveTo(0, 0);
FCanvas.LineTo(10, 10);
end;

SAASTN
دوشنبه 28 فروردین 1391, 00:59 صبح
در بحث دکمه با کپشن عمودی یه روش اومده ولی به محض کلیک روی دکمه همه چیز خراب میشه و دکمه باز به حالت استاندارد بر می گرده!
من تو 7 با Visual Style و بدون اون چک کردم، همچین اتفاقی نمی افته، و اون خطه محکم سر جاشه. در مورد XP مطمئن نیستم.
اما اگه احتمالا مشکل در مورد تشخیص فشرده شدن دکمه است:
procedure TVerticalButton.WMPaint(var Message: TWMPaint);
var
State: Integer;
UNCHECKED: Boolean;
CHECKED: Boolean;
INDETERMINATE: Boolean;
PUSHED: Boolean;
FOCUS: Boolean;
begin
inherited;
FCanvas.Pen.Color := clBlack;
FCanvas.MoveTo(0, 0);
FCanvas.LineTo(10, 10);

State := SendMessage(Handle, BM_GETSTATE, 0, 0);
UNCHECKED := (State and BST_UNCHECKED) = BST_UNCHECKED;
CHECKED := (State and BST_CHECKED) = BST_CHECKED;
INDETERMINATE := (State and BST_INDETERMINATE) = BST_INDETERMINATE;
PUSHED := (State and BST_PUSHED) = BST_PUSHED;
FOCUS := (State and BST_FOCUS) = BST_FOCUS;
if UNCHECKED then Form1.Memo1.Lines.Add('UNCHECKED');
if CHECKED then Form1.Memo1.Lines.Add('CHECKED');
if INDETERMINATE then Form1.Memo1.Lines.Add('INDETERMINATE');
if PUSHED then Form1.Memo1.Lines.Add('PUSHED');
if FOCUS then Form1.Memo1.Lines.Add('FOCUS');

if not(UNCHECKED or CHECKED or INDETERMINATE or PUSHED or FOCUS) then
Form1.Memo1.Lines.Add(IntToStr(State));
end;

mbshareat
دوشنبه 28 فروردین 1391, 08:56 صبح
سلام جناب SAASTN
دکمه تو دلفی من Style نداره و من در XP آزمایش کردم.
کدتون رو گذاشتم فقط یکسری گزارش تو Memo ریخت. اما جواب سوالم رو اگه لطف کنین ممنون می شم. یا حد اقل بفرمایین نمیشه!
من می تونم از TImage استفاده کنم ولی Focused نداره و همچنین Default و Cancel!

Ananas
دوشنبه 28 فروردین 1391, 09:55 صبح
سلام همشهری بزرگوار.
میگم نمیشه با panel کار کنی؟ خط دورشم که راحت میشه برداشت. با استفاده از HDC هم که می تونی روش ترسیم کنی. فکر میکنم بتونی Alpha هم براش بگذاری که میشه گفت یک جور ماسک هست که تعیین کنه کجاش دیده بشه و یا نشه و اینکه کلیک رو کدوم قسمت هاش کار کنه. فقط یک اشکالی ممکنه داشته باشه اینکه در حین اجرای برنامه ممکنه لازم باشه دوباره ماسک و رنگ بهش بدی، که خیلی هم سخت نیست تو قسمت onPainte می تونی کدش رو بنویسی.

SAASTN
چهارشنبه 30 فروردین 1391, 02:14 صبح
دکمه تو دلفی من Style نداره و من در XP آزمایش کردم.
منظورم این بود که توی 7 نمایش Visual Style رو غیر فعال کردم تا با تم 98 چک کنم. توی اون وضعیت هم مشکلی نداشت. من به XP دسترسی ندارم تا چکش کنم.

کدتون رو گذاشتم فقط یکسری گزارش تو Memo ریخت.
اون کد برای تشخیص اینه که در زمان ترسیم دکمه در چه وضعیتیه، مثلا فوکوس هست یا نه، فشرده شده یا نه.

من می تونم از TImage استفاده کنم ولی Focused نداره و همچنین Default و Cancel!
چیزی که می خوای وراثت چندگانه از دو کلاس مختلفه که تو دلفی امکانپذیر نیست.
ولی من هنوزم متوجه نمیشم چرا کار نمی کنه! ولی برای این که کلا همه ترسیم های قبلی رو بکنی این رو هم یه امتحان بکن:
procedure TVerticalButton.WMPaint(var Message: TWMPaint);
var
State: Integer;
UNCHECKED: Boolean;
CHECKED: Boolean;
INDETERMINATE: Boolean;
PUSHED: Boolean;
FOCUS: Boolean;
PS: TPaintStruct;
begin
// inherited;
BeginPaint(Handle, PS);
FCanvas.Pen.Color := clBlack;
FCanvas.MoveTo(0, 0);
FCanvas.LineTo(10, 10);
EndPaint(Handle, PS)


// State := SendMessage(Handle, BM_GETSTATE, 0, 0);
// UNCHECKED := (State and BST_UNCHECKED) = BST_UNCHECKED;
// CHECKED := (State and BST_CHECKED) = BST_CHECKED;
// INDETERMINATE := (State and BST_INDETERMINATE) = BST_INDETERMINATE;
// PUSHED := (State and BST_PUSHED) = BST_PUSHED;
// FOCUS := (State and BST_FOCUS) = BST_FOCUS;
// if UNCHECKED then Form1.Memo1.Lines.Add('UNCHECKED');
// if CHECKED then Form1.Memo1.Lines.Add('CHECKED');
// if INDETERMINATE then Form1.Memo1.Lines.Add('INDETERMINATE');
// if PUSHED then Form1.Memo1.Lines.Add('PUSHED');
// if FOCUS then Form1.Memo1.Lines.Add('FOCUS');
//
// if not(UNCHECKED or CHECKED or INDETERMINATE or PUSHED or FOCUS) then
// Form1.Memo1.Lines.Add(IntToStr(State));
end;

این دیگه در هر شرایطی فقط یه مستطیل خاکستری با یه خط تو گوشش میکشه. با حذف inherited ترسیماتی که توسط TCustomButton یا جد و آبادش انجام میشده لغو میشه. البته وجود BeginPaint و EndPaint الزامیه، در غیر اینصورت WM_Paint بطور پیاپی برای کنترل ارسال میشه و عملا برنامه هنگ می کنه. (که البته علتش رو نمی دونم!)

mbshareat
چهارشنبه 30 فروردین 1391, 10:57 صبح
سلام
من کد قبلی شما رو بدون
Inherited; اجرا کردم بدون هنگ کار می کنه!:
procedure TVerticalButton.WMPaint(var Message: TWMPaint);
begin
// inherited;
FCanvas.Pen.Color := clBlack;
FCanvas.MoveTo(0, 0);
FCanvas.LineTo(10, 10);
end;
ولی مشکل مشترک هر دو شیوه ترسیم اینه که وقتی برنامه رو اجرا می کنم ابتدای امر تصویر فرم پایین فرم اصلی!! روی دکمست!
85912

mbshareat
چهارشنبه 30 فروردین 1391, 11:01 صبح
علیکم السلام و رحمة الله و برکاته
دلفی من متاسفانه برای Panel رویداد OnPaint نداره و اگر هم داشت معلوم نبود مشکل فوق الذکر رو نداشته باشه!

SAASTN
چهارشنبه 30 فروردین 1391, 13:05 عصر
من کد قبلی شما رو بدون Inherited اجرا کردم بدون هنگ کار می کنه!:
برای اطمینان بیشتر کد رو بصورت زیر چک کن ببین شمارند بدون توقف بالا میره یا نه. توجه داشته باش که Counter نباید بصورت متغیر محلی تعریف بشه چون تو هربار اجرای روال صفر میشه:
var
Counter: Integer;
procedure TVerticalButton.WMPaint(var Message: TWMPaint);
begin
FCanvas.Pen.Color := clBlack;
FCanvas.MoveTo(0, 0);
FCanvas.LineTo(10, 10);
Form1.Caption := IntToStr(Counter);
Inc(Counter);
end;

اگر نرفت که دیگه نیازی به اون BeginPaint و ... نیست، البته ممکنه کنترل تو ورژنهای مختلف ویندوز رفتار متفاوتی داشته باشه، اگه برنامت قراره منتشر بشه بهتره تو چندتا ویندوز مختلف چکش کنی. یه احتمال ضعیفتر هم اینه که پیاده سازی TCustomButton تو ورژنای مختلف دلفی تفاوت داشته باشه، من با XE تست کردم.

ولی مشکل مشترک هر دو شیوه ترسیم اینه که وقتی برنامه رو اجرا می کنم ابتدای امر تصویر فرم پایین فرم اصلی!! روی دکمست!
خوب وقتی inherited رو بر می داریم دیگه هیچ کدوم از توابع ترسیمی اجداد کنترل اجرا نمی شن. یعنی باید کلیه ترسیمات رو خودمون انجام بدیم، و اینکه اون خطه ترسیم شده خودش نشون میده که کار درست انجام شده. احتمالا شما کنترل رو نصب کردی و در زمان دیزاین رو فرمت گذاشتی یا توی OnCreate فرم، کنترل رو ایجاد کردی که اون نتیجه رو گرفتی، من در زمان اجرا و تو OnClick یه باتن دیگه کنترل رو ایجاد می کنم و چون قبلش خود فرم ترسیم شده محل کنترل به رنگ پس زمینه در اومده.

mbshareat
چهارشنبه 30 فروردین 1391, 13:30 عصر
سلام علیکم
جناب SAASTN چقدر به شما زحمت دادم.
این دو خط کدی که گذاشتین کاری به ترسیم مجدد نداره. من این یک خط رو اضافه کردم:

FCanvas.Rectangle(FCanvas.ClipRect);
دکمه همش داره ترسیم میشه(از اونجایی که خط روش مرتب چشمک می زنه!).
البته برنامه قفل نمی کنه.(یکی از مزایای Win 7 که وقتی نصب کرده بودم فهمیدم اینه که دائما بی هیچ دلیل واضحی قفل می کنه!!)
من دکمه رو توی OnCreate ایجاد کرده بودم و حالا که در OnClick ایجاد کردم مشکل بالا پیش نیومد ولی وقتی فرم بره زیر چیزی تصویر دکمه خراب میشه.
البته این اواخر چند تا تاپیک دیگه رو هم نگاه می کردم که یادم نمیاد در مورد چی بود دوستان گفته بودند که Paint همیشه کنترل رو ترسیم نمی کنه.
راستش برام مهم نیست که حتما از دکمه استفاده کنم. اگه از Image هم بشه استفاده کنم ولی Focused بشه براش گذاشت خوبه! (البته با روشی برای فهمیدن دریافت فوکوس)
من الان یه دکمه دارم که از نوع TGraphicControl هستش اما فوکوس براش تعریف نشده. آیا میشه تست فوکوس براش بذارم؟

SAASTN
جمعه 01 اردیبهشت 1391, 00:24 صبح
آقا شرمنده که دیر شد

این دو خط کدی که گذاشتین کاری به ترسیم مجدد نداره. من این یک خط رو اضافه کردم:
منم نگفتم ربط داره، اونو برای کنترل گذاشتم که بصورت ویژوال ببینیم که کنترل بدون دلیل بطور مرتب ترسیم میشه. که خودت دیدی Fliker داره.

من دکمه رو توی OnCreate ایجاد کرده بودم و حالا که در OnClick ایجاد کردم مشکل بالا پیش نیومد ولی وقتی فرم بره زیر چیزی تصویر دکمه خراب میشه.
اینم که می گی با تغییر محل ایجاد کنترل این رفتار تغییر می کنه یکم عجیب به نظر میاد و البته روی سیستم من اتفاق نمی افته. و اون قضیه update نشدن بعد از خارج شدن از زیر فرم دیگه هم نباید اتفاق بیافته. چون به این ترتیب کلا فلسفه کامپوننت نویسی زیر سوال میره. حتی اون خطه هم پاک میشه؟

من الان یه دکمه دارم که از نوع TGraphicControl هستش اما فوکوس براش تعریف نشده. آیا میشه تست فوکوس براش بذارم؟
تا جایی که من می دونم نه. در واقع فوکوس گرفتن کنترل از طریق کیبورد بوسیله اضافه کردن WS_TABSTOP به Style در CreateParams و ارسال اون استایل به CreateWindowEx اتفاق میافته. ولی تو GraphicControl ها چون نیازی دیده نشده که هندل ویندوزی داشته باشن، اساسا این مراحل طی نمی شه.

به هر صورت من نمی دونم چرا اصرار داری از TImage استفاده کنی. اگر هم با باتن مشکل داری بهترین گزینه TCustomControl هست.

mbshareat
جمعه 01 اردیبهشت 1391, 10:01 صبح
سلام
من از ترکیب پنل و ایمیج استفاده کردم . یه کلاس از نوع پنل و یک کلاس از نوع ایمیج تعریف کردم و در کلاس اول از کلاس دوم استفاده کردم.
وقتی توی یک دکمه یه نمونه از کلاس دوم توی یک پنل معمولی استفاده می کنم مشکلی ندارم ولی وقتی در همین دکمه از کلاس اول یک نمونه می سازم فقط پنل بدون نمونه کلاس دوم درست می کنه. نکته عجیب دیگه اینکه Invalidate باعث اجرای Paint نمیشه.
امیدوارم از کدم خندتون نگیره:
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,ExtCtrls, StdCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
Panel1: TPanel;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TButImg = Class(TImage)
Public
Caption:String;
Procedure Paint;OverLoad;
End;
TButPanel = Class(TPanel)
Public
BI:TButImg;
Caption:String;
constructor Create(AOwner: TComponent);
destructor Destroy();
End;
var
Form1: TForm1;

implementation

{$R *.dfm}

{ TButImg }

procedure TButImg.Paint;
Var
W:Byte;
begin
Picture.Bitmap.Width:=Width;
Picture.Bitmap.Height:=Height;
Picture.Bitmap.Canvas.Rectangle(Picture.Bitmap.Can vas.ClipRect);
Picture.Bitmap.Canvas.Font.Name:='Tahoma';
Picture.Bitmap.Canvas.Font.Size:=12;
W:=Picture.Bitmap.Canvas.TextWidth(Caption);
Picture.Bitmap.Canvas.TextOut
(Width div 2- W Div 2,2,Caption);
end;

procedure TForm1.Button1Click(Sender: TObject);
Var
BI:TButImg;
BP:TButPanel;
begin
BI:=TButImg.Create(self);
BI.Parent:=Panel1;
BI.Width:=100;
BI.Height:=30;
BI.Caption:='تایید';
BI.Paint;
BP:=TButPanel.Create(Self);
BP.Parent:=Self;
BP.Width:=200;
BP.Height:=30;
BP.Caption:='تایید';
end;
constructor TButPanel.Create(AOwner: TComponent);
begin
inherited;
BI:=TButImg.Create(self.Parent);
BI.Parent:=Self;
BI.AutoSize:=True;
BI.Left:=0;
BI.Top:=0;
BI.Width:=Width;
BI.Height:=Height;
BI.Caption:=Caption;
BI.Paint;
end;
destructor TButPanel.Destroy();
begin
BI.Free;
inherited Destroy();
end;

end.