شرح التعامل مع SystemTray
انا بدأت فى ال QT مع ال C++ زى مانتو عارفين وبصراحة من افضل الطرق للتعليم هو إنك تطلع على ال Source code لأى برنامج هيفيد الواحد كتير .. ندخل فى الموضوع بإختصار فى برنامج فى ال Examples تبع ال QT بإسم systray هتلقيه تحت ال QT/Examples/Desktop
اول شئ ملف الresources ودا مضاف فيه بعض الصور اللى هتستخدم فى البرنامج
ثانيا فى تكنيك فى البرمجة بال C++ وهو إنك تكتب ال class من غير ماتعمل implement لل methods اللى فيه وتعمل ال implementation بتاعها بعدين ودا اللى إحنا هنعمله
شكل ال Application

لاحظ الApplication متقسم إلى
2 GroupBoxes
الأول هو TrayIcon وبيشمل
Label بإسم Icon:
و ComboBox فيه كذا Item زى Heart و Bad و Thrash
و CheckBox -> Show icon
التانى بيشمل
Label مكتوب عليه type
و ComboBox فيه الصور المستخدمة فى ال MessageBoxes ك informations
و Label مكتوب عليه Duration
و SpinBox
وبعد كدا Label بإسم title
وامامه LineEdit
وتحته Label مكتوب عليه body
وتحته RichEdit وفيه هيتكتب الرسالة اللى هتظهر !
واخيرا PushButton مكتوب عليه Show Message
نبدأ الشغل ..
افتح ال IDE اللى هتكتب فيها انا حاليا على Dev-C++
اولا اعمل ملف لل header وليكن window.h
هنضيف ال headers اللى هنستخدمها وهى ال Qwidget لأن دى ال Widget اللى هنشتق منها ال Class تبعنا
وال QsystemTrayIcon عشان نستخدم ال TrayIcon ...
بنعلن عن ال Classes اللى هنستخدمها
الQAction هى كل مايتم إضافته لل Menu
ال Class بتاعنا
لاحظ إنه إشتق من ال Qwidget
لازم إذا هيكون لل Class اللى بتاعك ال SLOTS/SIGNALS خاصة بيه لازم ال Q_OBJECT marco
ال Constructor ودالة تانية هنختص إنها تبقة مسؤلة عن ال Visibility هنخليهم public
هنضيف handler لل CloseEvent
نعلن عن ال SLOTS
الميمبرز اللى هنستخدمهم ولكن من غير ماتعمل اى initialization
ننهى التعريف
كدا إحنا عملنا التصميم المبدأى لل Class .. ندخل فى ال implementing ال code للميثودز و ال members
SAVE
افتح file جديد وسميه window.cpp
لازم نستدعى فيه
لأن فيه التصميم بتاع ال class اللى هنملاه
ونستدعى
عشان ال GUI Components
نبدأ فى إننا نعمل implementing لل Constructor زيه زى اى function !
لاحظ بما إنه ال Constructor فلازم يتم إنهاء التصميم الخاص بال GUI فيه فهنستدعى الدالتين اللى عايزينهم يصممو ال GUI قبل مانكتبهم حتى :D
وكمل الباقى ال Label وال CheckBox وباقى ال members
لاحظ
هنا تم ربط ال SLOTS بال SIGNALS .. إذا مش تعرف الفرق حاول تقرا اى توتريل
ال QVBoxLayout بيستخدم فى عمل GUI Layout Vertically
و YES ال QHBoxLayout بيستخدم فى عمله Horizontally
و YES تانى ال QGBoxLayout بيستخدم فى عمله بإستخدام GRID !
شكلك شاطر ياعم هههههههههه
ال setWindowsTitle بتستخدم فى وضع ال Title على ال Window!
ال resize لتحجيم ال Window
ال tr عشان لو ناوى تترجم برنامجك للغة تانية فى المستقبل ان شاء الله :D ويفضل إنك تضيفها على كل string هيظهر على اى window !
وبعد كدا ال setVisible method
وكل اللى فيها هو مراعاة ال ال items اللى فى ال trayicon's context menu تكون enabled او disabled حسب حال ال Window
ال setIcon هتستخدم ال index من ال iconComboBox عشان تحدد الicon اللى هتاخدها ال tray!
و setWindowIcon بتحدد ال icon اللى هتاخدها ال window
هى ال method المسئولة عن ال title وال body لل trayicon message
إذا تم الضغط على ال trayicon message هيظهر MessageBox فيه رسالة
"Sorry, I already gave what help I could.\n"
"Maybe you should try asking a human?"
فاكر ال createIconGroupBox وال createMessageGroupBox ?اللى إستخدمناهم فى ال Constructor ومش كاتبين فيها حاجة غير ال prototype ?
ادينا هنكتبهم
لاحظ إن انك تقدر تضيف icon فى combobox بإستخدام Qicon كأول بارميتر وتحدد فيه مسار الصورة و ويليه ال label اللى عايزه يظهر جمبها
واحد هيسأل فين مسار الصورة ؟ هجاوبك حالا بعد ماعلق على ال Layout
بنستخدم addWidget عشان نضيف اى widget ل Layout سواء Horizontal او Vertical او حتى GRID
اى layout ليه ميثود addLayout بتستخدم فى إننا نضيف اى Layout لل Layout الحالى .. هتشوفها بعدين
نكمل .. هنضع ال code الخاص ب create actions
عملنا كل اكشن منهم وربطنا ال SIGNAL و SLOT
عمل ال trayicon
لاحظ إن جزئية عمل ال trayicon متقسمة لجزئين
1- عمل ال Contextmenu الخاصة بال trayicon وهي trayIconMenu وضفنا فيها ال Actions اللى عملناها بالميثود السابقة بإستخدام addAction method
وال addSeperator بتضيف Seperator فى ال Menu
نعمل Object من ال trayIcon ونضيف ال contextMenu الخاصة بيها وهىtrayIconMenu بإستخدام
setContextMenu
بخصوص موضوع ال resources .. الصور موجودة عندك فى folder إسمه images ومتظبط ال resources file
systray.qrc
اعمل ملف main.cpp وهو هيكون ال Entry point لل Application بتاعنا
فى حال لو ال SystemTray غير متاح عندك هيطلع Error ويخرج من البرنامج غير كدا هيعمل Object من ال Window Class
بنستخدم show method عشان نخليه visible
وال return هو تنفيذ ال Application
بعد ماتخلص
افتح folder release وشغل!
البرنامج مرفق
بس كدا إيدى وجعتنى :S
انا بدأت فى ال QT مع ال C++ زى مانتو عارفين وبصراحة من افضل الطرق للتعليم هو إنك تطلع على ال Source code لأى برنامج هيفيد الواحد كتير .. ندخل فى الموضوع بإختصار فى برنامج فى ال Examples تبع ال QT بإسم systray هتلقيه تحت ال QT/Examples/Desktop
اول شئ ملف الresources ودا مضاف فيه بعض الصور اللى هتستخدم فى البرنامج
ثانيا فى تكنيك فى البرمجة بال C++ وهو إنك تكتب ال class من غير ماتعمل implement لل methods اللى فيه وتعمل ال implementation بتاعها بعدين ودا اللى إحنا هنعمله
شكل ال Application

