تقنيات نور التعليمية تقنيات نور التعليمية
في الوقت الحالي

جاري صيانة و تحديث للمدونة

في الوقت الحالي
جاري التحميل ...

الدرس 28 – أداة QCalendarWidget

1. ما هي QCalendarWidget؟

  • هي أداة رسومية في PyQt تعرض تقويمًا شهريًا.
  • تتيح للمستخدم اختيار تاريخ معين.
  • يمكن استخدامها في تطبيقات الحجز، إدارة المواعيد، والتذكير.

أداة QCalendarWidget



2. أهم الخصائص

الخاصية الوصف
setGridVisible(True/False) عرض شبكة حول الأيام أو إخفاؤها.
selectedDate() الحصول على التاريخ المختار.
setSelectedDate(QDate) تعيين تاريخ افتراضي.
clicked إشارة تُطلق عند الضغط على تاريخ.
selectionChanged إشارة تُطلق عند تغيير التاريخ المختار.

3. مثال عملي

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QCalendarWidget
from PyQt5.QtCore import QDate

class CalendarExample(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("مثال QCalendarWidget")
        self.resize(400, 300)

        layout = QVBoxLayout()

        # نص لعرض التاريخ المختار
        self.label = QLabel("اختر تاريخًا من التقويم")
        layout.addWidget(self.label)

        # إنشاء أداة التقويم
        self.calendar = QCalendarWidget()
        self.calendar.setGridVisible(True)  # عرض الخطوط
        self.calendar.setSelectedDate(QDate.currentDate())  # تاريخ اليوم

        # عند النقر على أي يوم
        self.calendar.clicked.connect(self.show_date)

        layout.addWidget(self.calendar)
        self.setLayout(layout)

    def show_date(self):
        date = self.calendar.selectedDate()
        self.label.setText(f"التاريخ المختار: {date.toString('dd/MM/yyyy')}")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = CalendarExample()
    window.show()
    sys.exit(app.exec_())

4. شرح الكود

  1. إنشاء التقويم

    self.calendar = QCalendarWidget()
    self.calendar.setGridVisible(True)
    

    هذا يعرض تقويمًا مع شبكة للفصل بين الأيام.

  2. عرض التاريخ المختار

    date = self.calendar.selectedDate()
    self.label.setText(date.toString('dd/MM/yyyy'))
    
  3. ربط الإشارة بالنص

    • عند النقر على أي يوم، يتم استدعاء الدالة show_date() لتحديث النص.


5. استخدامات عملية

  • تحديد تاريخ الميلاد في النماذج.

  • اختيار موعد حجز تذكرة أو فندق.

  • تحديد فترة زمنية لعرض بيانات معينة.


تمرين على QCalendarWidget مع QTableWidget بحيث:

  • تختار تاريخًا من التقويم.
  • تدخل وصفًا للمهمة أو الحدث.
  • تضيفه في جدول مرتبط بالتاريخ.
  • يتم عرض جميع المهام المخزنة، ويمكنك تعديلها أو حذفها.


التمرين – تقويم المهام

import sys
from PyQt5.QtWidgets import (
    QApplication, QWidget, QVBoxLayout, QHBoxLayout,
    QLabel, QLineEdit, QPushButton, QCalendarWidget,
    QTableWidget, QTableWidgetItem, QMessageBox
)
from PyQt5.QtCore import QDate

class TaskCalendar(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("تقويم المهام")
        self.resize(600, 500)

        layout = QVBoxLayout()

        # 1. التقويم
        self.calendar = QCalendarWidget()
        self.calendar.setGridVisible(True)
        layout.addWidget(self.calendar)

        # 2. إدخال المهمة
        input_layout = QHBoxLayout()
        self.task_input = QLineEdit()
        self.task_input.setPlaceholderText("اكتب المهمة هنا")
        self.btn_add = QPushButton("إضافة المهمة")
        self.btn_add.clicked.connect(self.add_task)
        input_layout.addWidget(self.task_input)
        input_layout.addWidget(self.btn_add)
        layout.addLayout(input_layout)

        # 3. جدول عرض المهام
        self.table = QTableWidget()
        self.table.setColumnCount(2)
        self.table.setHorizontalHeaderLabels(["التاريخ", "المهمة"])
        layout.addWidget(self.table)

        # 4. زر حذف المهمة
        self.btn_delete = QPushButton("حذف المهمة المحددة")
        self.btn_delete.clicked.connect(self.delete_task)
        layout.addWidget(self.btn_delete)

        self.setLayout(layout)

    def add_task(self):
        date = self.calendar.selectedDate().toString("dd/MM/yyyy")
        task = self.task_input.text()

        if not task:
            QMessageBox.warning(self, "خطأ", "يرجى كتابة المهمة أولاً")
            return

        row_pos = self.table.rowCount()
        self.table.insertRow(row_pos)
        self.table.setItem(row_pos, 0, QTableWidgetItem(date))
        self.table.setItem(row_pos, 1, QTableWidgetItem(task))

        self.task_input.clear()

    def delete_task(self):
        selected_row = self.table.currentRow()
        if selected_row >= 0:
            self.table.removeRow(selected_row)
        else:
            QMessageBox.warning(self, "خطأ", "يرجى اختيار مهمة لحذفها")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = TaskCalendar()
    window.show()
    sys.exit(app.exec_())

شرح التمرين

  1. اختيار التاريخ من QCalendarWidget.
  2. إضافة المهمة مع التاريخ إلى QTableWidget.
  3. إمكانية الحذف للمهمة المحددة.
  4. يمكن تعديل أي خلية في الجدول يدويًا.


 التمرين المطور بحيث:

  • يتم حفظ المهام تلقائيًا في ملف Excel عند الإضافة أو الحذف أو التعديل.
  • عند تشغيل البرنامج، يتم تحميل المهام تلقائيًا إذا كان الملف موجود.


النسخة المطورة – الحفظ التلقائي في Excel

import sys
import os
import pandas as pd
from PyQt5.QtWidgets import (
    QApplication, QWidget, QVBoxLayout, QHBoxLayout,
    QLabel, QLineEdit, QPushButton, QCalendarWidget,
    QTableWidget, QTableWidgetItem, QMessageBox
)
from PyQt5.QtCore import QDate

class TaskCalendar(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("تقويم المهام - حفظ تلقائي في Excel")
        self.resize(600, 500)

        self.excel_file = "tasks.xlsx"

        layout = QVBoxLayout()

        # 1. التقويم
        self.calendar = QCalendarWidget()
        self.calendar.setGridVisible(True)
        layout.addWidget(self.calendar)

        # 2. إدخال المهمة
        input_layout = QHBoxLayout()
        self.task_input = QLineEdit()
        self.task_input.setPlaceholderText("اكتب المهمة هنا")
        self.btn_add = QPushButton("إضافة المهمة")
        self.btn_add.clicked.connect(self.add_task)
        input_layout.addWidget(self.task_input)
        input_layout.addWidget(self.btn_add)
        layout.addLayout(input_layout)

        # 3. جدول عرض المهام
        self.table = QTableWidget()
        self.table.setColumnCount(2)
        self.table.setHorizontalHeaderLabels(["التاريخ", "المهمة"])
        layout.addWidget(self.table)

        # 4. زر حذف المهمة
        self.btn_delete = QPushButton("حذف المهمة المحددة")
        self.btn_delete.clicked.connect(self.delete_task)
        layout.addWidget(self.btn_delete)

        self.setLayout(layout)

        # تحميل البيانات من الملف إذا موجود
        self.load_from_excel()

        # الحفظ التلقائي عند تعديل أي خلية
        self.table.itemChanged.connect(self.save_to_excel)

    def add_task(self):
        date = self.calendar.selectedDate().toString("dd/MM/yyyy")
        task = self.task_input.text()

        if not task:
            QMessageBox.warning(self, "خطأ", "يرجى كتابة المهمة أولاً")
            return

        row_pos = self.table.rowCount()
        self.table.insertRow(row_pos)
        self.table.setItem(row_pos, 0, QTableWidgetItem(date))
        self.table.setItem(row_pos, 1, QTableWidgetItem(task))

        self.task_input.clear()
        self.save_to_excel()

    def delete_task(self):
        selected_row = self.table.currentRow()
        if selected_row >= 0:
            self.table.removeRow(selected_row)
            self.save_to_excel()
        else:
            QMessageBox.warning(self, "خطأ", "يرجى اختيار مهمة لحذفها")

    def save_to_excel(self):
        rows = self.table.rowCount()
        cols = self.table.columnCount()
        data = []

        for row in range(rows):
            row_data = []
            for col in range(cols):
                item = self.table.item(row, col)
                row_data.append(item.text() if item else "")
            data.append(row_data)

        df = pd.DataFrame(data, columns=["التاريخ", "المهمة"])
        df.to_excel(self.excel_file, index=False)

    def load_from_excel(self):
        if os.path.exists(self.excel_file):
            df = pd.read_excel(self.excel_file)
            self.table.setRowCount(len(df))
            for row in range(len(df)):
                for col in range(len(df.columns)):
                    self.table.setItem(row, col, QTableWidgetItem(str(df.iat[row, col])))

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = TaskCalendar()
    window.show()
    sys.exit(app.exec_())

التطويرات المضافة

  • حفظ تلقائي عند الإضافة، الحذف، أو تعديل أي خلية.
  • تحميل تلقائي عند بدء البرنامج.
  • ملف Excel (tasks.xlsx) لتخزين البيانات بشكل دائم.


تطوير  التمرين الآن بحيث:

  • عند اختيار أي تاريخ من QCalendarWidget، يتم عرض المهام الخاصة بهذا التاريخ فقط في الجدول.
  • أضفت زر عرض كل المهام لإعادة إظهار جميع البيانات.


النسخة المطورة – تصفية المهام حسب التاريخ

import sys
import os
import pandas as pd
from PyQt5.QtWidgets import (
    QApplication, QWidget, QVBoxLayout, QHBoxLayout,
    QLineEdit, QPushButton, QCalendarWidget,
    QTableWidget, QTableWidgetItem, QMessageBox
)
from PyQt5.QtCore import QDate

class TaskCalendar(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("تقويم المهام - حفظ وتصفية تلقائية")
        self.resize(650, 550)

        self.excel_file = "tasks.xlsx"

        layout = QVBoxLayout()

        # 1. التقويم
        self.calendar = QCalendarWidget()
        self.calendar.setGridVisible(True)
        self.calendar.selectionChanged.connect(self.filter_tasks_by_date)
        layout.addWidget(self.calendar)

        # 2. إدخال المهمة
        input_layout = QHBoxLayout()
        self.task_input = QLineEdit()
        self.task_input.setPlaceholderText("اكتب المهمة هنا")
        self.btn_add = QPushButton("إضافة المهمة")
        self.btn_add.clicked.connect(self.add_task)
        input_layout.addWidget(self.task_input)
        input_layout.addWidget(self.btn_add)
        layout.addLayout(input_layout)

        # 3. جدول عرض المهام
        self.table = QTableWidget()
        self.table.setColumnCount(2)
        self.table.setHorizontalHeaderLabels(["التاريخ", "المهمة"])
        layout.addWidget(self.table)

        # 4. أزرار التحكم
        btn_layout = QHBoxLayout()
        self.btn_delete = QPushButton("حذف المهمة المحددة")
        self.btn_delete.clicked.connect(self.delete_task)

        self.btn_show_all = QPushButton("عرض كل المهام")
        self.btn_show_all.clicked.connect(self.load_from_excel)

        btn_layout.addWidget(self.btn_delete)
        btn_layout.addWidget(self.btn_show_all)
        layout.addLayout(btn_layout)

        self.setLayout(layout)

        # تحميل البيانات من الملف إذا موجود
        self.load_from_excel()

        # الحفظ التلقائي عند تعديل أي خلية
        self.table.itemChanged.connect(self.save_to_excel)

    def add_task(self):
        date = self.calendar.selectedDate().toString("dd/MM/yyyy")
        task = self.task_input.text()

        if not task:
            QMessageBox.warning(self, "خطأ", "يرجى كتابة المهمة أولاً")
            return

        row_pos = self.table.rowCount()
        self.table.insertRow(row_pos)
        self.table.setItem(row_pos, 0, QTableWidgetItem(date))
        self.table.setItem(row_pos, 1, QTableWidgetItem(task))

        self.task_input.clear()
        self.save_to_excel()

    def delete_task(self):
        selected_row = self.table.currentRow()
        if selected_row >= 0:
            self.table.removeRow(selected_row)
            self.save_to_excel()
        else:
            QMessageBox.warning(self, "خطأ", "يرجى اختيار مهمة لحذفها")

    def save_to_excel(self):
        rows = self.table.rowCount()
        cols = self.table.columnCount()
        data = []

        for row in range(rows):
            row_data = []
            for col in range(cols):
                item = self.table.item(row, col)
                row_data.append(item.text() if item else "")
            data.append(row_data)

        df = pd.DataFrame(data, columns=["التاريخ", "المهمة"])
        df.to_excel(self.excel_file, index=False)

    def load_from_excel(self):
        self.table.setRowCount(0)
        if os.path.exists(self.excel_file):
            df = pd.read_excel(self.excel_file)
            self.table.setRowCount(len(df))
            for row in range(len(df)):
                for col in range(len(df.columns)):
                    self.table.setItem(row, col, QTableWidgetItem(str(df.iat[row, col])))

    def filter_tasks_by_date(self):
        selected_date = self.calendar.selectedDate().toString("dd/MM/yyyy")
        if os.path.exists(self.excel_file):
            df = pd.read_excel(self.excel_file)
            filtered_df = df[df["التاريخ"] == selected_date]

            self.table.setRowCount(len(filtered_df))
            for row in range(len(filtered_df)):
                self.table.setItem(row, 0, QTableWidgetItem(filtered_df.iat[row, 0]))
                self.table.setItem(row, 1, QTableWidgetItem(filtered_df.iat[row, 1]))

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = TaskCalendar()
    window.show()
    sys.exit(app.exec_())

التطويرات المضافة

  1. تصفية المهام مباشرة عند اختيار أي تاريخ من التقويم.
  2. زر عرض كل المهام لإلغاء التصفية.
  3. حفظ تلقائي في Excel عند الإضافة، الحذف، أو التعديل.
  4. تحميل تلقائي من الملف عند التشغيل.

عن الكاتب

Tamer Ahmed

التعليقات


اتصل بنا

إذا أعجبك محتوى مدونتنا نتمنى البقاء على تواصل دائم ، فقط قم بإدخال بريدك الإلكتروني للإشتراك في بريد المدونة السريع ليصلك جديد المدونة أولاً بأول ، كما يمكنك إرسال رساله بالضغط على الزر المجاور ...

جميع الحقوق محفوظة

تقنيات نور التعليمية