paint-brush
הנה איך בניתי זרימת אינטרנט כמו בונה ממשק משתמש עבור Pythonעל ידי@paulfreeman
350 קריאות
350 קריאות

הנה איך בניתי זרימת אינטרנט כמו בונה ממשק משתמש עבור Python

על ידי Paul10m2024/10/05
Read on Terminal Reader

יותר מדי זמן; לקרוא

שיתוף בתהליך החשיבה והניסיון שלי בבניית בונה ממשק משתמש לגרור ושחרר עבור python
featured image - הנה איך בניתי זרימת אינטרנט כמו בונה ממשק משתמש עבור Python
Paul HackerNoon profile picture
0-item
1-item


עבדתי על בונה גרור ושחרר עבור Python בשבועות האחרונים.


אתה יכול לבדוק את זה ב PyUIBuilder

קוד מקור: https://github.com/PaulleDemon/PyUIBuilder


מה יכול הקבלן לעשות?

בקיצור, זה יכול לעזור לך לבנות במהירות ממשק משתמש עבור Python ולייצר קוד ממשק משתמש במספר ספריות/מסגרות, כולל Tkinter ו-customtkinter. אתה יכול לקרוא עוד על סעיף תכונות


אבל אני לא רק רוצה להשיק פרויקט, אני גם רוצה לשתף אתכם בחוויה שלי. בבלוג זה אעבור על תהליך החשיבה שלי ועל סקירה ברמה גבוהה של האופן שבו בניתי את האפליקציה.

מעלה את הרעיון.

בניגוד לאמונה הרווחת, Python משמשת לעתים קרובות לבניית יישומים מהירים, והיא פופולרית במיוחד בקרב מפתחים העוסקים במדעי נתונים, אוטומציה, משימות סקריפטים וכו'. כלים פנימיים וממשקי GUI רבים, במיוחד בהגדרות מדעיות ומחקריות, נבנים עם Python בשל כך הפשטות והזמינות של מסגרות כמו Tkinter, PyQt ואחרות.

רַעְיוֹן

כעת, היו הרבה בוני גרירה ושחרור לאינטרנט, אבל מעט מאוד עבור ממשקי משתמשי Python, במיוחד עבור tkinter. ראיתי כמה, אבל הבעיה הייתה שהם היו מספר מוגבל מאוד של ווידג'טים או שייצרו קוד בפורמט XML, וזה לא אידיאלי אם אתה מפתח ממשק משתמש ב-Python.


אז, בהתחלה, רק רציתי לבנות בונה גרירה ושחרור ממשק משתמש מתאים רק עבור Tkinter.


המשכתי להתעסק ברעיון של בונה GUI אידיאלי (ללא משחק מילים). קיבלתי השראה מהממשק של Canva, והמצאתי כמה תכונות שיהפכו את ה-GUI שלי לאידיאלי.


  1. כל הווידג'טים צריכים להיעשות כמו פלאגינים.
  2. אמור לתמוך בווידג'טים של ממשק משתמש של צד שלישי בצורה של תוספים.
  3. אמור להיות מסוגל להעלות נכסים כגון תמונות, סרטונים וכו'.
  4. זה אמור ליצור קוד בפייתון.

אז, בסביבות סוף יולי, החלטתי להתחיל לעבוד על הפרויקט

מרחיב את הרעיון

בהתחלה זה נקרא tkbuilder, מה שמציין שזהו בונה GUI עבור ספריית ממשק המשתמש של Tkinter.


אבל, אם שמתם לב אני יכול גם להרחיב על אותו רעיון לתמוך במספר מסגרות וספריות Python GUI, מכיוון שהכל עשוי כמו תוסף וזה בדיוק מה שתכננתי לעשות.

תכנון גרסה ראשונית.

עבור הגרסה הראשונית, לא רציתי להוסיף יותר מדי תכונות שיכריעו את המשתמשים. רציתי לבנות אותו על סמך משוב מאנשים שמשתמשים בו. ככה אני לא מבזבז זמן על בניית דברים שאנשים לא רוצים.


מההתחלה החלטתי שלא יהיה לי אחורי או כל טופס הרשמה. בדרך זו הרבה יותר פשוט עבורי לפתח ולמשתמשים המשתמשים בו. רק רציתי חזית פשוטה שאנשים יכולים להתחיל איתו.

בחירת שפת JS, TS או Python

בחירת שפה

כן, זה היה משהו שחשבתי עליו די לפעמים, רוב בוני GUI עבור Python בחוץ נבנו באמצעות Python. הבחירה הראשונה שלי עבור Python הייתה PySide.


האפליקציה מבוססת GUI המורכבת ביותר שבניתי באמצעות PyQt/Pyside הייתה א עורך מבוסס צמתים כמה שנים אחורה.


אבל מהר מאוד הבנתי את המגבלות של השימוש בפיתון לבניית הגרסה הראשונית.


  • לספריות ממשק המשתמש של Python אין הרבה ווידג'טים של צד שלישי שיעזרו לי לבנות במהירות את הגרסה הראשונית.
  • לא קל להפיץ את אפליקציית Python כקבצי exe, כאשר בשימוש ב-JS נוכל להפיץ אותה בצורה של אפליקציית אלקטרונים.
  • רוב האנשים מעדיפים להשתמש באינטרנט במקום להוריד קובץ הפעלה מאתר לא מוכר.


גם Typescript הייתה אופציה, אבל עם Typescript תמיד הרגשתי שזה מפורט מדי


אלה היו הדברים היחידים שמיד שמתי לב אליהם, אז הבחירה הראשונה שלי הפכה באמצעות JS.


נ.ב: מאוחר יותר המשכתי להתחרט שלא התחלתי עם TS, אבל זה יהיה סיפור לפעם אחרת.

מסגרת או אין מסגרת.

הספרייה דמוית המסגרת שאני הכי נוחה איתה היא React.js, אבל יצירת הפשטה תדרוש שימוש בשיעורים, מה שלא מומלץ מאז הצגת ה-hooks.


הבעיה של אי שימוש במסגרת הייתה שאצטרך לבנות הכל בעצמי ולא תהיה לי גישה לספריות הרכיבים העצומות שיש ל-React להציע.


לשניהם היו פשרות, אבל עדיין ניתן להשתמש בשיעורי React, אז זו הפכה לבחירה ברורה עבורי.

התחלה מטלטלת

התחלתי בבניית הבסיס והסרגל הצדדי בתחילת אוגוסט, ונאלצתי להפסיק בגלל חוסר כספים, אז התחלתי לעבוד אצל לקוח, שלצערי לא שילם את הסכום הסופי. ניסיתי מימון המונים אבל גם שם לא היה לי מזל.


אז, בחודש ספטמבר עם הכספים הקטנים שנותרו לי, החלטתי ללכת על כל הפרויקט הזה. בסביבות ה-9 בספטמבר התחלתי את העבודה מחדש.

מתכננים קדימה...

לתכנן קדימה

הרבה מהזמן הושקע בחשיבה על ההפשטה הבסיסית, שניתן להרחיב אותה לקנה מידה כדי לענות על הצרכים.


  1. רציתי לקבל קנבס, שניתן להגדיל ולפנות בדומה ל-Figma.

  2. יישומון בסיס שממנו כל שאר הווידג'טים יכולים לצאת.

  3. תכונת גרירה ושחרור לגרירה ושחרור של רכיבי ממשק משתמש לתוך הקנבס.


כדי לבנות עם React, אתה צריך לחשוב ולבנות את זה בצורה מסוימת, למרות ויכוחים אם זו ספרייה או מסגרת, זה תמיד מרגיש יותר כמו Framework מאשר ספרייה.

עיצוב ממשק משתמש

תמיד אהבתי איך Canva בנה את סרגל הצד שלהם, רציתי שיהיה משהו דומה עבור בונה הגרירה והשחרור שלי.

רשמתי את מה שעולה בראשי על פיסת נייר. לא האמן הכי טוב שיש 🙄

עיצוב ממשק משתמש

תהליך החשיבה שלי לגבי האינטראקציה של הקנבס והווידג'ט.

לתכנן קדימה...

אז מי צריך להיות אחראי על גרירה, שינוי גודל, בחירה. הקנבס או הווידג'ט הבסיסי. כיצד יטופלו הווידג'טים בתוך הווידג'ט?


האם יישומון הבסיס יכיר את ילדיהם או שהוא ינוהל עם מבנה נתונים יחיד על ידי הקנבס עצמו. איך אעבד ילדים בתוך ילדים?


כיצד יפעלו הגרירה והשחרור בתוך הקנבס ושאר הווידג'טים?


כיצד ינוהלו פריסות?


אלו היו חלק מהשאלות שהתחלתי לשאול לפני בניית העניין כולו.


למרות שעכשיו ממשק המשתמש נראה פשוט יותר, הושקעה מחשבה רבה בבניית הבסיס, כך שהוא נראה הרבה יותר פשוט עבור המשתמשים.

גישה מבוססת HTML Canvas או גישה ללא קנבס.

גישה מבוססת קנבס

