گام به گام ساختن notepad+ با پایتون ( قسمت اول)

گام به گام ساختن notepad+ با پایتون ( قسمت اول)

سلام!

مقدمه ای که به نظرم خوندنش خالی از لطف نیست ، ولی اگه حوصله نداری میتونی ردش کنی!

داشتم توی محتوا های جادی می گشتم که به یه سری‌ویدئو ی جالب بخوردم : « بستون » . توی این سری فیلم جادی شروع کرده بود به ساختن یه چیزی شبیه پلتفرم ثبت و رصد مخارج و درآمد هاش با پایتون  ، نکته این بود که از تمام مراحل هم فیلم گرفته بود ! از خراب شدنش ، از سرچ کردن هاش  و خلاصه از همه چیز ...
این شد که گفتم خب چه حرکت جالبی! من که خب قطعا به اندازه ی جادی مهارت ندارم ، ویدئو ضبط کن هم که نیستم ، چه‌کنم چه‌کار کنم؟
برم از مراحل یه پروژه قدم به قدم بنویسم  . سنگ مفت ، گنجشک هم مفت! یا خوب میشه که چه عالی ! یا بد میشه که اصلا مهم نیست :|

حالا فقط میموند که  چی باشه؟
دقت کردید به notepad  و  gedit ؟  به فرقشون توجه کنید ... gedit رو حتی میشه یجور code editor ابتدایی دونست ، اما نوت پد ؟! نوت پد چی؟ خب نمیدونم notepadدقیقا چیه 🤣 ولی خب در این حد میشه گفت « یه چیزیه که نهایتا حالت تاریک و  روشن داره  و میشه توش چیز میز نوشت ، بعدم با همه ی فرمت ها ذخیره‌ش کرد :| » . ایده اینه که یه چیزی بسازیم ، بهتر از  notepad ، شبیه gedit و ضعیف تر از notepad++ .

مقدمه ی اصلی ( بخونید که بدونید چه خبره )

خب ، اگه مقدمه ی نسبتا طولانی بالا رو نخوندید ( که بهتون حق میدم ) ، خلاصه ی کاری که میخوایم بکنیم اینه که قدم به قدم یه نسخه ی بهتر از notepad رو  ، با پایتون بسازیم . 
نکته هم اینه که « من قبلا این کار رو نکردم ، در نتیجه امکان داره وسط کار خراب بشه و کلا بنیاد کار رو عوض کنیم » اما چیزی که بهتون اطمینان میدم اینه که چیز های خیلی خیلی خوبی رو یاد خواهیم گرفت . در نتیجه حتی اگه پروژه کلا شکست هم بخوره باز برای شما ی خواننده اتفاق بدی نیفتاده ، این وسط ها کلی کار هست که باید بکنیم و از هر کدومشون هم چیز های خوبی میتونه دربیاد ( البته به نظر خودم ) .

مقدمه بسه ، بریم شروع کنیم .
 

چی میخوایم؟

