מד התקדמות פשוט מבוסס שורת פקודה

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

מה זה מד התקדמות?

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

אם עדיין לא הבנתם, הנה דוגמה קטנה:

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

ממה מורכב מד התקדמות?

השאלה נראית די טריוויאלית, אבל היא בכל זאת חשובה מאוד להמשך המדריך. מד התקדמות מורכב ממסילה, שיכולה להיות קו אופקי, מעגל, או כל צורה אחרת, וצורה לציון ההתקדמות – בדרך כלל סתם ריבוע. המסילה היא דמיונית בלבד – היא אינה אלא רצף של צורות פשוטות יותר. מד ההתקדמות שלנו יורכב, כאמור, מטקסט, ולכן נצטרך למצוא תווים מתאימים לשימוש במסילה ובאות ההתקדמות. כמו כן, נצטרך לבחור אורך למד ההתקדמות שניצור – האורך לא עקרוני, אך עם זאת מובן מאליו שלא נבחר באורך של 10,000 תווים. לצורך המדריך בחרתי באורך של עשרה תווים. דוגמה למד ההתקדמות שניצור במהלך המדריך: [++++++----]

טוב, אז מה לכתוב בקוד?

בשלב הזה אתם כבר וודאי מנחשים (גם אם לא, אל תדאגו – פשוט המשיכו לקרוא) מהו רצף הפעולות שאמורות להתרחש לצורך יצירת מד ההתקדמות שלנו. בהנחה שתו המסילה שבחרנו הוא סימן חיסור ותו ההתקדמות הוא סימן חיבור, תהליך ההדפסה אמור להראות בערך ככה: להדפיס סימן חיסור עשר פעמים ברצף, למחוק את כל עשרת סימני החיסור שהדפסנו, להדפיס סימן חיבור – ואז להדפיס תשעה סימני חיסור, למחוק את כל תשעת הסימנים, להדפיס עוד סימן חיבור, להדפיס שמונה סימני חיסור, וכן הלאה – עד שמגיעים למצב שבו הדפסנו עשרה תווי התקדמות (סימני חיבור). מד ההתקדמות יראה בערך ככה: +--------- ++-------- +++------- וכן הלאה. הנה הקוד שיצר את הדוגמה שלמעלה: int i, k; for (i = 0; i < 10; ++i) { for (k = 10-i; k <= 10; ++k) printf("+"); for (k = i+1; k < 10; ++k) printf("-"); printf("\n"); }

"אלו עשרה מדי התקדמות שונים – אני ביקשתי אחד..."

נכון – זה קורה כי בכל התקדמות אנחנו מדפיסים מד התקדמות חדש ומעודכן. אין שום סיבה (לא אסתטית ולא לוגית) לעשות את זה – המשתמש בסך הכל רוצה לראות את ההתקדמות של התהליך במקום אחד, בלי סיבוכים מיותרים. יש ל-C פתרון מצויין עבור בעיה זו - התו \b (לוכסן ואחריו B קטנה). הוא אולי נראה כמו שני תווים, אבל ב-C הוא מציין תו אחד שמשמעותו BackSpace - כלומר תו מחיקה, בדיוק כמו לחיצה על כפתור BackSpace במקלדת. שמרו את הקוד הבא בקובץ חדש והדרו אותו: #include <stdio.h> int main() { printf("I don’t\b\b\b\b\b\b like bunnies!"); return 0; } ייתכן שחשבתם שהקוד הנ"ל ידפיס את המחרוזת I don’t like bunnies!, אבל אבוי! המילה don’t והרווח שלפניה נמחקו, וכל מה שנשאר זה "I like bunnies!"! כמה צפוי :P עדיין לא הבנתם איך זה עוזר לנו? שימו לב שהוא מוחק תווים בזמן ריצת התוכנה, ולכן אפשר להשתמש בו כדי לדמות תנועה. קחו למשל את הקוד של שלב 1 – כל מה שצריך כדי להוסיף לו "תנועה" זה פשוט למחוק את תווי המסילה אחרי כל הדפסה, להדפיס תו התקדמות נוסף, ומייד אחר כך למלא את המקום הריק בתווי מסילה. בינתיים הקוד יראה בערך כך: int i, k; for (i = 0; i <= 10; ++i) { if (i != 0) printf("+"); for (k = i; k < 10; ++k) printf("-"); for (k = i; k < 10; ++k) printf("\b"); } נכון, זה עדיין לא תנועה – הכל קורה כל כך מהר שאתם פשוט לא מספיקים לראות את השינוי בין שלבי ההתקדמות השונים. כדי להוסיף עיכוב בין הריצות של הלולאה, נצטרך לכתוב פונקציה שתחזור (קרי: תבצע פעולת return) אחרי זמן מסויים שנקבע. כדי לממש את זה, נצטרך לשמור במשתנה את הסכום של מספר אלפיות השניה שעברו מאז הפעלת התוכנה ושל מספר אלפיות השניה שבהן נרצה לעכב את הריצה. לצורך זה נכליל את הספריה התקנית time.h – קיימת בה פונקציה בשם clock שמחזירה טיפוס long המכיל את הזמן (באלפיות שניה) שעבר מאז שהתוכנה הופעלה. אחרי ששמרנו את המידע הדרוש במשתנה, השאר פשוט מאוד – נכתוב לולאה שתרוץ כל עוד הערך המוחזר מ-clock() קטן מהערך השמור במשתנה. void delay(int ms) { long timeout = clock() + ms; while (clock() < timeout) continue; } לפונקציה, מן הסתם, צריך לקרוא אחרי הלולאה שמדפיסה את תווי המסילה. זהו! עכשיו יש לכם מד התקדמות מבוסס שורת פקודה לתפארת מדינת ישראל. עכשיו רק נשאר להכניס אותו לפונקציה מסוגננת ולשחק עם הפרמטרים שלה :-) הנה הקוד המוגמר: #include <stdio.h> #include <time.h> void delay(int ms) { long timeout = clock() + ms; while (clock() < timeout) continue; } void printProgressBar(int length, int interval) { printf("["); int i, k; for (i = 0; i <= length; ++i) { if (i != 0) printf("#"); for (k = i; k < length; ++k) printf("+"); printf("]"); delay(interval); for (k = i; k <= length; ++k) printf("\b"); } } int main() { int i; for (i = 0; i < 50; i += 5) { printProgressBar(i, 100); printf("\n"); } return 0; } אני מקווה שנהניתם לקרוא ולהתנסות במדריך הזה. ביקורות, הצעות שיפור, רעיונות - כולם יתקבלו בברכה :-)

אין תגובות: