📌 ما هو QTableWidget؟
هو عنصر واجهة رسومية في PyQt يسمح بعرض البيانات على شكل جدول من صفوف وأعمدة، يشبه جداول Excel.
يمكننا من خلاله:
- إضافة صفوف وأعمدة.
- إدخال بيانات نصية أو أرقام داخل الخلايا.
- تعديل وحذف البيانات.
- التحكم في رأس الأعمدة والصفوف.
📝 خطوات إنشاء جدول باستخدام Designer:
- افتح Qt Designer.
- أنشئ نافذة جديدة.
- من عناصر الواجهة اسحب QTableWidget وضعه في منتصف النافذة.
- من الخصائص (Property Editor):
- غير اسم الجدول إلى
tableWidget
. - عدّل عدد الأعمدة مثلاً إلى 3.
- سم الأعمدة (Name, Age, Country).
- غير اسم الجدول إلى
- أضف زر (
QPushButton
) باسمbtnAddRow
وعنوان "إضافة صف". - أضف زر آخر باسم
btnDeleteRow
بعنوان "حذف الصف المحدد". - احفظ الملف باسم:
table_example.ui
💻 الكود البرمجي:
import sys
from PyQt5 import QtWidgets, uic
from PyQt5.QtWidgets import QTableWidgetItem, QMessageBox
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
uic.loadUi("table_example.ui", self)
# ربط الأزرار بالدوال
self.btnAddRow.clicked.connect(self.add_row)
self.btnDeleteRow.clicked.connect(self.delete_row)
# ضبط عدد الأعمدة وعناوينها
self.tableWidget.setColumnCount(3)
self.tableWidget.setHorizontalHeaderLabels(["Name", "Age", "Country"])
def add_row(self):
# إضافة صف جديد
row_position = self.tableWidget.rowCount()
self.tableWidget.insertRow(row_position)
# تعبئة افتراضية (يمكنك تعديلها لاحقًا)
self.tableWidget.setItem(row_position, 0, QTableWidgetItem("User"))
self.tableWidget.setItem(row_position, 1, QTableWidgetItem("20"))
self.tableWidget.setItem(row_position, 2, QTableWidgetItem("Egypt"))
def delete_row(self):
# حذف الصف المحدد
selected_row = self.tableWidget.currentRow()
if selected_row >= 0:
self.tableWidget.removeRow(selected_row)
else:
QMessageBox.warning(self, "تنبيه", "الرجاء اختيار صف لحذفه")
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
🎯 النتيجة:
- عند تشغيل البرنامج يظهر جدول بثلاثة أعمدة (Name – Age – Country).
- بالضغط على زر إضافة صف تتم إضافة بيانات جديدة بشكل افتراضي.
- يمكن حذف أي صف بتحديده والضغط على حذف الصف المحدد.
📌 في التمرين القادم سنطور هذا الدرس بحيث يتم إدخال البيانات يدويًا عبر نوافذ إدخال (QInputDialog) بدل القيم الافتراضية.
✅ التمرين
قم بإنشاء واجهة تحتوي على:
- جدول (QTableWidget) بثلاثة أعمدة: Name – Age – Country.
- زر بعنوان "➕ إضافة بيانات".
- زر بعنوان "❌ حذف الصف المحدد".
🔹 عند الضغط على زر إضافة بيانات:
- يظهر للمستخدم مربع إدخال (QInputDialog) يطلب منه إدخال الاسم، العمر، والدولة.
- ثم تضاف هذه القيم في صف جديد داخل الجدول.
🔹 عند الضغط على زر حذف الصف المحدد:
- يتم حذف الصف الذي قام المستخدم بتحديده.
💻 الحل
import sys
from PyQt5 import QtWidgets, uic
from PyQt5.QtWidgets import QTableWidgetItem, QMessageBox, QInputDialog
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
uic.loadUi("table_example.ui", self)
# ربط الأزرار بالدوال
self.btnAddRow.clicked.connect(self.add_row)
self.btnDeleteRow.clicked.connect(self.delete_row)
# ضبط الأعمدة
self.tableWidget.setColumnCount(3)
self.tableWidget.setHorizontalHeaderLabels(["Name", "Age", "Country"])
def add_row(self):
# إدخال البيانات عبر QInputDialog
name, ok1 = QInputDialog.getText(self, "إدخال الاسم", "أدخل الاسم:")
if not ok1 or name.strip() == "":
return
age, ok2 = QInputDialog.getInt(self, "إدخال العمر", "أدخل العمر:", min=1, max=120)
if not ok2:
return
country, ok3 = QInputDialog.getText(self, "إدخال الدولة", "أدخل الدولة:")
if not ok3 or country.strip() == "":
return
# إضافة الصف للجدول
row_position = self.tableWidget.rowCount()
self.tableWidget.insertRow(row_position)
self.tableWidget.setItem(row_position, 0, QTableWidgetItem(name))
self.tableWidget.setItem(row_position, 1, QTableWidgetItem(str(age)))
self.tableWidget.setItem(row_position, 2, QTableWidgetItem(country))
def delete_row(self):
# حذف الصف المحدد
selected_row = self.tableWidget.currentRow()
if selected_row >= 0:
self.tableWidget.removeRow(selected_row)
else:
QMessageBox.warning(self, "تنبيه", "الرجاء اختيار صف لحذفه")
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
🎯 النتيجة
- عند الضغط على زر ➕ إضافة بيانات، تظهر نوافذ إدخال واحدة تلو الأخرى (اسم – عمر – دولة).
- بعد إدخال البيانات، تتم إضافتها مباشرة في جدول QTableWidget.
- عند تحديد صف والضغط على زر ❌ حذف الصف المحدد، يتم حذفه من الجدول.
✅ النسخة المطورة – حفظ البيانات في Excel
📦 المتطلبات
قبل التشغيل، يجب تثبيت مكتبة openpyxl (إذا لم تكن مثبتة):
pip install openpyxl
💻 الكود
import sys
from PyQt5 import QtWidgets, uic
from PyQt5.QtWidgets import QTableWidgetItem, QMessageBox, QInputDialog, QFileDialog
from openpyxl import Workbook
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
uic.loadUi("table_example.ui", self)
# ربط الأزرار بالدوال
self.btnAddRow.clicked.connect(self.add_row)
self.btnDeleteRow.clicked.connect(self.delete_row)
# زر جديد لحفظ البيانات في Excel
self.btnSaveExcel.clicked.connect(self.save_to_excel)
# ضبط الأعمدة
self.tableWidget.setColumnCount(3)
self.tableWidget.setHorizontalHeaderLabels(["Name", "Age", "Country"])
def add_row(self):
# إدخال البيانات عبر QInputDialog
name, ok1 = QInputDialog.getText(self, "إدخال الاسم", "أدخل الاسم:")
if not ok1 or name.strip() == "":
return
age, ok2 = QInputDialog.getInt(self, "إدخال العمر", "أدخل العمر:", min=1, max=120)
if not ok2:
return
country, ok3 = QInputDialog.getText(self, "إدخال الدولة", "أدخل الدولة:")
if not ok3 or country.strip() == "":
return
# إضافة الصف للجدول
row_position = self.tableWidget.rowCount()
self.tableWidget.insertRow(row_position)
self.tableWidget.setItem(row_position, 0, QTableWidgetItem(name))
self.tableWidget.setItem(row_position, 1, QTableWidgetItem(str(age)))
self.tableWidget.setItem(row_position, 2, QTableWidgetItem(country))
def delete_row(self):
# حذف الصف المحدد
selected_row = self.tableWidget.currentRow()
if selected_row >= 0:
self.tableWidget.removeRow(selected_row)
else:
QMessageBox.warning(self, "تنبيه", "الرجاء اختيار صف لحذفه")
def save_to_excel(self):
# اختيار اسم الملف لحفظ البيانات
file_path, _ = QFileDialog.getSaveFileName(self, "حفظ البيانات", "", "Excel Files (*.xlsx)")
if file_path:
workbook = Workbook()
sheet = workbook.active
sheet.title = "Data"
# كتابة عناوين الأعمدة
headers = ["Name", "Age", "Country"]
sheet.append(headers)
# كتابة البيانات من الجدول
for row in range(self.tableWidget.rowCount()):
row_data = []
for col in range(self.tableWidget.columnCount()):
item = self.tableWidget.item(row, col)
row_data.append(item.text() if item else "")
sheet.append(row_data)
# حفظ الملف
workbook.save(file_path)
QMessageBox.information(self, "تم الحفظ", f"تم حفظ البيانات في الملف:\n{file_path}")
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
📝 التعديلات المطلوبة في Designer
- أضف زر جديد (
QPushButton
) بعنوان: 💾 حفظ في Excel. - غير اسمه في الخصائص إلى:
btnSaveExcel
- احفظ التعديلات.
🎯 النتيجة
- يمكن إدخال البيانات يدويًا في الجدول.
- يمكن حذف الصفوف.
- عند الضغط على زر 💾 حفظ في Excel، يفتح مربع حوار لاختيار مكان الحفظ.
- يتم إنشاء ملف Excel يحتوي على الأعمدة والبيانات المدخلة.
سنضيف ميزة استيراد البيانات من ملف Excel إلى التطبيق الذي عرضناه سابقًا (جدول مع إمكانية الحفظ في CSV).
الخطوة 1: المكتبات المطلوبة
سنحتاج إلى مكتبة pandas لقراءة ملفات Excel بسهولة:
pip install pandas openpyxl
الخطوة 2: الكود مع ميزة الاستيراد من Excel
import sys
import pandas as pd
from PyQt5.QtWidgets import (
QApplication, QMainWindow, QWidget, QVBoxLayout,
QPushButton, QTableWidget, QTableWidgetItem,
QFileDialog, QMessageBox
)
class ExcelImporter(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("استيراد بيانات من Excel")
self.setGeometry(200, 200, 700, 400)
# الواجهة
self.central_widget = QWidget()
self.setCentralWidget(self.central_widget)
self.layout = QVBoxLayout(self.central_widget)
# الجدول
self.table = QTableWidget()
self.layout.addWidget(self.table)
# زر استيراد
self.btn_import = QPushButton("📂 استيراد من Excel")
self.btn_import.clicked.connect(self.import_from_excel)
self.layout.addWidget(self.btn_import)
def import_from_excel(self):
# اختيار ملف Excel
options = QFileDialog.Options()
file_name, _ = QFileDialog.getOpenFileName(
self,
"اختر ملف Excel",
"",
"Excel Files (*.xlsx *.xls)",
options=options
)
if file_name:
try:
# قراءة البيانات باستخدام pandas
df = pd.read_excel(file_name)
# ضبط الجدول
self.table.setRowCount(df.shape[0])
self.table.setColumnCount(df.shape[1])
self.table.setHorizontalHeaderLabels(df.columns)
# ملء البيانات في الجدول
for row in range(df.shape[0]):
for col in range(df.shape[1]):
self.table.setItem(row, col, QTableWidgetItem(str(df.iat[row, col])))
QMessageBox.information(self, "نجاح", "✅ تم استيراد البيانات بنجاح!")
except Exception as e:
QMessageBox.critical(self, "خطأ", f"حدث خطأ أثناء استيراد الملف:\n{e}")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = ExcelImporter()
window.show()
sys.exit(app.exec_())
✅ ما الجديد هنا؟
- أضفنا زر 📂 استيراد من Excel.
- عند الضغط عليه يتم فتح نافذة لاختيار ملف
.xlsx
أو.xls
. - يتم استخدام pandas لقراءة البيانات.
- يتم عرض البيانات داخل QTableWidget.