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

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

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

الدرس 11: التعامل مع QTableWidget لعرض البيانات بشكل جدولي

📌 ما هو QTableWidget؟

هو عنصر واجهة رسومية في PyQt يسمح بعرض البيانات على شكل جدول من صفوف وأعمدة، يشبه جداول Excel.
يمكننا من خلاله:

  • إضافة صفوف وأعمدة.
  • إدخال بيانات نصية أو أرقام داخل الخلايا.
  • تعديل وحذف البيانات.
  • التحكم في رأس الأعمدة والصفوف.
QTableWidget

📝 خطوات إنشاء جدول باستخدام Designer:

  1. افتح Qt Designer.
  2. أنشئ نافذة جديدة.
  3. من عناصر الواجهة اسحب QTableWidget وضعه في منتصف النافذة.
  4. من الخصائص (Property Editor):
    • غير اسم الجدول إلى tableWidget.
    • عدّل عدد الأعمدة مثلاً إلى 3.
    • سم الأعمدة (Name, Age, Country).
  5. أضف زر (QPushButton) باسم btnAddRow وعنوان "إضافة صف".
  6. أضف زر آخر باسم btnDeleteRow بعنوان "حذف الصف المحدد".
  7. احفظ الملف باسم:
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

  1. أضف زر جديد (QPushButton) بعنوان: 💾 حفظ في Excel.
  2. غير اسمه في الخصائص إلى:
btnSaveExcel
  1. احفظ التعديلات.

🎯 النتيجة

  • يمكن إدخال البيانات يدويًا في الجدول.
  • يمكن حذف الصفوف.
  • عند الضغط على زر 💾 حفظ في 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_())

✅ ما الجديد هنا؟

  1. أضفنا زر 📂 استيراد من Excel.
  2. عند الضغط عليه يتم فتح نافذة لاختيار ملف .xlsx أو .xls.
  3. يتم استخدام pandas لقراءة البيانات.
  4. يتم عرض البيانات داخل QTableWidget.

عن الكاتب

Tamer Ahmed

التعليقات


اتصل بنا

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

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

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