فعلا ابزار هایی که احتیاج داریم این ها هستن (غیر از پایتون 😁) :

  • PySimpleGUI  - برای نوشتن UI
  • subprocess  - برای کامپایل کردن و این جور کارا ( که احتمالا برای چند تا زبان یه همچین قابلیتی رو بذاریم

فعلا در همین حد به نظم کافیه ، تا بعد ببینیم چی به کارمون میاد .
subprocess  که پیش‌فرض پایتونه اما PySimpleGUI رو باید نصب کنید . خیلی بعیده ندونه کسی ، ولی خب برای احتیاط می‌نویسم :

windows :

pip install PySimpleGUI 

linux :

!pip install PySimpleGUI

دلیل استفاده مون از  PySimpleGUI کیفیت بیشتر و امکانات بهترش نسبت به tkinter و سادگی‌ش نسبت به پای‌کیوت و پای‌سایده 

 

استارت

خب ، بریم که شروع کنیم .
اول از همه بریم ابتدایی ترین عضو برنامه رو داشته باشیم . پنجره ی برنامه .

import PySimpleGui as gui
window = gui.Window("title",[layout] , (size))

این یه طرح کلی از چیزی که میخوایمه.  اول از همه که خب داریم یه آبجکتی به اسم window میسازیم . همونطور که از اسمش برمیاد ، این همون پنجره ی برنامه‌س . 

کلاسِ Window که ما ازش یه آبجکت ساختیم ، یه تابع سازنده ( init ) داره که (غیر از self) چند تا آرگومان رو باید دریافت کنه .
ما از بین این آرگومان ها ،  سه تاشون رو در حال حاضر احتیاج داریم که title ، layout  و size هستن  .  هر کدوم هم قاعدتا یه چیزی رو تعیین می کنن .  

  • title ->  اسمی که قراره بالای پنجره بیاد
  • size -> اندازه ی پنجره
  • layout -> اجزای برنامه که داخل window هستن
    • مِنو ها ،  باتن ها و هر چیزی

با این حساب همچین چیزی رو باید داشته باشیم  ( به جای قبلی )

import PySimpleGui as gui
window = gui.Window("notepad+",[layout] , siza = (500,500))

چرا layout رو خالی گذاشتم؟ دلیلش اینه که یه لیستِ تقریبا بزرگه . ما هم میخوایم که تمیز و با دقت کد بزنیم . عقل حکم می کنه یه لیست جداگانه ایجاد کنیم و اونجا محتویات برنامه رو بنویسیم بعدم به عنوان آرگومان ، اونجا واردش کنیم .

فعلا توی برنامه‌مون چی میخوایم؟ یه جایی که توش متن رو بشه وارد کرد .  کلاسِ Multiline برامون این فضا رو فراهم میکنه . آرگومان هایی که ازمون میخواد مربوط میشن به  اندازه و فونت ؛ البته آرگومان های دیگه هم هست که الان کاریشون نداریم ، ولی بعدا حتما استفاده خواهیم کرد . تا الان باید همچین  چیزی داشته باشـیم  :

import PySimpleGui as gui
layout = [
	[gui.Multiline( font=("courier", 12) , size=(80, 55) )]
]
#...

سوال : چرا انقدر tuple  و list در list شد؟!

پاسخ : tuple که تایپِ آرگومانیِ که دریافت میکنه . اینکه چرا انقدر list لازمه رو هم از کسی بپرسید که کتابخونه رو نوشته :)

بعله ...
تا اینجا ما یه پنجره داریم و یه جایی برای نوشتن متن . 

پس می‌نویسیم که  :

import PySimpleGui as gui
layout = [
	[gui.Multiline( font=("courier", 12) , size=(80, 55) )]
]
window = gui.Window("notepad+",layout , siza = (500,500))

خب . اگه الان برنامه رو اجرا کنید ،  نتیجه‌ای که میخوایم رو تحویل نمیگیریم .
ما الان تعریف کردیم که یه پنجره باشه ، توی اینطوری باشه ، اونطوری باشه و اینا .
ولی براش اینکه نمایششون بده ، تعریف نشده .

توی tkinter برای اینکار از mainloop و pack استفاده می‌شد که تقریبا کار رو راحت می‌کرد . برای پای‌کیوت هم show بود .
اینجا باید تا یه جاهایی خودمون انجامش بدیم :)

اول از همه به مِتُدِ read برمیخوریم که تا حدی کار show و pack رو انجام میده :

window.read()

بعد باید یه while true بذاریم که تقریبا کار mainloop رو انجام بده .

while True :
	window.read()

تقریبا تموم شد . آمّا ( یه سلامی هم بکنیم به همشری های عزیزم ! یاشاسین آذربایجان! )  ،  برنامه‌مون بسته نمیشه! یعنی اگه اون ضربدری که معمولا بالای برنامه ها دیده میشه رو توی برنامه‌مون بزنیم ، برنامه ارور میده و خب ماهم از ارور خوشمون نمیاد .

چه کار کنیم ؟!

یه دوستی داشتیم ، به اسم window.read که این دوستمون دو تا مقدار برمی‌گردونه ، که ما یکیش رو میخوایم  البته فعلا  ولی خب دومی رو هم میگیریم که بعدا لازممون میشه .

