الفكرة العامة
QDockWidget
عنصر واجهة رسومية يسمح بإضافة نوافذ فرعية يمكن:
- تثبيتها على جوانب النافذة (يمين / يسار / أعلى / أسفل).
- سحبها وتحويلها إلى نوافذ مستقلة عائمة (Floating).
- إخفاؤها / إظهارها حسب الحاجة.
يُستخدم كثيرًا في برامج معقدة مثل:
- بيئات التطوير (IDE) حيث تظهر قائمة الملفات أو وحدة الإخراج كـ Dock.
- برامج التصميم مثل فوتوشوب حيث تظهر لوحات الأدوات بشكل Dock.
استيراد المكتبات
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QTextEdit, QDockWidget, QListWidget, QLabel
from PyQt5.QtCore import Qt
مثال عملي — نافذة رئيسية مع Dock جانبي
الكود التالي ينشئ نافذة رئيسية تحتوي على:
- محرر نص في الوسط.
- Dock جانبي فيه قائمة ملفات.
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QTextEdit, QDockWidget, QListWidget, QLabel
from PyQt5.QtCore import Qt
class DockExample(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("مثال QDockWidget - النوافذ العائمة")
self.resize(800, 500)
# المحرر الرئيسي في الوسط
editor = QTextEdit()
editor.setPlainText("مرحبًا! هذا هو المحرر الرئيسي.")
self.setCentralWidget(editor)
# إنشاء Dock Widget
dock = QDockWidget("قائمة الملفات", self)
dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)
# محتوى الـ Dock
file_list = QListWidget()
file_list.addItems([f"ملف_{i}.txt" for i in range(1, 6)])
dock.setWidget(file_list)
# إضافة الـ Dock للنافذة (افتراضيًا على اليسار)
self.addDockWidget(Qt.LeftDockWidgetArea, dock)
if __name__ == "__main__":
app = QApplication(sys.argv)
win = DockExample()
win.show()
sys.exit(app.exec_())
ملاحظات على الكود
QMainWindow
ضروري لاستخدام Dock Widgets (لأنها تعتمد على مناطق Dock).setCentralWidget()
لتعيين الودجت الرئيسي (هنا محرر النص).QDockWidget("العنوان", parent)
لإنشاء Dock جديد.setAllowedAreas()
لتحديد أي الجوانب يمكن أن يوضع فيها Dock.addDockWidget(Qt.LeftDockWidgetArea, dock)
لإضافته إلى الجانب المطلوب.
مزايا إضافية
-
يمكن جعل الـ Dock قابل للإخفاء من قائمة View عبر
setFeatures(QDockWidget.DockWidgetClosable | QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetFloatable)
. - يمكن إضافة أكثر من Dock (مثلاً Dock للأدوات، Dock للمعاينة).
- يمكن للمستخدم سحب Dock خارج النافذة ليصبح نافذة مستقلة.
تمرين عملي (قبل الحل)
أنشئ تطبيق يحتوي على:
- محرر نص (QTextEdit) في الوسط.
- Dock على اليسار يحتوي على قائمة ملفات.
- Dock آخر على اليمين يحتوي على وصف / معلومات (QLabel).
- اجعل المستخدم قادرًا على سحب أي Dock للخارج كنافذة مستقلة.
فكرة تطويرية
- اجعل إعدادات الموقع (حجم النوافذ ومكان الـ Dock) تُحفظ في ملف (JSON) وتُسترجع عند الفتح.
- أضف زر إظهار / إخفاء Dock من قائمة رئيسية.
- اجعل محتوى Dock يتفاعل مع المحرر (مثلاً عند اختيار ملف من القائمة يظهر اسمه داخل المحرر).
📝 تمرين عملي — تطبيق متعدد النوافذ باستخدام QDockWidget
المطلوب:
- محرر نص رئيسي في الوسط.
- Dock على اليسار يحتوي على قائمة ملفات.
- Dock على اليمين يحتوي على معلومات / وصف.
- دعم سحب Dock كنافذة مستقلة (Floating).
- تفاعل بسيط: عند اختيار ملف من القائمة، يظهر اسمه في Dock اليمين + يضاف داخل المحرر.
✅ الحل
import sys
from PyQt5.QtWidgets import (
QApplication, QMainWindow, QTextEdit, QDockWidget, QListWidget, QLabel, QWidget, QVBoxLayout
)
from PyQt5.QtCore import Qt
class DockApp(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("تطبيق متعدد النوافذ باستخدام QDockWidget")
self.resize(1000, 600)
# 🔹 1. المحرر الرئيسي
self.editor = QTextEdit()
self.editor.setPlainText("مرحبًا بك! اختر ملفًا من القائمة...")
self.setCentralWidget(self.editor)
# 🔹 2. Dock اليسار (قائمة الملفات)
self.file_dock = QDockWidget("قائمة الملفات", self)
self.file_dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)
self.file_list = QListWidget()
self.file_list.addItems([f"ملف_{i}.txt" for i in range(1, 6)])
self.file_list.currentTextChanged.connect(self.show_file_info)
self.file_dock.setWidget(self.file_list)
self.addDockWidget(Qt.LeftDockWidgetArea, self.file_dock)
# 🔹 3. Dock اليمين (معلومات)
self.info_dock = QDockWidget("معلومات الملف", self)
self.info_dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)
info_widget = QWidget()
info_layout = QVBoxLayout()
self.info_label = QLabel("لم يتم اختيار أي ملف بعد.")
info_layout.addWidget(self.info_label)
info_widget.setLayout(info_layout)
self.info_dock.setWidget(info_widget)
self.addDockWidget(Qt.RightDockWidgetArea, self.info_dock)
# 🔹 4. تمكين السحب (Float) والإغلاق
self.file_dock.setFeatures(
QDockWidget.DockWidgetClosable | QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetFloatable
)
self.info_dock.setFeatures(
QDockWidget.DockWidgetClosable | QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetFloatable
)
# 🔹 5. التفاعل
def show_file_info(self, file_name):
if file_name:
self.info_label.setText(f"المعلومات:\nاسم الملف: {file_name}\nالحجم: تجريبي")
self.editor.setPlainText(f"محتوى {file_name}\n\n(هذا نص تجريبي يمكن استبداله بمحتوى حقيقي)")
if __name__ == "__main__":
app = QApplication(sys.argv)
win = DockApp()
win.show()
sys.exit(app.exec_())
⚙️ شرح سريع:
1-QDockWidget
أنشأنا Dock لليسار (قائمة ملفات) و Dock لليمين (معلومات).2-عند اختيار ملف من القائمة (
currentTextChanged
):- يتم تحديث Dock اليمين بمعلومات عن الملف.
- يتم عرض نص داخل المحرر في الوسط.
3-DockWidgetFloatable
تسمح بسحب الـ Dock كنافذة مستقلة.4-DockWidgetClosable
تسمح بإغلاق الـ Dock.💡 تطوير إضافي:
- استبدال "محتوى تجريبي" بقراءة محتوى الملف الفعلي من الهارد.
- إضافة قائمة عليا (MenuBar) فيها خيار "إظهار/إخفاء Docks".
- حفظ أماكن وأحجام الـ Dock عند الإغلاق (باستخدام
saveState()
وrestoreState()
).
🚀 النسخة المطورة — حفظ حالة الـ Dock وإعادتها تلقائيًا
✅ الكود
import sys
import os
from PyQt5.QtWidgets import (
QApplication, QMainWindow, QTextEdit, QDockWidget, QListWidget, QLabel, QWidget, QVBoxLayout
)
from PyQt5.QtCore import Qt, QSettings
class DockApp(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("تطبيق Dock مطور - حفظ الحالة")
self.resize(1000, 600)
# 🔹 1. المحرر الرئيسي
self.editor = QTextEdit()
self.editor.setPlainText("مرحبًا بك! اختر ملفًا من القائمة...")
self.setCentralWidget(self.editor)
# 🔹 2. Dock اليسار (قائمة الملفات)
self.file_dock = QDockWidget("قائمة الملفات", self)
self.file_dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)
self.file_list = QListWidget()
self.file_list.addItems([f"ملف_{i}.txt" for i in range(1, 6)])
self.file_list.currentTextChanged.connect(self.show_file_info)
self.file_dock.setWidget(self.file_list)
self.addDockWidget(Qt.LeftDockWidgetArea, self.file_dock)
# 🔹 3. Dock اليمين (معلومات)
self.info_dock = QDockWidget("معلومات الملف", self)
self.info_dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)
info_widget = QWidget()
info_layout = QVBoxLayout()
self.info_label = QLabel("لم يتم اختيار أي ملف بعد.")
info_layout.addWidget(self.info_label)
info_widget.setLayout(info_layout)
self.info_dock.setWidget(info_widget)
self.addDockWidget(Qt.RightDockWidgetArea, self.info_dock)
# 🔹 4. تمكين السحب (Float) والإغلاق
for dock in [self.file_dock, self.info_dock]:
dock.setFeatures(
QDockWidget.DockWidgetClosable
| QDockWidget.DockWidgetMovable
| QDockWidget.DockWidgetFloatable
)
# 🔹 5. تحميل الحالة السابقة إذا وجدت
self.settings = QSettings("tamer_company", "dock_app")
self.restoreGeometry(self.settings.value("geometry", b""))
self.restoreState(self.settings.value("windowState", b""))
def show_file_info(self, file_name):
"""تحديث Dock اليمين + المحرر عند اختيار ملف"""
if file_name:
self.info_label.setText(f"المعلومات:\nاسم الملف: {file_name}\nالحجم: تجريبي")
self.editor.setPlainText(
f"محتوى {file_name}\n\n(هذا نص تجريبي يمكن استبداله بمحتوى حقيقي)"
)
def closeEvent(self, event):
"""حفظ الحالة عند الإغلاق"""
self.settings.setValue("geometry", self.saveGeometry())
self.settings.setValue("windowState", self.saveState())
event.accept()
if __name__ == "__main__":
app = QApplication(sys.argv)
win = DockApp()
win.show()
sys.exit(app.exec_())
⚙️ شرح الإضافات الجديدة
QSettings("tamer_company", "dock_app")
→ يخزن الإعدادات في ملف تلقائي (على ويندوز في الريجستري، وعلى لينكس/ماك في ملف إعدادات).saveGeometry()
و saveState()
→ يحفظ حجم النافذة وحالة الـ Dock.restoreGeometry()
و restoreState()
→ يعيد الحالة كما كانت آخر مرة.closeEvent
→ عند إغلاق النافذة، نخزن الحالة قبل الخروج.
💡 التطوير المستقبلي
- إضافة زر إعادة ضبط الواجهة لمسح الحالة المحفوظة.
- جعل حفظ الحالة في ملف JSON بدل
QSettings
لو عايز تحكم أوضح في التخزين. - ربط Dock القائمة بفتح ملفات حقيقية من الجهاز بدل النص التجريبي.