View Full Version : آموزش: در باره Class و User Defined Type (UDT)
mazoolagh
پنج شنبه 08 شهریور 1403, 19:21 عصر
تا بحال تاپیکی در باره این دو
و کاربردشون
و تفاوتهاشون
و این که کی از کدوم یکی بهتره استفاده کنیم،
اینجا ندیدم - حتی در حد یک توضیح ساده.
سعی میکنم بتدریج همون چند خط رو اینجا قلمی کنم.
eb_1345
پنج شنبه 08 شهریور 1403, 19:59 عصر
تا بحال تاپیکی در باره این دو
و کاربردشون
و تفاوتهاشون
و این که کی از کدوم یکی بهتره استفاده کنیم،
اینجا ندیدم - حتی در حد یک توضیح ساده.
سعی میکنم بتدریج همون چند خط رو اینجا قلمی کنم.
:تشویق::تشویق::تشویق:
mazoolagh
شنبه 10 شهریور 1403, 15:37 عصر
با UDT شروع میکنیم که ساده تر هست.
UDT چیزی نیست به جز ترکیبی از چند نوع دیتا (DATA TYPE) دیگه که یک اسم بهش میدیم:
Type Category
ID As Long
Name As String
Description As String
End Type
در تعریف UDT چند نکته هست که باید دقت کنین:
حتما باید در آغاز ماجول تعریف بشه - قبل از هر SUB یا FUNCTION
به صورت دیفالت PUBLIC هست یعنی در کل برنامه در دسترس هست - مگر اینکه مشخص کنین PRIVATE بودنش رو.
اگر در فرم تعریف بشه باید حتما PRIVATE باشه!
mazoolagh
شنبه 10 شهریور 1403, 16:16 عصر
بعد از تعریف UDT ، مثل هر DATA TYPE دیگه در IntelliSense دیده میشه:
156008
156009
mazoolagh
شنبه 10 شهریور 1403, 17:05 عصر
اینجا یک پرسشی ممکنه پیش بیاد که:
ما در اکسس که جدول و رکوردست و ... داریم،
پس چه نیازی به UDT هست؟
بخشی از پاسخ این هست که UDT در واقع یک مفهوم و امکان کدنویسی و مستقل از اکسس هست.
در واقع VBA یک محصول مستقل (STANDALONE) مثل VB نیست،
بلکه مایکروسافت این رو بعنوان یک زبان داخلی برای امکان تعامل و ارتباط بین نرم افزارهای خودش
از دل VB ساخت و توسعه داد.
VBA در تمام نرم افزارهای OFFICE هست و خواهد بود،
ولی در هر کدام از آنها با آبجکتهای همون سروکار داره
و برای کار با دیگر آبجکتها باید رفرنس به کتابخونه مناسب بدین.
مثلا در اکسس چیزهایی مثل TABLE, QUERY, RECORDSET, FORM, REPORT ... از پیش تعریف شده هست،
در اکسل CELL, WORKBOOK, WORKSHEET, ...
در ورد DOCUMENT, PARAGRAPH, FONT, ...
البته VBA منحصر به محصولات مایکروسافت نیست،
مثلا در AUTOCAD هم از زمانی که روی ویندوز آمد بود (در کنار AUTOLISP که از زمان DOS هم بود)
و هنوز هم هست (البته چند سالی هست که دیگه همراه خودش نصب نمیشه و باید کتابخانه اش رو جداگانه دانلود کرد)
خب،
از بحث اصلی دور نشیم.
پس دیدیم که چرا در VBA اکسس، UDT هم با وجود داشتن ساختارها و امکانات آماده مشابه هست.
mazoolagh
شنبه 10 شهریور 1403, 17:16 عصر
متداولترین کاربرد UDT در اکسس زمانی هست که نیاز داریم یک فانکشن بیشتر از یک مقدار برگردونه.
قبلا نمونه برای این داشتیم این هست که توضیح بیشتری نیاز نداره.
وب سرويس (barnamenevis.org) (https://barnamenevis.org/showthread.php?524097-%D9%88%D8%A8-%D8%B3%D8%B1%D9%88%D9%8A%D8%B3) پست 13 رو ببینین
mazoolagh
شنبه 10 شهریور 1403, 17:55 عصر
کاربرد دیگه UDT در کار با روتینهای DLLها و پاس کردن (و گرفتن) مقادیر به (از) اونها هست.
برای این هم نمونه داریم:
راهنمائی در خصوص رنگ فرم (barnamenevis.org) (https://barnamenevis.org/showthread.php?559627-%D8%B1%D8%A7%D9%87%D9%86%D9%85%D8%A7%D8%A6%DB%8C-%D8%AF%D8%B1-%D8%AE%D8%B5%D9%88%D8%B5-%D8%B1%D9%86%DA%AF-%D9%81%D8%B1%D9%85) پست شماره 7 رو ببینین
mazoolagh
سه شنبه 13 شهریور 1403, 20:06 عصر
کلاس (Class) یک مفهوم عمومی برنامه نویس شی گرا هست (object oriented)
وگرچه از نظر داشتن propertyهای متفاوت مشابه UDT هست،
ولی چون میشه از کد هم در اون استفاده کرد (sub و function) ، تواناییهاش و کاربردهاش به مراتب گسترده تر و بیشتر هست،
و به همون نسبت هم نوشتن کلاس دانش بیشتری نسبت به UDT نیاز داره.
سعی میکنم مطلب رو همزمان با نوشتن یک کلاس نمونه کاربردی توضیح بدم (بتدریج).
moustafa
سه شنبه 13 شهریور 1403, 23:18 عصر
تا بحال تاپیکی در باره این دو
و کاربردشون
و تفاوتهاشون
و این که کی از کدوم یکی بهتره استفاده کنیم،
اینجا ندیدم - حتی در حد یک توضیح ساده.
سعی میکنم بتدریج همون چند خط رو اینجا قلمی کنم.
سلام ودرود وسپاس بی نهایت :تشویق::تشویق::تشویق:
mazoolagh
چهارشنبه 14 شهریور 1403, 18:22 عصر
سلام ودرود وسپاس بی نهایت :تشویق::تشویق::تشویق:
با سلام و عرض ادب متقابل
و تشکر از لطف جنابعالی و دیگر دوستان
بحث کلاس رو ادامه میدیم:
================
در VBA نیاز هست که کلاس حتما در یک ماجول جدا و اختصاصی تعریف بشه (class module)،
به یکی از دو روش میتونیم کلاس ماجول بسازیم:
1- از منوی create و انتخاب class module
156024
2- در محیط vba editor
در پنجره project explorer روی اسم برنامه راست کلیک و insert class module :
156025
بر خلاف ماجول های عادی که اسم اون مهم نیست،
یک کلاس اسمش رو از اسم ماجولش میگیره و همینجور که میبینین جداگانه هم نگهداری میشه:
156026
156027
همینجور که دیده میشه قرار هست یک کلاس به اسم TimeSpan بسازیم.
mazoolagh
چهارشنبه 14 شهریور 1403, 18:48 عصر
TimeSpan در واقع نوعی از دیتا (در واقع ابجکت) هست که برای نمایش نگهداری بازه های زمانی به کار میره (با تاریخ اشتباه نگیرین)
و معمولا شامل روز، ساعت، دقیقه و ثانیه است که بنا به نیاز ممکنه میلی ثانیه یا کمتر از اون هم براش تعریف بشه،
یا فقط تا دقیقه باشه.
مطالعه بیشتر در مورد TimeSpan Struct (https://learn.microsoft.com/en-us/dotnet/api/system.timespan?view=netframework-4.8.1#definition)
یک کاربرد timespan در جمع ساعت های کاری هست،
به عنوان مثال جمع کارکرد یک کارمند در ماه.
در این کلاس نمونه فرض رو براین گذاشتیم که دقت زمانی تا میلی ثانیه نیاز هست
پس نیاز داریم برای این کلاس چیزی تعریف کنیم که نشون دهنده روز، ساعت، دقیقه، ثانیه، و میلی ثانیه باشه.
این چیز رو بهش میگن property و این پراپرتی میتونه یک دیتا استاندارد vba یا خودش یک ابجکت دیگه باشه،
که روش کار با دومی کمی تفاوت داره.
برای هر پراپرتی میتونیم پروسیجرهایی (در قالب مشخص و فیکس) بنویسیم
که بشه برای اون پراپرتی مقدار تعیین کرد و یا مقدارش رو خوند.
برای خوندن پروسیجر get ، و برای نوشتن اگر یک مقدار ساده باشه let ،و اگر یک ابجکت باشه set ،
و خود پراپرتی هم میتونه private یا public باشه (بسته به نیاز و کاربرد).
mazoolagh
چهارشنبه 14 شهریور 1403, 19:49 عصر
در اولین گام از تعریف پراپرتی های گفته شده شروع میکنیم:
'======= Class: TimeSpan =======
Option Compare Database
Option Explicit
'======= Declarations =======
Private xDAYS As Long
Private xHOURS As Long
Private xMINUTES As Long
Private xSECONDS As Long
Private xMILLISECONDS As Long
'======= Properties =======
Public Property Get Days() As Long
Days = xDAYS
End Property
Public Property Let Days(ByVal value As Long)
xDAYS = value
End Property
'================
Public Property Get Hours() As Long
Hours = xHOURS
End Property
Public Property Let Hours(ByVal value As Long)
xHOURS = value
End Property
'================
Public Property Get Minutes() As Long
Minutes = xMINUTES
End Property
Public Property Let Minutes(ByVal value As Long)
xMINUTES = value
End Property
'================
Public Property Get Seconds() As Long
Seconds = xSECONDS
End Property
Public Property Let Seconds(ByVal value As Long)
xSECONDS = value
End Property
و به تدریج کلاس رو تکمیل میکنیم.
atf1379
چهارشنبه 14 شهریور 1403, 22:00 عصر
سلام
وقت بخیر
ان شاءالله دوستان علاقمند به یادگیری زبان برنامه نویسی VBA از کنار این آموزش های مفیدی که اساتید عزیز بدون هیچ چشمداشتی برای تهیه اون زحمت می کشن بی تفاوت رد نشن و در یادگیری و بکارگیری اونها کوشا باشن
moustafa
پنج شنبه 15 شهریور 1403, 08:54 صبح
با اجازه استاد من یه مثال ساده از type نوشتم :
Type sp
x As Integer
y As String
z As Boolean
End Type
Function sl(a As Integer, b As Integer, c As String) As sp
sl.x = a - b
If a > b Then
sl.z = True
sl.y = c & ": is true"
ElseIf a < b Then
sl.z = False
sl.y = c & ": is false"
Else
sl.z = zero
sl.y = c & ":is zero"
End If
End Function
w=sl(5,3,"result").x '2
v=sl(5,3,"result").y 'result: is true
u= sl(5,3,"result").z 'True
moustafa
پنج شنبه 15 شهریور 1403, 10:03 صبح
با اجازه برداشت شخصی من :
let و get برای گرفتن یا مقداردهی اعضای خصوصی وغیرقابل دسترسی کلاس توسط یه عضو عمومی یا پالیکه .
اگه عضو خصوصی در دسترس باشه میشه توابع نوشته شده داخل کلاس رو که از اون عضو خصوصی استفاده میکنه دستکاری یا حذفش کرد و یا مقادیر غیر مجاز داد وساختار کلاس رو بهم ریخت بنابراین توسط let و get داده رو به اون عضو میدیم یا میگیرم و اون عضو پشت پرده کارشو انجام میده . در مثال زیر یه محدودیت ورود اعداد بزرگتر از 5 رو به عضو خصوصی دادیم که در حالت عمومی و مستقیم نمیشد این محدودیت رو بوجود اورد .(اشتباهاتم رو لطفا تصحیح فرمائید )
Public Property Let Hours(ByVal value As Long)
if value>5 then
xHOURS = value
else
msgbox "inter greader than 5"
end if
End Property
mazoolagh
یک شنبه 18 شهریور 1403, 17:45 عصر
با اجازه برداشت شخصی من :
let و get برای گرفتن یا مقداردهی اعضای خصوصی وغیرقابل دسترسی کلاس توسط یه عضو عمومی یا پالیکه .
اگه عضو خصوصی در دسترس باشه میشه توابع نوشته شده داخل کلاس رو که از اون عضو خصوصی استفاده میکنه دستکاری یا حذفش کرد و یا مقادیر غیر مجاز داد وساختار کلاس رو بهم ریخت بنابراین توسط let و get داده رو به اون عضو میدیم یا میگیرم و اون عضو پشت پرده کارشو انجام میده . در مثال زیر یه محدودیت ورود اعداد بزرگتر از 5 رو به عضو خصوصی دادیم که در حالت عمومی و مستقیم نمیشد این محدودیت رو بوجود اورد .(اشتباهاتم رو لطفا تصحیح فرمائید )
خواهش میکنم،
با اجازتون این رو در پایان کار این کلاس نمونه برمیگردم و توضیح میدم،
تا پیوستگی مطالب از دست نره.
mazoolagh
یک شنبه 18 شهریور 1403, 17:52 عصر
خب،
تا اینجا برای کلاس فقط چند پراپرتی ضروری رو تعریف کردیم.
برای تکمیل پروسیجرهای خود پراپرتی ها (و بعدا متدها) چند constant هم تعریف میکنیم،
که کدنویسی محاسبات رو برای ما راحتتر میکنه.
Const HoursPerDay As Long = 24
Const MinutesPerHour As Long = 60
Const SecondsPerMinute As Long = 60
Const MillisecondsPerSecond As Long = 1000
Const MinutesPerDay As Long = HoursPerDay * MinutesPerHour ' 1,440
Const SecondsPerHour As Long = SecondsPerMinute * MinutesPerHour ' 3600
Const SecondsPerDay As Long = SecondsPerHour * HoursPerDay ' 86,400
Const MillisecondsPerMinute As Long = MillisecondsPerSecond * SecondsPerMinute ' 60,000
Const MillisecondsPerHour As Long = MillisecondsPerMinute * MinutesPerHour ' 3,600,000
Const MillisecondsPerDay As Long = MillisecondsPerHour * HoursPerDay ' 86,400,000
Const MaxMilliseconds As Long = (2 ^ 31) - 1 ' + 2,147,483,647
Const MinMilliseconds As Long = -MaxMilliseconds
Const MaxSeconds As Long = MaxMilliseconds \ MillisecondsPerSecond ' 2,147,483
Const MinSeconds As Long = -MaxSeconds
Const MaxMinutes As Long = MaxMilliseconds \ MillisecondsPerMinute ' 35,791
Const MinMinutes As Long = -MaxMinutes
Const MaxHours As Long = MaxMilliseconds \ MillisecondsPerHour ' 596
Const MinHours As Long = -MaxHours
Const MaxDays As Long = MaxMilliseconds \ MillisecondsPerDay ' 24
Const MinDays As Long = -MaxDays
مشابه همین const ها رو میتونین در سورس #C این کلاس برای دات نت هم ببینین،
من اسامی رو از همونجا برداشتم (کم و بیش)،
ولی دیتاتایپ ها رو long درنظر گرفتم (32 بیت) بابت گارانتی اجرا در پلتفرم های 32 بیت.
با توجه به آموزشی بودن مبحث اهمیتی نداره (فعلا)
ولی بعدا در موردش توضیح میدهم.
mazoolagh
یک شنبه 18 شهریور 1403, 18:59 عصر
برای محاسبات مبنا رو باید بر روی کوچکترین مقدار زمان (در اینجا میلی ثانیه) بگذاریم،
به این صورت که مقدار یک timespan نهایتا برحسب میلی ثانیه خواهد بود.
این constهای پست 17 بر همین اساس و با توجه با بیشترین مقدار یک 32bit integer محاسبه شدن.
و البته timespan تاریخ نیست بلکه یک بازه زمانی هست و به همین خاطر میتونه مثبت یا منفی باشه.
mazoolagh
یک شنبه 18 شهریور 1403, 19:13 عصر
همچنین چند پراپرتی دیگه هم اضافه میکنیم:
Public Property Get TotalDays() As Double ' read only
TotalDays = TotalMilliseconds / MillisecondsPerDay
End Property
Public Property Get TotalHours() As Double ' read only
TotalHours = TotalMilliseconds / MillisecondsPerHour
End Property
Public Property Get TotalMinutes() As Double ' read only
TotalMinutes = TotalMilliseconds / MillisecondsPerMinute
End Property
Public Property Get TotalSeconds() As Double ' read only
TotalSeconds = TotalMilliseconds / MillisecondsPerSecond
End Property
Public Property Get TotalMilliseconds() As Long ' read only
TotalMilliseconds = xTOTAL_MILLISECONDS
End Property
اینها پروسیجر let ندارن پس read only میشن،
و خب مشخصا مقدار timespan رو بر اساس یک واحد مشخص میکنن.
مثلا 1 روز و 12 ساعت معادل 1.5 روز میشه،
یا 66 دقیقه معادل 1.1 ساعت و ...
برای همین دیگه integer نیستن (به جز TotalMilliseconds که کوچکترین واحد هست)
بعدا در متدهایی که مینویسیم اینها رو در نظر میگیریم.
mazoolagh
یک شنبه 18 شهریور 1403, 19:19 عصر
تا اینجا کد کلاس TimeSpan به این شکل شده:
'======= Class: TimeSpan =======
Option Compare Database
Option Explicit
'======= Constants =======
Const HoursPerDay As Long = 24
Const MinutesPerHour As Long = 60
Const SecondsPerMinute As Long = 60
Const MillisecondsPerSecond As Long = 1000
Const MinutesPerDay As Long = HoursPerDay * MinutesPerHour ' 1,440
Const SecondsPerHour As Long = SecondsPerMinute * MinutesPerHour ' 3600
Const SecondsPerDay As Long = SecondsPerHour * HoursPerDay ' 86,400
Const MillisecondsPerMinute As Long = MillisecondsPerSecond * SecondsPerMinute ' 60,000
Const MillisecondsPerHour As Long = MillisecondsPerMinute * MinutesPerHour ' 3,600,000
Const MillisecondsPerDay As Long = MillisecondsPerHour * HoursPerDay ' 86,400,000
Const MaxMilliseconds As Long = (2 ^ 31) - 1 ' + 2,147,483,647
Const MinMilliseconds As Long = -MaxMilliseconds
Const MaxSeconds As Long = MaxMilliseconds \ MillisecondsPerSecond ' 2,147,483
Const MinSeconds As Long = -MaxSeconds
Const MaxMinutes As Long = MaxMilliseconds \ MillisecondsPerMinute ' 35,791
Const MinMinutes As Long = -MaxMinutes
Const MaxHours As Long = MaxMilliseconds \ MillisecondsPerHour ' 596
Const MinHours As Long = -MaxHours
Const MaxDays As Long = MaxMilliseconds \ MillisecondsPerDay ' 24
Const MinDays As Long = -MaxDays
'======= Declarations =======
Private xDAYS As Long
Private xHOURS As Long
Private xMINUTES As Long
Private xSECONDS As Long
Private xMILLISECONDS As Long
Private xTOTAL_MILLISECONDS As Long
'======= Properties =======
Public Property Get Days() As Long
Days = xDAYS
End Property
Public Property Let Days(ByVal value As Long)
xDAYS = value
End Property
Public Property Get Hours() As Long
Hours = xHOURS
End Property
Public Property Let Hours(ByVal value As Long)
xHOURS = value
End Property
Public Property Get Minutes() As Long
Minutes = xMINUTES
End Property
Public Property Let Minutes(ByVal value As Long)
xMINUTES = value
End Property
Public Property Get Seconds() As Long
Seconds = xSECONDS
End Property
Public Property Let Seconds(ByVal value As Long)
xSECONDS = value
End Property
Public Property Get Milliseconds() As Long
Milliseconds = xMILLISECONDS
End Property
Public Property Let Milliseconds(ByVal value As Long)
xMILLISECONDS = value
End Property
Public Property Get TotalDays() As Double ' read only
TotalDays = TotalMilliseconds / MillisecondsPerDay
End Property
Public Property Get TotalHours() As Double ' read only
TotalHours = TotalMilliseconds / MillisecondsPerHour
End Property
Public Property Get TotalMinutes() As Double ' read only
TotalMinutes = TotalMilliseconds / MillisecondsPerMinute
End Property
Public Property Get TotalSeconds() As Double ' read only
TotalSeconds = TotalMilliseconds / MillisecondsPerSecond
End Property
Public Property Get TotalMilliseconds() As Long ' read only
TotalMilliseconds = xTOTAL_MILLISECONDS
End Property
mazoolagh
یک شنبه 18 شهریور 1403, 19:40 عصر
هر کلاس (در VBA) دو رخداد اصلی داره:
Class_Initialize و Class_Terminate
که از اسمهاشون مشخصه کی اجرا میشن.
همیشه باید وقتی یک چیزی رو از نوع object میسازیم اون رو با set مقدار دهی کنیم.
و همیشه باید در پایان کار به nothing سِت بشن.
کلاس هم برای ما یک ابجکت میسازه،
وقتی بنویسیم dim ts as timespan هنوز ts نامشخص هست تا زمانیکه set ts=new timespan
که در اینجا Class_Initialize اجرا میشه.
و زمانی که بنویسیم set ts=nothing رخداد Class_Terminate تریگر میشه.
معمولا از Class_Initialize برای مقداردهی اولیه متغییرها و پراپرتی ها و .. استفاده میشه (در صورت نیاز).
همچنین اگر در یک کلاس از ابجکتهای دیگه استفاده کرده باشیم (مثلا یک پراپرتی از نوع recordset داشته باشیم)،
باید در این دو رخداد این ابجکتها رو set new و set nothing کنیم.
در اینجا متغییرها و پراپرتی های ما هیچکدوم ابجکت نیستن،
ولی از Class_Initialize برای مقداردهی اولیه استفاده میکنیم و به Class_Terminate هم نیاز نداریم:
Private Sub Class_Initialize()
xDAYS = 0
xHOURS = 0
xMINUTES = 0
xSECONDS = 0
xMILLISECONDS = 0
xTOTAL_MILLISECONDS = 0
End Sub
البته مقادیر عددی با تعریف اولیه خودکار مقدارشون 0 هست،
ولی اینجا کاربرد این رخداد رو خواستیم نشون بدیم.
mazoolagh
یک شنبه 18 شهریور 1403, 19:49 عصر
حالا شروع میکنیم به نوشتن روتین های مورد نیاز.
یک روتین نیاز داریم که از روی مقدار timespan بر حسب میلی ثانیه (که گفتیم پایه همه محاسبات هست)
همه بخشهای زمانی رو محاسبه کنه:
Private Sub Calc_TimeParts()
Dim x As Long
x = Abs(TotalMilliseconds)
xDAYS = x \ MillisecondsPerDay
x = x Mod MillisecondsPerDay
xHOURS = x \ MillisecondsPerHour
x = x Mod MillisecondsPerHour
xMINUTES = x \ MillisecondsPerMinute
x = x Mod MillisecondsPerMinute
xSECONDS = x \ MillisecondsPerSecond
xMILLISECONDS = x Mod MillisecondsPerSecond
End Sub
mazoolagh
یک شنبه 18 شهریور 1403, 20:00 عصر
یک تابع دیگه نیاز داریم که از روی بخشهای زمانی ارزش timespan رو بر حسب میلی ثانیه حساب کنه:
Private Sub Calc_TotalMilliSeconds()
Dim x As Variant
x = _
CDec(Milliseconds) + _
CDec(Seconds * MillisecondsPerSecond) + _
CDec(Minutes * MillisecondsPerMinute) + _
CDec(Hours * MillisecondsPerHour) + _
CDec(Days * MillisecondsPerDay)
If x < MinMilliseconds Or x > MaxMilliseconds Then
Raise_Error 1010
Else
xTOTAL_MILLISECONDS = x
End If
End Sub
در اینجا ابتدا محاسبات رو بر اساس یک متغییر دسیمال انجام میدیم،
و بعد از اینکه مطمئن شدیم در محدوده مجاز long هست اون رو در xTOTAL_MILLISECONDS میریزیم،
وگرنه یک خطای کاستوم میسازیم.
روتین Raise_Error یکی دیگه از روتینهایی هست که باید بنویسیم
و کارش ساخت یک خطای کاستوم با شماره و متنی هست که براش مشخص میکنیم.
اگر در یک ماجول عملیاتی با کلاس انجام بدیم که به خطا برخورد کنه،
میتونیم در error handler اون روتین از این خطای کاستوم که از کلاس میاد استفاده کنیم (درست مثل خطاهای خود اکسس)
وگرنه که خود اکسس پیام میده (همونی که ما براش مشخص کردیم).
mazoolagh
چهارشنبه 21 شهریور 1403, 18:29 عصر
مرحله بعدی درست کردن اسکلت روتین Raise_Error هست
که در پست شماره 23 بهش اشاره شد.
این روتین به ما کمک میکنه که کدهای دیگه ما کوچیک و جمع و جور و نگهداری برنامه ساده تر باشه:
Private Sub Raise_Error( _
ByVal Error_Number As Integer, _
Optional ByVal Source As String = "", _
Optional ByVal value As Variant = Nothing)
Dim Description As String
Select Case Error_Number
Case ...
Description = ...
Source = ...
Case ...
Description = ...
Source = ...
...
...
End Select
Err.Raise _
Number:=vbObjectError + Error_Number, _
Source:="TimeSpan." & Source, _
Description:=Description, _
HelpFile:="TimeSpan"
End Sub
mazoolagh
چهارشنبه 21 شهریور 1403, 18:46 عصر
الان برمیگردیم سر پروسیجرهای Let برای پراپرتی ها و کدها رو برای validation تکمیل میکنیم:
Public Property Let Days(ByVal value As Long)
If value < 0 Or value > MaxDays Then
Raise_Error 1001, "Days", value
Else
xDAYS = value
Calc_TotalMilliSeconds
End If
End Property
Public Property Let Hours(ByVal value As Long)
If value < 0 Or value >= HoursPerDay Then
Raise_Error 1002, "Hours", value
Else
xHOURS = value
Calc_TotalMilliSeconds
End If
End Property
Public Property Let Minutes(ByVal value As Long)
If value < 0 Or value >= MinutesPerHour Then
Raise_Error 1003, "Minutes", value
Else
xMINUTES = value
Calc_TotalMilliSeconds
End If
End Property
Public Property Let Seconds(ByVal value As Long)
If value < 0 Or value >= SecondsPerMinute Then
Raise_Error 1004, "Seconds", value
Else
xSECONDS = value
Calc_TotalMilliSeconds
End If
End Property
Public Property Let Milliseconds(ByVal value As Long)
If value < 0 Or value >= MillisecondsPerSecond Then
Raise_Error 1005, "MilliSeconds", value
Else
xMILLISECONDS = value
Calc_TotalMilliSeconds
End If
End Property
mazoolagh
چهارشنبه 21 شهریور 1403, 19:02 عصر
حالا که بخش پراپرتی ها رو تکمیل کردیم میریم سر وقت متد هایی که نیاز داریم.
هر method یک روتین هست که میتونه یک sub یا function باشه،
تا زمانی که نیازی نیست مقداری برگرده و عملیات روی خود ابجکت انجام میشه از sub استفاده میکنیم.
از متد ساده ای به Zero شروع میکنیم که فقط مقدار ابجکت رو صفر میکنه:
Public Sub Zero()
xDAYS = 0
xHOURS = 0
xMINUTES = 0
xSECONDS = 0
xMILLISECONDS = 0
xTOTAL_MILLISECONDS = 0
End Sub
و یک متد ساده دیگه که ارزش ابجکت رو تغییر علامت میده (مثبت به منفی و برعکس):
Public Sub Negate()
xTOTAL_MILLISECONDS = -xTOTAL_MILLISECONDS
End Sub
mazoolagh
چهارشنبه 21 شهریور 1403, 19:19 عصر
و یک متد From که از روی اجزای زمان timespan رو مقدار دهی کنه:
Public Sub From( _
Optional day As Long = 0, _
Optional hour As Long = 0, _
Optional minute As Long = 0, _
Optional second As Long = 0, _
Optional millisecond As Long = 0)
Days = day
Hours = hour
Minutes = minute
Seconds = second
Milliseconds = millisecond
End Sub
156057
mazoolagh
چهارشنبه 21 شهریور 1403, 19:28 عصر
متد که از روی بخش زمان یک date ، ابجکت رو مقدار دهی میکنه:
Public Sub FromTimeofDate(d As Date)
From _
hour:=DatePart("h", d), _
minute:=DatePart("n", d), _
second:=DatePart("s", d)
End Sub
mazoolagh
چهارشنبه 21 شهریور 1403, 19:36 عصر
متدهایی برای مقداردهی کل ابجکت (و نه یک پراپرتی) از روی یک اندازه از زمان:
Public Sub FromDays(ByVal value As Double)
If value < MinDays Or value > MaxDays Then
Raise_Error 1011, "FromDays", value
Else
xTOTAL_MILLISECONDS = value * MillisecondsPerDay
Calc_TimeParts
End If
End Sub
Public Sub FromHours(ByVal value As Double)
If value < MinHours Or value > MaxHours Then
Raise_Error 1012, "FromHours", value
Else
xTOTAL_MILLISECONDS = value * MillisecondsPerHour
Calc_TimeParts
End If
End Sub
Public Sub FromMinutes(ByVal value As Double)
If value < MinMinutes Or value > MaxMinutes Then
Raise_Error 1013, "FromMinutes", value
Else
xTOTAL_MILLISECONDS = value * MillisecondsPerMinute
Calc_TimeParts
End If
End Sub
Public Sub FromSeconds(ByVal value As Double)
If value < MinSeconds Or value > MaxSeconds Then
Raise_Error 1014, "FromSeconds", value
Else
xTOTAL_MILLISECONDS = value * MillisecondsPerSecond
Calc_TimeParts
End If
End Sub
Public Sub FromMilliSeconds(ByVal value As Long)
If value < MinMilliseconds Or value > MaxMilliseconds Then
Raise_Error 1015, "FromMilliSeconds", value
Else
xTOTAL_MILLISECONDS = value
Calc_TimeParts
End If
End Sub
به نوع مقادیر دقت کنین که
همه double هستن (چون باید بتون اعشار قبول کنن مثل 3.78 روز)
بجز میلی ثانیه - که کوچکترین واحد هست.
mazoolagh
چهارشنبه 21 شهریور 1403, 19:56 عصر
متدهایی برای اضافه (کم) کردن یک مقدار زمانی به (از) ابجکت:
Public Sub AddDays(ByVal day As Double)
Dim x As Variant
x = _
CDec(xTOTAL_MILLISECONDS) + _
CDec(day * MillisecondsPerDay)
If x < MinMilliseconds Or x > MaxMilliseconds Then
Raise_Error 1010, "AddDays"
Else
xTOTAL_MILLISECONDS = xTOTAL_MILLISECONDS + day * MillisecondsPerDay
Calc_TimeParts
End If
End Sub
Public Sub AddHours(hour As Double)
Dim x As Variant
x = _
CDec(xTOTAL_MILLISECONDS) + _
CDec(hour * MillisecondsPerHour)
If x < MinMilliseconds Or x > MaxMilliseconds Then
Raise_Error 1010, "AddHours"
Else
xTOTAL_MILLISECONDS = xTOTAL_MILLISECONDS + hour * MillisecondsPerHour
Calc_TimeParts
End If
End Sub
Public Sub AddMinutes(minute As Double)
Dim x As Variant
x = _
CDec(xTOTAL_MILLISECONDS) + _
CDec(minute * MillisecondsPerMinute)
If x < MinMilliseconds Or x > MaxMilliseconds Then
Raise_Error 1010, "AddMinutes"
Else
xTOTAL_MILLISECONDS = xTOTAL_MILLISECONDS + minute * MillisecondsPerMinute
Calc_TimeParts
End If
End Sub
Public Sub AddSeconds(second As Double)
Dim x As Variant
x = _
CDec(xTOTAL_MILLISECONDS) + _
CDec(second * MillisecondsPerSecond)
If x < MinMilliseconds Or x > MaxMilliseconds Then
Raise_Error 1010, "AddSeconds"
Else
xTOTAL_MILLISECONDS = xTOTAL_MILLISECONDS + second * MillisecondsPerSecond
Calc_TimeParts
End If
End Sub
Public Sub AddMilliSeconds(millisecond As Long)
Dim x As Variant
x = _
CDec(xTOTAL_MILLISECONDS) + _
CDec(millisecond)
If x < MinMilliseconds Or x > MaxMilliseconds Then
Raise_Error 1010, "AddMilliSeconds"
Else
xTOTAL_MILLISECONDS = xTOTAL_MILLISECONDS + millisecond
Calc_TimeParts
End If
End Sub
mazoolagh
چهارشنبه 21 شهریور 1403, 20:09 عصر
متدهای ضرب و تقسیم:
Public Sub Multiply(factor As Double)
Dim x As Variant
x = CDec(xTOTAL_MILLISECONDS) * factor
If x < MinMilliseconds Or x > MaxMilliseconds Then
Raise_Error 1010, "Multiply"
Else
xTOTAL_MILLISECONDS = xTOTAL_MILLISECONDS * factor
Calc_TimeParts
End If
End Sub
Public Sub Divide(factor As Double)
Dim x As Variant
x = CDec(xTOTAL_MILLISECONDS) / factor
If x < MinMilliseconds Or x > MaxMilliseconds Then
Raise_Error 1010, "Divide"
Else
xTOTAL_MILLISECONDS = xTOTAL_MILLISECONDS / factor
Calc_TimeParts
End If
End Sub
mazoolagh
چهارشنبه 21 شهریور 1403, 20:15 عصر
متد ToString :
Public Enum ToStringOptions
Full = 0 ' Day HH:MM:SS.mmm
Day_HH = 1
Day_HHMM = 2
Day_HHMMSS = 3
HH = 4
HHMM = 5
HHMMSS = 6
HHMMSSmmm = 7
End Enum
Public Function ToString(Optional output As ToStringOptions = Full) As String
Dim sign As String
If xTOTAL_MILLISECONDS < 0 Then
sign = "-"
Else
sign = ""
End If
Select Case output
Case 0 ' Full
ToString = sign & _
Days & _
format(Hours, " 00") & ":" & _
format(Minutes, "00") & ":" & _
format(Seconds, "00") & "." & _
format(Milliseconds, "000")
Case 1 ' Day _HH
ToString = sign & _
Days & _
format(Hours, " 00")
Case 2 ' Day HH:MM
ToString = sign & _
Days & _
format(Hours, " 00") & ":" & _
format(Minutes, "00")
Case 3 ' Day HH:MM:SS
ToString = sign & _
Days & _
format(Hours, " 00") & ":" & _
format(Minutes, "00") & ":" & _
format(Seconds, "00")
Case 4 ' HH
ToString = sign & _
format(Hours, "00")
Case 5 ' HH:MM
ToString = sign & _
format(Hours, "00") & ":" & _
format(Minutes, "00")
Case 6 ' HH:MM:SS
ToString = sign & _
format(Hours, "00") & ":" & _
format(Minutes, "00") & ":" & _
format(Seconds, "00")
Case 7 ' HH:MM:SS.mmm
ToString = sign & _
format(Hours, "00") & ":" & _
format(Minutes, "00") & ":" & _
format(Seconds, "00") & "." & _
format(Milliseconds, "000")
End Select
End Function
mazoolagh
چهارشنبه 21 شهریور 1403, 20:24 عصر
این بخش اول آموزش کلاس در VBA بود.
تا اینجا اگر اشکالی دیده میشه،
یا مطلبی از چشم دور مونده ممنون میشم مطرح کنین .
همچنین مطلب تکمیلی اگر دارین لطف کنین اینجا بگذارین یا لینک بدین.
mazoolagh
چهارشنبه 21 شهریور 1403, 20:30 عصر
من یه مثال ساده از type نوشتم :
Type sp
x As Integer
y As String
z As Boolean
End Type
Function sl(a As Integer, b As Integer, c As String) As sp
sl.x = a - b
If a > b Then
sl.z = True
sl.y = c & ": is true"
ElseIf a < b Then
sl.z = False
sl.y = c & ": is false"
Else
sl.z = zero
sl.y = c & ":is zero"
End If
End Function
w=sl(5,3,"result").x '2
v=sl(5,3,"result").y 'result: is true
u= sl(5,3,"result").z 'True
مثال خوبی هست.
وقتی تایپ یک تابع رو UDT میگذاریم، معمولا به بیشتر از از پراپرتی اون نیاز داریم.
پس بهتر هست که برای جلوگیری از تکرار دوباره تابع، اول یک متغییر از اون نوع تعریف
و بعد خروجی تابع رو به اون منسوب کنیم.
mazoolagh
چهارشنبه 21 شهریور 1403, 20:36 عصر
با اجازه برداشت شخصی من :
let و get برای گرفتن یا مقداردهی اعضای خصوصی وغیرقابل دسترسی کلاس توسط یه عضو عمومی یا پالیکه .
اگه عضو خصوصی در دسترس باشه میشه توابع نوشته شده داخل کلاس رو که از اون عضو خصوصی استفاده میکنه دستکاری یا حذفش کرد و یا مقادیر غیر مجاز داد وساختار کلاس رو بهم ریخت بنابراین توسط let و get داده رو به اون عضو میدیم یا میگیرم و اون عضو پشت پرده کارشو انجام میده . در مثال زیر یه محدودیت ورود اعداد بزرگتر از 5 رو به عضو خصوصی دادیم که در حالت عمومی و مستقیم نمیشد این محدودیت رو بوجود اورد .(اشتباهاتم رو لطفا تصحیح فرمائید )
Public Property Let Hours(ByVal value As Long)
if value>5 then
xHOURS = value
else
msgbox "inter greader than 5"
end if
End Property
اشتباه نیست،
ولی دقیق هم نیست!
فکر کنم در پست ها و کدهای نمونه مشخص هست.
moustafa
پنج شنبه 22 شهریور 1403, 21:34 عصر
این بخش اول آموزش کلاس در VBA بود.
تا اینجا اگر اشکالی دیده میشه،
یا مطلبی از چشم دور مونده ممنون میشم مطرح کنین .
همچنین مطلب تکمیلی اگر دارین لطف کنین اینجا بگذارین یا لینک بدین.
با عرض تشکروخسته نباشین .شی گرائی در وی بی ا شامل ارث بری هم میشه؟
moustafa
پنج شنبه 22 شهریور 1403, 21:36 عصر
مثال خوبی هست.
وقتی تایپ یک تابع رو UDT میگذاریم، معمولا به بیشتر از از پراپرتی اون نیاز داریم.
پس بهتر هست که برای جلوگیری از تکرار دوباره تابع، اول یک متغییر از اون نوع تعریف
و بعد خروجی تابع رو به اون منسوب کنیم.
با تشکر خوب متوجه نشدم ممکنه با یه مثال بیشتر توضیح بدین
mazoolagh
شنبه 24 شهریور 1403, 09:11 صبح
با تشکر خوب متوجه نشدم ممکنه با یه مثال بیشتر توضیح بدین
Type sp
x As Integer
y As String
z As Boolean
End Type
Function sl(a As Integer, b As Integer, c As String) As sp
sl.x = a - b
If a > b Then
sl.z = True
sl.y = c & ": is true"
ElseIf a < b Then
sl.z = False
sl.y = c & ": is false"
Else
sl.z = zero
sl.y = c & ":is zero"
End If
End Function
'=====================
DIM Q AS sp
Q= sl(5,3,"result")
DEBUG.PRINT Q.x , Q.y , Q.z
mazoolagh
شنبه 24 شهریور 1403, 09:14 صبح
با عرض تشکروخسته نباشین .شی گرائی در وی بی ا شامل ارث بری هم میشه؟
پاسخ کوتاه: نه!
ولی سر فرصت بیشتر توضیح میدم.
vBulletin® v4.2.5, Copyright ©2000-1404, Jelsoft Enterprises Ltd.