עכשיו ל-html יש אלמנט Canvas ברירת מחדל, שמאפשר לך לעשות הרבה דברים כמו לצייר, להוסיף תמונה וכאלה, עכשיו זה נראה כמו אלמנט אידיאלי לשימוש עבור התוכנית שלי.


אז, התחלתי לבדוק אם יש וקיים יישום של גרירה ושחרור, שינוי גודל, זום ותנועה. מצאתי בדים , זו נראתה כמו ספרייה פנטסטית למקרה השימוש שלי.


ניסיתי להתנסות עם Fabric.Js וניסיתי ליישם את כל העניין ב-stof.js כפי שאתה יכול לראות את זה יישום , אבל היה משהו בקנבס שלא חזיתי.


  1. התחלתי להתנסות עם גישה מבוססת ווים בעת בניית הבד, אבל פונקציית ה-dispose של fabric.js הייתה אסינכרית, כך שהיא לא תשחק טוב עם הוקס.
  2. לא יכול להיות ל-Canvas אלמנטים צאצאים כמו Div או אלמנטים אחרים שיהפכו את זה קצת יותר קשה לבנות מנהלי פריסה
  3. איתור באגים בכל דבר על קנבס הוא די קשה מכיוון שהאלמנטים הפנימיים של הקנבס אינם מופיעים באלמנט הבדיקה של כלי המפתח


גישה לא מבוססת קנבס


כעת, לאחר ניסויים, הגישה ללא קנבס נראתה טובה יותר, מכיוון שיש לי גישה למנהל הפריסה המוגדר כברירת מחדל, בנוסף היו זמינים הרבה רכיבים מובנים מראש של ממשק המשתמש שיעשו את הבחירה האידיאלית הזו בעת שינוי קנה מידה.


תכננתי לדמות קנבס על ידי שימוש בשני div'ים שונים אחד div פנימי ו- div מיכל חיצוני.


כעת יצירת זום ופאן היו קלים למדי ליישום, שכן ל-CSS כבר היה טרנספורמציה, קנה מידה ותרגום.


ראשית, כדי ליישם את זה, הייתי צריך להיות מיכל שמכיל קנבס. כעת הקנבס הזה הוא אלמנט בלתי נראה (ללא נסתר על הצפה), זה המקום שבו כל האלמנטים נשמטים, ומיושמים קנה מידה ותרגום.

מְכוֹלָה

עבור זום אין הייתי צריך להגדיל את קנה המידה ולזום אאוט להקטין אותו.

נסה את הדוגמה הפשוטה הזו. (מקש + כדי להתקרב - כדי להתרחק)


Panning עבד באופן דומה

גרור ושחרר

גרור ושחרר

כשהתחלתי חקרתי על כמה ספריות כמו תגיב-יפה-Dnd , React Dnd-kit ו תגיב סוופי .


לאחר מחקר ראיתי ש-react-beautiful-dnd כבר לא נשמר והתחלתי עם React dnd-kit. בתור תחילת בנייה, מצאתי את התיעוד של ה-dnd-kit מוגבל למדי למה שבניתי, בנוסף, בקרוב יצאה מהדורה חדשה עם שינויים גדולים בספרייה, אז החלטתי לבטל את react-dnd-kit עד הגרסה העיקרית.


כתבתי מחדש את החלקים שבהם השתמשתי ב-DND-kit עם ה-Drag and Drop API של HTML. המגבלה היחידה עם ממשק ה-API המקורי של גרירה ושחרור הייתה שהוא עדיין לא נתמך על ידי מכשירי מגע מסוימים, מה שלא היה חשוב לי כי בניתי למכשירים ללא מגע.

מקור יחיד של אמת

תתמודד עם האמת

כאשר בונים אפליקציה כזו, קל לאבד את המעקב אחר כל המשתנים והשינויים. אז, אני לא יכול לקבל משתנים מרובים לעקוב אחר אותה פיסת מידע.


המידע/מצב של כל יישומון צריך להיות מוחזק על ידי הקנבס או על ידי הווידג'ט עצמו, אשר לאחר מכן מעביר את המידע לפי בקשה.


או אולי השתמש בספריית ניהול המדינה כמו redux


בחרתי לקבל את כל המידע על הווידג'טים המנוהלים על ידי רכיב Canvas לאחר ניסוי גישות שונות.