حالا این دوتا چی هستن؟

یکیشون اتفاقاتی که توی برنامه توسط کاربر ایجاد شده‌ست و  اونیکی هم در حال حاضر اون چیزی رو برمیگردونه که ما توی بخش قابل نوشتن برنامه نوشتیم . 

ما فعلا هیچ کاری به دومی نداریم . بعدا میایم سراغش . الان فقط میخوایم رویداد ها رو زیر نظر داشته باشیم .

اسم اولی رو event  و دومی رو value میذاریم .
با این حساب همچین چیزی خواهیم داشت :

while True :
	event , value = window.read()

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

وقتی میخوایم برنامه رو ببندیم ، این درخواست ما توی event ذخیره میشه ، و اگر درخواست ما با اتریبیوتِ WIN_CLOSED برابر بود ، برنامه‌مون باید بسته بشه . توی tkinter و qt این دردسر وجود نداره ، اما اینجا چرا . باید خودمون بگیم چطور برنامه بسته بشه .

قاعدتا وقتی یه حلقه ی تکرار داره برنامه ی ما رو سرپا نگه میداره ، باید اول حلقه رو تموم کنیم ( بشکنیمش )  بعد به برنامه بگیم بسته بشه.
برای بستن برنامه از مِتُدِ close استفاده می کنیم  ،  و شکستن حلقه هم با یه if و break حل میشه .

نتیجه :

while True :
	event , value = window.read()
	if event == gui.WIN_CLOSED :
		break
	
window.close()

اینم از این . 
تا حالا چیزی که نوشتیم ، یه صفحه‌س  که میشه توش نوشت و بعدم بستش . کارایی نداره ؛ ولی خب قدم اول هم بخشی از مسیره :) 

مجموعا کدی که باید می نوشتیم هم اینه :

import PySimpleGUI as gui


# Define the GUI layout
layout = [
    [gui.Multiline(font=('courier', 12), size=(80, 45))]
    ]

# Create the window
window = gui.Window('notepad+', layout , size=(800, 600))

while True :
    event , values = window.read()
    if event == gui.WIN_CLOSED :
        break

window.close()

نکته : برنامه ی ما ، بدون این while True  و break و if و close هم بالا میاد :) . دلیل در اصل ، ما زمانی از while True استفاده می کنیم که بخوایم به کار های کاربر واکنش نشون بدیم ، اون‌هم چند بار . یعنی برنامه بتونه دائم به درخواست کاربر جواب بده .   با این حساب چون برنامه ی ما هنوز هیچ واکنش خاصی نشون نمیده به کاربر ، میشه بدون  while هم نوشتش .

اما ما از الان while رو استفاده کردیم ، تا بعدا راحت تر باشیم. 
با توجه به نکته ی قبل ، برنامه رو میشه اینطوری هم نوشت :

import PySimpleGUI as gui


# Define the GUI layout
layout = [
    [gui.Multiline(font=('courier', 12), size=(80, 45))]
    ]

# Create the window
window = gui.Window('notepad+', layout , size=(800, 600))

window.read()

حالا با خیال راحت از کد اجرا بگیرید و نتیجه رو ببینید . 

Image not loaded - graphical output

 

خداحافظیِ شیرین ، بعد از پر حرفی های من

خب! قسمت اول رو در همین لحظه به پایان می‌رسونیم 

امیدوارم خوشتون اومده باشه . این قسمت هم یه مقداری طولانی شد ، چون داشتیم استارت می زدیم . از دفعات بعد کوتاه تر و پُر کُد تر خواهم نوشت :)

اگه نظر ، انتقاد یا پیشنهادی دارید خوشحال میشم برام بنویسید . و لطفا اگه خوشتون اومد این پست رو لایک کنید که بدجور به همایتتون احتیاج دارم . 

راستی ، منتظر قسمت بعد هم حتما باشید .
روز و روزگارتون خُرَّم .

از بهترین نوشته‌های کاربران سکان آکادمی در سکان پلاس