خوب تو قسمت قبلی مقاله با شیوه و اصولی که ما قراره بر پایه اون برنامه مون رو بسازیم آشنا شدیم. حالا توی این مقاله قراره چیزهایی که گفتیم رو پیاده سازی
کنیم. چی بهتر از این که مقاله رو با یه مثال خیلی ساده جلو ببریم و رفته رفته در مورد کدها بحث کنیم.
قبل از هر چیز همونطور که تو قسمت قبلی مقاله گفتم شما باید جزو یکی از چهار دسته مشخص شده باشید تا بتونید از این سری مقاله ها خوب استفاده کنید. می
دونید این معنیش چیه؟ معنیش اینکه من نمی خوام وقت خودم, و صد البته وقت شما رو با توضیح در مورد کدهای جاوا اسکریپت و HTML هدر بدم چون اگه جاوا
اسکریپت و HTML بلد نیستید واقعا هیچ نیازی ندارید که به این شیوه برنامه نویسی کنید, من بهتون اطمینان میدم که استفاده ی مستقیم از GTK,QT و wxWidget
برای شما بهتر خواهد بود.
در ضمن ما چون قراره از QT استفاده کنیم فرض رو بر این می گیریم که شما با QT آشنا هستید. اگه با QT آشنایی نداشته باشید هم چندان مهم نیست چون بهر
حال فقط از چند تا متد و دو سه تا کلاس و چند خط کد (که به صورت ثابت می تونید کپی/پست کنید) استفاده می کنیم. بهر حال همونطور که گفته بودم قرار نیست
با QT رابط گرافیکی بسازیم. دلیل استفاده از چیزی مثل QT رو تو مقاله ی قبلی توضیح دادم. اگه از GTK یا wxWidget هم بخواید استفاده کنید همین وضعیت رو
خواهید داشت یعنی کافیه فقط با چند خط کد آشنا بشِد و در کل نیار به آشنایی عمیق با این ابزارها نخواهید داشت.
من برای راحتی کار از jQuery استفاده میکنم. شما می تونید از هر فریم ورک دیگه ایی که دوست دارید استفاده کنید, و خوب مسلما می تونید از هیچ فریم ورکی هم
استفاده نکنید. من فقط برای راحت تر شدن کار از jquery استفاده میکنم.
تو مثال اول ما اسمی رو توسط یه تکست باکس از کاربر دریافت میکنیم, و با توجه به اسمی که وارد شده به کاربر سلام می کنیم. این مثال خیلی سادست و اصلا
لازم نیست بخوایم از پایتون یا Webkit استفاده کنیم (یعنی میشه با جاوااسکریپت خالی هم این کارو کرد) ولی برای آشنایی اولیه با جنبه های کار می تونید کدها رو
مطالعه کنید. وقتی پای کار با فایل ها, تنظیمات سیستم, پایگاه داده, و یا برنامه های تیمی بزرگ وسط میاد, اون موقع هستش که واقعا استفاده کردن از پایتون به
درد میخوره چون جاوا اسکریپت برای انجام این جور اعمال محدودیت داره. بذارید قبل از اینکه این مثال رو به شیوه ی خودمون بسازم, اون رو به صورت معمولی با جاوا
اسکریپت و HTML بسازم تا بعدا بتونیم کدها رو باهم مقایسه کنیم. کدهای زیر رو توی فایل sample1.html ذخیره کنید:
<html>
<head>
<title>sample1</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<div>
<label for="name">ur name: </label>
<input type="text" id="name" value="" name="name">
<p style="margin:5px 5px;" id="result"> </p>
<input type="button" id="send" value="Say Hello" name="send">
</div>
<!--------------------------- javascript codes ------------------------------>
<script type="text/javascript" src="./jquery-1.3.2min.js"></script>
<script type="text/javascript">
$("#send").click(function() {
var name = $("#name").val();
$("#result").html("Hi " + name);
});
</script>
<!--------------------------- javascript codes ------------------------------>
</body>
</html>
یه دکمه داریم که رخداد click رو براش در نظر گرفتیم. هر وقت هم که روش کلیک میکنیم به اسمی که توی تکست باکس وارد کردیم سلام میکنه. چن تا چیز هست
که قبل اجرا کردن این فایل با یه مرورگر باید بهش دقت کنید.
- ما از فریم ورک jQuery استفاده کردیم و فرض بر این بوده که فایل اصلی jQuery در پوشه ی جاری موجود باشه. این فایل رو از آدرس زید دانلود کنید:
www.jquery.com- بیاید عادت های بد رو کنار بذاریم. اگه کد جاوااسکریپت شما نیازی نداشت که قبل از ساخته شدن کامل DOM اجرا بشه, پس هیچ نیازی ندارید اون ها رو توی تگ
Head بنویسید. سعی کنید تو این جور موارد همیشه اون ها رو به عنوان آخرین تگ زیر مجموعه ی تگ Body قرار بدید.
این برنامه تحت یه مرورگر (برای مثال فایرفاکس) انجام شد و همه چیز برای ما آماده بود اما اگه بخوایم با کمک پایتون و WebKit این برنامه رو بنویسیم باید همه چیز رو
از اول بسازیم. خیلی سخت نگیرید چون منظور از جمله ی "همه چیز رو از اول بسازیم" حدود 20-30 خط کد بیشتر نیست که اکثرا هم به صورت ثابت می تونید تو برنامه
هاتون استفاده کنید.
حالا قدم به قدم باهم پیش میریم تا در آخر کد نهایی حاصل بشه. ما قرار بود از Qt استفاده کنیم پس باید یه کد ساده بنویسیم که بتونه یه پنجره ی خالی رو به ما
نشون بده:
#!/usr/bin/python
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtWebKit import *
class MyForm(QWidget):
def __init__(self):
QMainWindow.__init__(self)
self.resize(300,110)
if __name__ == "__main__":
app = QApplication(sys.argv)
w = MyForm()
w.show()
sys.exit(app.exec_())
به ماژول هایی که صدا زده شدند خوب دقت کنید. همچنین متوجه باشید که کلاس اصلی برنامه ی ما از شی QWidget ارث برده.
تو مرحله بعدی قبل از اینکه بخوایم کنترل WebKit رو به پنجره اضافه کنیم لازمه که برای حفظ نمای کار یه لایه ی نگه دارنده تو پنجره اضافه کنیم:
def __init__(self):
QMainWindow.__init__(self)
self.resize(300,110)
self.layout = QVBoxLayout(self)
self.layout.setMargin(0)
حالا می تونیم کنترل WebKit رو به این لایه اضاف کنیم. به چند خط کدی که جدیدا اضافه میکنم خوب دقت کنید:
def __init__(self):
QMainWindow.__init__(self)
self.resize(300,110)
self.layout = QVBoxLayout(self)
self.layout.setMargin(0)
self.view = QWebView(self)
self.page = self.view.page()
self.frame = self.page.mainFrame()
self.layout.addWidget(self.view)
حالا شما می تونید با چیزی که الآن ساختید هر صفحه ی HTML ایی که دلتون میخواد رو (چه در هارددیسک خودتون, و چه در روی اینترنت) توی این پنجره نمایش
بدید. اما قبل از اینکار یه نکته هست که باید بهش دقت کنید اونم اینکه, اکثر موتور های رندرینگ صفحات وب, به صورت پیش فرض رنگ پشت زمینه ی صفحه ی شما
رو سفید در نظر میگیرن. چون ما قراره کاری کنیم که همه چیز مثل GUI های معمولی سیستم عامل دلخواه شما در بیاد, باید کاری کنیم که رنگ پس زمینه ی
صفحات شما حالت ناپیدا یا به قولی Transparent به خودش بگیره:
def __init__(self):
QMainWindow.__init__(self)
self.resize(300,110)
self.layout = QVBoxLayout(self)
self.layout.setMargin(0)
self.view = QWebView(self)
self.page = self.view.page()
self.frame = self.page.mainFrame()
self.layout.addWidget(self.view)
palette = self.view.palette()
palette.setBrush(QPalette.Base, Qt.transparent)
self.view.page().setPalette(palette)
self.view.setAttribute(Qt.WA_OpaquePaintEvent, False)
حالا می تونیم با خیال راحت آدرس فایل HTML خودتون رو به WebKit معرفی کنید:
def __init__(self):
QMainWindow.__init__(self)
self.resize(300,110)
self.layout = QVBoxLayout(self)
self.layout.setMargin(0)
self.view = QWebView(self)
self.page = self.view.page()
self.frame = self.page.mainFrame()
self.layout.addWidget(self.view)
palette = self.view.palette()
palette.setBrush(QPalette.Base, Qt.transparent)
self.view.page().setPalette(palette)
self.view.setAttribute(Qt.WA_OpaquePaintEvent, False)
self.view.load(QUrl("sample1.html"))
با اضافه کردن کد بالا, برنامه ایی که قبل تر با جاوااسکریپت نوشته بودیم اجرا میشه. درسته که شما چیزی مثل فایرفاکس نساختید, اما میتونید با همین چند خط کد
صفحات مختلف وب رو توی این پنجره مشاهده کنید. تا اینجای کار ما برنامه ایی نوشتیم که میتونه هر صفحه ی وبی که ما بهش معرفی میکنیم رو برای ما نمایش
بده. کدهایی که تا اینجای کار نوشته شد, بصورت ثابت استفاده میشه پس میتونید بدون دردسر همه رو کپی/پست کنید.
تو مثالی که زدیم, تابعی برای رخداد کلیک در جاوااسکریپت تعیین کرده بودیم که با اجرای اون نوشته ی داخل تکست باکس خونده میشه و برنامه بهش سلام میکنه.
حالا قراره به جای اینکه این کار توسط یه تابع جاوااسکریپت انجام بشه, با صدا زدن یه تابع پایتون همچین کاری رو انجام بدیم. یعنی باید برای هر رخداد در جاوا
اسکریپت (مثل رخداد کلیک) یه تابع متناظر در کدهای پایتون تعریف کنیم. این دقیقا همون روشیه که موقع برنامه نویسی با QT یا GTK ازش استفاده میکردیم.
(سیگنال ها)
روش کار این طوریه:
- یه رخداد کلیک برای دکمه ی موجود در صفحه تعریف میکنیم.
- با اجرای این رخداد, نوشته ی داخل تکست باکس توسط جاوااسکریپت خونده میشه.
- توسط جاوااسکریپت متدی که با پایتون تعریف کردیم رو صدا میزنیم و رشته ی خونده شده رو به عنوان پارامتر بهش ارسال میکنیم.
- متد نوشته شده با پایتون هم با توجه به رشته ایی که به عنوان پارامتر میگیره به اسم مورد نظر سلام میکنه.
حالا بیاید ببنیم چطور باید این کار رو انجام بدیم. اولین کار اینکه متد خودمون رو توی پایتون تعریف میکنیم. به شیوه ایی که کد جاوااسکریپت رو از درون کد پایتون اجرا
میکنیم خوب توجه کنید:
def sayHello(self, message):
code = '$("#result").html("Hi " + "%s");' % message
self.frame.evaluateJavaScript(code)
برای کد پایتون نوع داده ها فرقی نداره اما برای QT که با ++C نوشته شده مهمه که نوع آرگومان رشته ایی باشه یا عددی. پس وقتی داریم از طرف QT داده ایی رو
به پایتون میفرستیم باید مشخص کنیم که نوع داده ایی ما چیه. برای این کار PyQT روش راحتی رو در نظر گرفته, اونم اینه که در یه همچین مواردی میتونید به تابع
خودتون یه decorator مخصوص اضافه کنید:
@pyqtSignature("sayHello(const QString)")
def sayHello(self, message):
code = '$("#result").html("Hi " + "%s");' % message
self.frame.evaluateJavaScript(code)
کاری که توی این مرحله باید انجام بدیم اینه که کلاسی که در پایتون تعریف کردیم رو برای جاواسکریپت در دسترس قرار بدیم تا بتونه از متد های کلاسمون استفاده
کنه. برای این کار به یه خط کد احتیاج داریم:
def __init__(self):
QMainWindow.__init__(self)
self.resize(300,110)
self.layout = QVBoxLayout(self)
self.layout.setMargin(0)
self.view = QWebView(self)
self.page = self.view.page()
self.frame = self.page.mainFrame()
self.layout.addWidget(self.view)
palette = self.view.palette()
palette.setBrush(QPalette.Base, Qt.transparent)
self.view.page().setPalette(palette)
self.view.setAttribute(Qt.WA_OpaquePaintEvent, False)
self.view.load(QUrl("s.html"))
self.frame.addToJavaScriptWindowObject("myform", self)
حالا می تونیم توی کدهای جاوااسکریپت خودمون به روش زیر از شی ایی که در پایتون تعریف کرده بودیم استفاده کنیم تا بتونیم متد مورد نظر خودمون رو صدا بزنیم:
$("#send").click(function() {
var name = $("#name").val();
window.myform.sayHello(name);
});
به روش صدا زدن متد خودمون دقت کنید. همونطور که میبینید شی تعریف شده در پایتون, وقتی برای جاوااسکریپت مورد دسترس قرار میگیره, می تونه به عنوان زیر
مجموعه ی شی window استفاده بشه. اگه یه وقتی به هر نحوی صفحه ی وب ما refresh بشه, دیگه شی ما برای جاوااسکریپت در دسترس نخواهد بود و نیاز
داریم که دوباره اون یه خط کد رو بنویسیم. برای حل این مشکل میتونیم از یکی از رخداد های QT کمک بگیریم تا هر وقت این اتفاق افتاد, خود به خود متدی متناظر با
این رویداد اجرا بشه و در اون متد شی ما به جاوااسکریپت اضافه بشه:
def __init__(self):
QMainWindow.__init__(self)
self.resize(300,110)
self.layout = QVBoxLayout(self)
self.layout.setMargin(0)
self.view = QWebView(self)
self.page = self.view.page()
self.frame = self.page.mainFrame()
self.layout.addWidget(self.view)
palette = self.view.palette()
palette.setBrush(QPalette.Base, Qt.transparent)
self.view.page().setPalette(palette)
self.view.setAttribute(Qt.WA_OpaquePaintEvent, False)
self.view.load(QUrl("s.html"))
self.frame.addToJavaScriptWindowObject("myform", self)
self.connect(self.frame, SIGNAL("javaScriptWindowObjectCleared()"), self.attachObject)
def attachObject(self):
self.frame.addToJavaScriptWindowObject("myform", self)
در آخر هم کد نهایی HMTL/JavaScrip و پایتون ما به صورت زیر در میاد:
#!/usr/bin/python
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtWebKit import *
class MyForm(QWidget):
def __init__(self):
QMainWindow.__init__(self)
self.resize(300,110)
self.layout = QVBoxLayout(self)
self.layout.setMargin(0)
self.view = QWebView(self)
self.page = self.view.page()
self.frame = self.page.mainFrame()
self.layout.addWidget(self.view)
palette = self.view.palette()
palette.setBrush(QPalette.Base, Qt.transparent)
self.view.page().setPalette(palette)
self.view.setAttribute(Qt.WA_OpaquePaintEvent, False)
self.view.load(QUrl("s.html"))
self.frame.addToJavaScriptWindowObject("myform", self)
self.connect(self.frame, SIGNAL("javaScriptWindowObjectCleared()"), self.attachObject)
def attachObject(self):
self.frame.addToJavaScriptWindowObject("myform", self)
@pyqtSignature("sayHello(const QString)")
def sayHello(self, message):
code = '$("#result").html("Hi " + "%s");' % message
self.frame.evaluateJavaScript(code)
if __name__ == "__main__":
app = QApplication(sys.argv)
w = MyForm()
w.show()
sys.exit(app.exec_())
<html>
<head>
<title>sample1</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<div>
<label for="name">ur name: </label>
<input type="text" id="name" value="" name="name">
<p style="margin:5px 5px;" id="result"> </p>
<input type="button" id="send" value="Say Hello" name="send">
</div>
<!--------------------------- javascript codes ------------------------------>
<script type="text/javascript" src="./jquery-1.3.2min.js"></script>
<script type="text/javascript">
$("#send").click(function() {
var name = $("#name").val();
window.myform.sayHello(name);
});
</script>
<!--------------------------- javascript codes ------------------------------>
</body>
</html>
این مثال خیلی ساده بود و نیاز خاصی به کدهای پایتون حس نمیشد. برای تمرین میتونید اسمی که کاربر وارد میکنه رو توسط پایتون توی یه فایل ذخیره کنید, این کاریه
که با جاوااسکریپت نمی تونید انجام بدیم. با این مدل برنامه نویسی ما سعی میکنیم ساخت GUI و یا تعدادی عملیات ساده رو به HTML/Javascript واگذار کنیم, در
عوض کارهای سخت پشت صحنه رو با پایتون انجام میدیم.
این همه ی چیزی که نیاز دارید نبود. حین کار با این شیوه سوال های زیادی براتون پیش میاد که البته همشون قابل حل هستند. مثلا یکیش اینکه چجوری باید برنامه
ایی بنویسید که از چند تا فرم و پنجره ی جداگانه تشکیل شده باشه!
شاید در مورد ریزه کاری های دیگه ایی که این روش از اون ها تبعیت میکنه هم چند تا مقاله ی دیگه نوشتم...