لاحظ الApplication متقسم إلى
2 GroupBoxes
الأول هو TrayIcon وبيشمل
Label بإسم Icon:
و ComboBox فيه كذا Item زى Heart و Bad و Thrash
و CheckBox -> Show icon
التانى بيشمل
Label مكتوب عليه type
و ComboBox فيه الصور المستخدمة فى ال MessageBoxes ك informations
و Label مكتوب عليه Duration
و SpinBox
وبعد كدا Label بإسم title
وامامه LineEdit
وتحته Label مكتوب عليه body
وتحته RichEdit وفيه هيتكتب الرسالة اللى هتظهر !
واخيرا PushButton مكتوب عليه Show Message
نبدأ الشغل ..
افتح ال IDE اللى هتكتب فيها انا حاليا على Dev-C++
اولا اعمل ملف لل header وليكن window.h
كود:
#ifndef WINDOW_H #define WINDOW_H
وال QsystemTrayIcon عشان نستخدم ال TrayIcon ...
كود:
#include <QSystemTrayIcon> #include <Qwidget>
كود:
class QAction; class QCheckBox; class QComboBox; class QGroupBox; class QLabel; class QLineEdit; class QMenu; class QPushButton; class QSpinBox; class QtextEdit;
ال Class بتاعنا
كود:
class Window : public Qwidget
لازم إذا هيكون لل Class اللى بتاعك ال SLOTS/SIGNALS خاصة بيه لازم ال Q_OBJECT marco
ال Constructor ودالة تانية هنختص إنها تبقة مسؤلة عن ال Visibility هنخليهم public
كود:
public: Window(); void setVisible(bool visible);
كود:
protected: void closeEvent(QCloseEvent *event);
كود:
private slots: void setIcon(int index); void iconActivated(QSystemTrayIcon::ActivationReason reason); void showMessage(); void messageClicked(); الميثودز التالية هى اللى هنستخدمها فى عمل ال iconGroupBox وال MessageGroupBox وال Actions بتاعت ال menu وال trayicon private: void createIconGroupBox(); void createMessageGroupBox(); void createActions(); void createTrayIcon();
كود:
QGroupBox *iconGroupBox; QLabel *iconLabel; QComboBox *iconComboBox; QCheckBox *showIconCheckBox; QGroupBox *messageGroupBox; QLabel *typeLabel; QLabel *durationLabel; QLabel *durationWarningLabel; QLabel *titleLabel; QLabel *bodyLabel; QComboBox *typeComboBox; QSpinBox *durationSpinBox; QLineEdit *titleEdit; QTextEdit *bodyEdit; QPushButton *showMessageButton; QAction *minimizeAction; QAction *maximizeAction; QAction *restoreAction; QAction *quitAction; QSystemTrayIcon *trayIcon; QMenu *trayIconMenu;
كود:
}; #endif
SAVE
افتح file جديد وسميه window.cpp
لازم نستدعى فيه
كود:
#include "window.h"
ونستدعى
كود:
#include <QtGui>
نبدأ فى إننا نعمل implementing لل Constructor زيه زى اى function !
كود:
Window::Window() { createIconGroupBox(); createMessageGroupBox(); iconLabel->setMinimumWidth(durationLabel->sizeHint().width()); createActions(); createTrayIcon(); connect(showMessageButton, SIGNAL(clicked()), this, SLOT(showMessage())); connect(showIconCheckBox, SIGNAL(toggled(bool)), trayIcon, SLOT(setVisible(bool))); connect(iconComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setIcon(int))); connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(messageClicked())); connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason))); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(iconGroupBox); mainLayout->addWidget(messageGroupBox); setLayout(mainLayout); iconComboBox->setCurrentIndex(1); trayIcon->show(); setWindowTitle(tr("Systray")); resize(400, 300); }
كود:
createIconGroupBox(); createMessageGroupBox();
لاحظ
كود:
connect(showMessageButton, SIGNAL(clicked()), this, SLOT(showMessage())); connect(showIconCheckBox, SIGNAL(toggled(bool)), trayIcon, SLOT(setVisible(bool))); connect(iconComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setIcon(int))); connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(messageClicked())); connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
ال QVBoxLayout بيستخدم فى عمل GUI Layout Vertically
و YES ال QHBoxLayout بيستخدم فى عمله Horizontally
و YES تانى ال QGBoxLayout بيستخدم فى عمله بإستخدام GRID !
شكلك شاطر ياعم هههههههههه
ال setWindowsTitle بتستخدم فى وضع ال Title على ال Window!
ال resize لتحجيم ال Window
ال tr عشان لو ناوى تترجم برنامجك للغة تانية فى المستقبل ان شاء الله :D ويفضل إنك تضيفها على كل string هيظهر على اى window !
وبعد كدا ال setVisible method
كود:
void Window::setVisible(bool visible) { minimizeAction->setEnabled(visible); maximizeAction->setEnabled(!isMaximized()); restoreAction->setEnabled(isMaximized() || !visible); QWidget::setVisible(visible); }
كود:
void Window::setIcon(int index) { QIcon icon = iconComboBox->itemIcon(index); trayIcon->setIcon(icon); setWindowIcon(icon); trayIcon->setToolTip(iconComboBox->itemText(index)); }
و setWindowIcon بتحدد ال icon اللى هتاخدها ال window
كود:
void Window::showMessage() { QSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::MessageIcon( typeComboBox->itemData(typeComboBox->currentIndex()).toInt()); trayIcon->showMessage(titleEdit->text(), bodyEdit->toPlainText(), icon, durationSpinBox->value() * 1000); }
كود:
void Window::messageClicked() { QMessageBox::information(0, tr("Systray"), tr("Sorry, I already gave what help I could.\n" "Maybe you should try asking a human?")); }
"Sorry, I already gave what help I could.\n"
"Maybe you should try asking a human?"
فاكر ال createIconGroupBox وال createMessageGroupBox ?اللى إستخدمناهم فى ال Constructor ومش كاتبين فيها حاجة غير ال prototype ?
ادينا هنكتبهم
كود:
void Window::createIconGroupBox() { iconGroupBox = new QGroupBox(tr("Tray Icon")); iconLabel = new QLabel("Icon:"); iconComboBox = new QComboBox; iconComboBox->addItem(QIcon(":/images/bad.svg"), tr("Bad")); iconComboBox->addItem(QIcon(":/images/heart.svg"), tr("Heart")); iconComboBox->addItem(QIcon(":/images/trash.svg"), tr("Trash")); showIconCheckBox = new QCheckBox(tr("Show icon")); showIconCheckBox->setChecked(true); QHBoxLayout *iconLayout = new QHBoxLayout; iconLayout->addWidget(iconLabel); iconLayout->addWidget(iconComboBox); iconLayout->addStretch(); iconLayout->addWidget(showIconCheckBox); iconGroupBox->setLayout(iconLayout); }
واحد هيسأل فين مسار الصورة ؟ هجاوبك حالا بعد ماعلق على ال Layout
بنستخدم addWidget عشان نضيف اى widget ل Layout سواء Horizontal او Vertical او حتى GRID
اى layout ليه ميثود addLayout بتستخدم فى إننا نضيف اى Layout لل Layout الحالى .. هتشوفها بعدين
كود:
void Window::createMessageGroupBox() { messageGroupBox = new QGroupBox(tr("Balloon Message")); typeLabel = new QLabel(tr("Type:")); typeComboBox = new QComboBox; typeComboBox->addItem(tr("None"), QSystemTrayIcon::NoIcon); typeComboBox->addItem(style()->standardIcon( QStyle::SP_MessageBoxInformation), tr("Information"), QSystemTrayIcon::Information); typeComboBox->addItem(style()->standardIcon( QStyle::SP_MessageBoxWarning), tr("Warning"), QSystemTrayIcon::Warning); typeComboBox->addItem(style()->standardIcon( QStyle::SP_MessageBoxCritical), tr("Critical"), QSystemTrayIcon::Critical); typeComboBox->setCurrentIndex(1); durationLabel = new QLabel(tr("Duration:")); durationSpinBox = new QSpinBox; durationSpinBox->setRange(5, 60); durationSpinBox->setSuffix(" s"); durationSpinBox->setValue(15); durationWarningLabel = new QLabel(tr("(some systems might ignore this " "hint)")); durationWarningLabel->setIndent(10); titleLabel = new QLabel(tr("Title:")); titleEdit = new QLineEdit(tr("Cannot connect to network")); bodyLabel = new QLabel(tr("Body:")); bodyEdit = new QTextEdit; bodyEdit->setPlainText(tr("Don't believe me. Honestly, I don't have a " "clue.\nClick this balloon for details.")); showMessageButton = new QPushButton(tr("Show Message")); showMessageButton->setDefault(true); QGridLayout *messageLayout = new QGridLayout; messageLayout->addWidget(typeLabel, 0, 0); messageLayout->addWidget(typeComboBox, 0, 1, 1, 2); messageLayout->addWidget(durationLabel, 1, 0); messageLayout->addWidget(durationSpinBox, 1, 1); messageLayout->addWidget(durationWarningLabel, 1, 2, 1, 3); messageLayout->addWidget(titleLabel, 2, 0); messageLayout->addWidget(titleEdit, 2, 1, 1, 4); messageLayout->addWidget(bodyLabel, 3, 0); messageLayout->addWidget(bodyEdit, 3, 1, 2, 4); messageLayout->addWidget(showMessageButton, 5, 4); messageLayout->setColumnStretch(3, 1); messageLayout->setRowStretch(4, 1); messageGroupBox->setLayout(messageLayout); }
كود:
void Window::createActions() { minimizeAction = new QAction(tr("Mi&nimize"), this); connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide())); maximizeAction = new QAction(tr("Ma&ximize"), this); connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized())); restoreAction = new QAction(tr("&Restore"), this); connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal())); quitAction = new QAction(tr("&Quit"), this); connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); }
عمل ال trayicon
كود:
void Window::createTrayIcon() { trayIconMenu = new QMenu(this); trayIconMenu->addAction(minimizeAction); trayIconMenu->addAction(maximizeAction); trayIconMenu->addAction(restoreAction); trayIconMenu->addSeparator(); trayIconMenu->addAction(quitAction); trayIcon = new QSystemTrayIcon(this); trayIcon->setContextMenu(trayIconMenu); }
1- عمل ال Contextmenu الخاصة بال trayicon وهي trayIconMenu وضفنا فيها ال Actions اللى عملناها بالميثود السابقة بإستخدام addAction method
وال addSeperator بتضيف Seperator فى ال Menu
نعمل Object من ال trayIcon ونضيف ال contextMenu الخاصة بيها وهىtrayIconMenu بإستخدام
setContextMenu
بخصوص موضوع ال resources .. الصور موجودة عندك فى folder إسمه images ومتظبط ال resources file
systray.qrc
اعمل ملف main.cpp وهو هيكون ال Entry point لل Application بتاعنا
كود:
#include "window.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); if (!QSystemTrayIcon::isSystemTrayAvailable()) { QMessageBox::critical(0, QObject::tr("Systray"), QObject::tr("I couldn't detect any system tray " "on this system.")); return 1; } Window window; window.show(); return app.exec(); }
بنستخدم show method عشان نخليه visible
وال return هو تنفيذ ال Application
بعد ماتخلص
كود:
~> qmake -project ~> qmake systray.pro ~> make
البرنامج مرفق
بس كدا إيدى وجعتنى :S
تعليق