1. ما هي QCalendarWidget؟
-
هي أداة رسومية في PyQt تعرض تقويمًا شهريًا.
-
تتيح للمستخدم اختيار تاريخ معين.
-
يمكن استخدامها في تطبيقات الحجز، إدارة المواعيد، والتذكير.
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. شرح الكود
-
إنشاء التقويم
self.calendar = QCalendarWidget() self.calendar.setGridVisible(True)
هذا يعرض تقويمًا مع شبكة للفصل بين الأيام.
-
عرض التاريخ المختار
date = self.calendar.selectedDate() self.label.setText(date.toString('dd/MM/yyyy'))
-
ربط الإشارة بالنص
-
عند النقر على أي يوم، يتم استدعاء الدالة
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_())
شرح التمرين
-
اختيار التاريخ من
QCalendarWidget
. -
إضافة المهمة مع التاريخ إلى
QTableWidget
. -
إمكانية الحذف للمهمة المحددة.
-
يمكن تعديل أي خلية في الجدول يدويًا.
التمرين المطور بحيث:
-
يتم حفظ المهام تلقائيًا في ملف 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_())
التطويرات المضافة
-
تصفية المهام مباشرة عند اختيار أي تاريخ من التقويم.
-
زر عرض كل المهام لإلغاء التصفية.
-
حفظ تلقائي في Excel عند الإضافة، الحذف، أو التعديل.
-
تحميل تلقائي من الملف عند التشغيل.