מבנה הנתונים נראה בערך כך.

 [ { id: "", // id of the widget widgetType: WidgetClass, // base widget children: [], // children will also have the same datastructure as the parent parent: "", // id of the parent of the current widget initialData: {} // information about the widget's data that's about to be rendered eg: backgroundColor, foregroundColor etc. } ]

מנהלי הקשר

עכשיו רציתי שהנכסים שהועלו בסרגל הצד יהיו נגישים באמצעות סרגל הכלים של הווידג'טים. אבל בכל פעם שאני מחליף את הכרטיסיות הצדדיות, העיבוד מחדש גרם להיעלמות הנכסים שהועלו.


אחת המגבלות הגדולות ביותר עם Redux היא שאתה יכול לאחסן רק נתונים הניתנים לסידרה. לא ניתן לאחסן נתונים שאינם ניתנים לסידרה כגון תמונה, וידאו, נכסים אחרים ב-redux. זה יקשה על העברת נתונים משותפים סביב רכיבים שונים.


דרך אחת להתגבר על זה היא להשתמש בהקשר של React. בקצרה, React Context מספקת דרך להעביר נתונים דרך עץ הרכיבים ללא צורך להעביר אביזרים ידנית בכל רמה.


כל מה שהייתי צריך לעשות כדי לקבל את הנתונים ברכיבים שונים היה לעטוף אותם סביב ספק הקשר של React.


יצרתי ספקי הקשר משלי לשני דברים:

  1. גרירה ושחרור - הפעלת גרירה ושחרור מסרגל הצד + גרירה ושחרור בתוך אלמנטים צאצאים.
  2. העלאת קבצים - להנגיש את הקבצים שהועלו בסרגל הכלים עבור כל ווידג'ט.


הנה דוגמה פשוטה לאופן שבו השתמשתי בהקשר של React עבור גרירה ושחרור.

 import React, { createContext, useContext, useState } from 'react' const DragWidgetContext = createContext() export const useDragWidgetContext = () => useContext(DragWidgetContext) // Provider component to wrap around parts that need drag-and-drop functionality export const DragWidgetProvider = ({ children }) => { const [draggedElement, setDraggedElement] = useState(null) const onDragStart = (element) => { setDraggedElement(element) } const onDragEnd = () => { setDraggedElement(null) } return ( <DragWidgetContext.Provider value={{ draggedElement, onDragStart, onDragEnd }}> {children} </DragWidgetContext.Provider> ) }


כֵּן! זהו. כל מה שהייתי צריך לעשות עכשיו זה לעטוף אותו סביב הרכיב שבו הייתי צריך את ההקשר, שבמקרה שלי היה מעל Canvas וסרגל הצד.

יצירת קוד

אַחֲרָיוּת

מכיוון שכל ווידג'ט מתנהג אחרת ויש לו תכונות משלו, החלטתי שהווידג'טים חייבים להיות אחראים על יצירת הקוד שלהם ומנוע קוד יטפל רק בהתנגשויות של שמות משתנים וחיבור הקוד.


בדרך זו, הצלחתי בקלות להתרחב כדי לתמוך בווידג'טים רבים שנבנו מראש, כמו גם בכמה תוספים של ממשק משתמש של צד שלישי.

יוצא לשידור חי

לא היה לי קצה אחורי או הרשמה והיו הרבה חברות שסיפקו אירוח בחינם לדפים סטטיים. תחילה החלטתי ללכת עם Vercel, אבל פעמים רבות ראיתי צמיג חינם של Vercel יורד אם היו יותר מדי בקשות.


זה הרגע שגיליתי על דפי Cloudflares הַצָעָה. בצמיג הפנוי שלהם היה כמעט הכל ללא הגבלה. אז השימוש ב-cloudflare הפך לבחירה העיקרית שלי.


החסרונות היחידים היו זמני הבנייה היו איטיים למדי וחסר להם לא מעט תיעוד.


החלק הכי מעצבן בשלב הבנייה היה כישלון הבנייה, זה עבד על Vercel, אבל לא על דפי cloudflare??? היומנים גם לא היו כל כך ברורים. ויש לנו צמיגים בחינם יש רק 500 בנייה בחודש, אז לא רציתי לבזבז יותר מדי


ניסיתי במשך שעות ואז החלטתי להגדיר אינטגרציה מתמשכת למחרוזת ריקה

 CI='' npm install


וזה סוף סוף עלה לאוויר.
לִחיוֹת

רוצים לראות איך זה התקדם במהלך החודשים?

בניתי את כל הדבר הזה בפומבי. אני מעוניין לראות את זה מתקדם מסרגל צד פשוט לבונה Drag n drop מפוצץ לחלוטין, אתה יכול לבדוק את כל ציר הזמן כאן .


#בנה בציבור


הו! אל תשכח לעקוב אחרי עדכונים

מאגר כוכבים ⭐️


אם אהבתם את סוג התוכן הזה, אני אכתוב בלוגים נוספים ונכנס יותר לעומק של איך אני מתכנן ובונה דברים, כדי לעקוב אחריכם תוכלו להירשם לניוזלטר המשנה שלי :)