الفكرة: بعد ما عرفنا Radio و CheckBox، نحتاج طريقة لتجميع الأزرار في مجموعات مستقلة بحيث:
- كل مجموعة Radio تكون حصرية داخلها (اختيار واحد فقط لكل مجموعة).
- نقدر نعرف أي زر انضغط داخل المجموعة عن طريق معرّف (ID).
- نعرض المجموعات داخل
QGroupBoxلتمييزها بصريًا.
أهم النقاط
QButtonGroup:addButton(button, id)لإضافة زر مع رقم معرف.- الإشارة
buttonClicked[int]تعطينا الـ id للزر المضغوط. setExclusive(True)لجعل المجموعة حصرية (مفيد لـ Radio).
QGroupBox: صندوق بعنوان لتجميع عناصر الواجهة.
مثال عملي: مجموعتان مستقلتان
- مجموعة 1 (Radio): النوع — فرد/شركة
- مجموعة 2 (Radio): الخطة — أساسي/احترافي/مؤسسي
- زر “تلخيص” يعرض الاختيارات.
import sys
from PyQt5.QtWidgets import (
QApplication, QWidget, QRadioButton, QVBoxLayout, QHBoxLayout,
QGroupBox, QLabel, QPushButton, QButtonGroup
)
class GroupingDemo(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("الدرس 12 - QButtonGroup و QGroupBox")
self.setGeometry(200, 200, 480, 300)
main_layout = QVBoxLayout()
# ===== المجموعة الأولى: النوع =====
type_box = QGroupBox("النوع")
type_layout = QVBoxLayout(type_box)
self.rb_personal = QRadioButton("فرد")
self.rb_company = QRadioButton("شركة")
self.rb_personal.setChecked(True)
type_layout.addWidget(self.rb_personal)
type_layout.addWidget(self.rb_company)
self.type_group = QButtonGroup(self)
self.type_group.setExclusive(True)
self.type_group.addButton(self.rb_personal, 1)
self.type_group.addButton(self.rb_company, 2)
# ===== المجموعة الثانية: الخطة =====
plan_box = QGroupBox("الخطة")
plan_layout = QVBoxLayout(plan_box)
self.rb_basic = QRadioButton("أساسي")
self.rb_pro = QRadioButton("احترافي")
self.rb_enterprise = QRadioButton("مؤسسي")
self.rb_basic.setChecked(True)
plan_layout.addWidget(self.rb_basic)
plan_layout.addWidget(self.rb_pro)
plan_layout.addWidget(self.rb_enterprise)
self.plan_group = QButtonGroup(self)
self.plan_group.setExclusive(True)
self.plan_group.addButton(self.rb_basic, 10)
self.plan_group.addButton(self.rb_pro, 20)
self.plan_group.addButton(self.rb_enterprise, 30)
# ===== زر التلخيص + النتيجة =====
self.result_label = QLabel("")
summarize_btn = QPushButton("تلخيص الاختيارات")
summarize_btn.clicked.connect(self.summarize)
# ترتيب المجموعات أفقياً
groups_row = QHBoxLayout()
groups_row.addWidget(type_box)
groups_row.addWidget(plan_box)
main_layout.addLayout(groups_row)
main_layout.addWidget(summarize_btn)
main_layout.addWidget(self.result_label)
self.setLayout(main_layout)
# (اختياري) تتبع التغييرات فوراً
self.type_group.buttonClicked[int].connect(self.on_type_changed)
self.plan_group.buttonClicked[int].connect(self.on_plan_changed)
def current_type_text(self):
if self.rb_personal.isChecked():
return "فرد"
return "شركة"
def current_plan_text(self):
if self.rb_basic.isChecked():
return "أساسي"
if self.rb_pro.isChecked():
return "احترافي"
return "مؤسسي"
def summarize(self):
t = self.current_type_text()
p = self.current_plan_text()
self.result_label.setText(f"النوع: {t} — الخطة: {p}")
def on_type_changed(self, id_):
# أمثلة: تسجيل/تصحيح/تفعيل منطق إضافي
# print("Type changed id:", id_)
pass
def on_plan_changed(self, id_):
# print("Plan changed id:", id_)
pass
if __name__ == "__main__":
app = QApplication(sys.argv)
w = GroupingDemo()
w.show()
sys.exit(app.exec_())
ملاحظات سريعة
- استخدم
QButtonGroupعندما تحتاج تمييز أي زر انضغط عبر id بدل فحصisChecked()لكل زر. - يمكن عمل أكثر من مجموعة في نفس النافذة وكل مجموعة تعمل باستقلال.
QGroupBoxيعطيك عنوانًا وتأطيرًا يجمل الواجهة ويُنظّمها بصريًا.
تمرين تطبيقي
المطلوب:
- مجموعة Radio لــ طريقة الدفع: بطاقة، تحويل بنكي، باي بال.
- مجموعة Radio للــ دورة الدفع: شهري، سنوي.
- زر “استكمال” يعرض ملخصًا مثل:
الدفع: بطاقة — الدورة: سنوي
الحل:
import sys
from PyQt5.QtWidgets import (
QApplication, QWidget, QRadioButton, QVBoxLayout, QHBoxLayout,
QGroupBox, QLabel, QPushButton, QButtonGroup
)
class PaymentForm(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("تمرين - تجميع أزرار الدفع")
self.setGeometry(250, 250, 480, 260)
main = QVBoxLayout()
# طريقة الدفع
pay_box = QGroupBox("طريقة الدفع")
v1 = QVBoxLayout(pay_box)
self.rb_card = QRadioButton("بطاقة")
self.rb_bank = QRadioButton("تحويل بنكي")
self.rb_paypal = QRadioButton("PayPal")
self.rb_card.setChecked(True)
for w in (self.rb_card, self.rb_bank, self.rb_paypal):
v1.addWidget(w)
self.pay_group = QButtonGroup(self)
self.pay_group.addButton(self.rb_card, 101)
self.pay_group.addButton(self.rb_bank, 102)
self.pay_group.addButton(self.rb_paypal, 103)
# دورة الدفع
cycle_box = QGroupBox("دورة الدفع")
v2 = QVBoxLayout(cycle_box)
self.rb_monthly = QRadioButton("شهري")
self.rb_yearly = QRadioButton("سنوي")
self.rb_monthly.setChecked(True)
v2.addWidget(self.rb_monthly)
v2.addWidget(self.rb_yearly)
self.cycle_group = QButtonGroup(self)
self.cycle_group.addButton(self.rb_monthly, 201)
self.cycle_group.addButton(self.rb_yearly, 202)
# صفّ تجميع المجموعتين
row = QHBoxLayout()
row.addWidget(pay_box)
row.addWidget(cycle_box)
self.result = JLabel = QLabel("")
submit = QPushButton("استكمال")
submit.clicked.connect(self.summary)
main.addLayout(row)
main.addWidget(submit)
main.addWidget(self.result)
self.setLayout(main)
def summary(self):
pay = "بطاقة" if self.rb_card.isChecked() else ("تحويل بنكي" if self.rb_bank.isChecked() else "PayPal")
cycle = "شهري" if self.rb_monthly.isChecked() else "سنوي"
self.result.setText(f"الدفع: {pay} — الدورة: {cycle}")
if __name__ == "__main__":
app = QApplication(sys.argv)
w = PaymentForm()
w.show()
sys.exit(app.exec_())

