Привет всем!
Так уж сложилось, что до сих пор мой опыт программирования предназначался для создания узкоспециализированных приложений. Так, профессиональное знание Simpl+ и NetLinx помогает мне писать модули и программы для контроллеров Crestron и AMX, базовые знания PHP и MySQL раньше помогали создавать простые веб-сайты, а сейчас помогают писать небольшие скрипты для сетевых накопителей, классический С я использую в своих хобби-поделках для программирования 8-битных микроконтроллеров Silabs. Но, параллельно с этим, я все время хотел найти какую-нибудь среду для написания десктопных приложений.
Познакомьтесь, Qt! Кроссплатформенная среда для написания приложений на языке С++. Один и тот же код можно без изменений откомпилировать для Windows / Mac / Linux. Qt доступен как под коммерческой, так и под открытой лицензией. А последние планы по развитию среды впечатляют еще больше! Разработчики Qt поставили перед собой задачу поддержки почти всех основных мобильных платформ: iOS, Android и даже Windows RT! Таким образом, разработчик, владеющий инструментарием Qt, будет способен писать приложения "вообще для всего"!
Такие возможности мне показались убедительными для того, чтобы еще несколько лет назад купить в магазине учебник по Qt и попробовать освоить базовые концепции языка / среды в действии. Я написал несколько простейших программ, одной их которых хочу поделиться со всеми.
Программа Send Hotkey должна имитировать нажатие горячих клавиш на ПК, где она запущена. Основные требования к данной программы такие:
- автоматический запуск с Windows, блокирование запуска второго экземпляра;
- автоматическое сворачивание в системный трей, простое контекстное меню в трее;
- настройка порта для взаимодействия с внешней системой управления, сохранение номера порта в системном реестре;
- встроенная справка с примерами взаимодействия с программой;
- простая инсталляция / деинсталляция.
У меня нет цели выложить полные исходники данной программы, но основной файл "window.cpp" оказался менее 100 строк. Привожу его ниже:
#include "window.h" #include "ui_window.h" // конструктор Window::Window(QWidget *parent):QDialog(parent), ui(new Ui::Window) { // создаем объект типа QSharedMemory (строковой ключ сгенерирован заранее случайным образом) sm = new QSharedMemory("0E94CC22-CC9D-4C61-B0F5-34C9E738C21D"); if(sm->attach()) { // если смогли присоединиться к Shared Memory, значит это уже не первый экзмепляр программы, // выводим сообщение и завершаем программу QMessageBox::information(this, "Notice", "Already running in system tray!"); QTimer::singleShot(250, qApp, SLOT(quit())); return; } else { // иначе это первый экземпляр программы, создаем Shared Memory длиной 1 байт и продолжаем работу sm->create(1); } // инилиализируем пользовательский интерфейс ui->setupUi(this); // соединяем сигнал о наличии датаграмм UDP со слотом отправки горячих клавиш connect(&udpSocket, SIGNAL(readyRead()), this, SLOT(sendHotkeys())); // соединяем сигнал об изменении номера порта UDP со слотом обработки этого события // считываем номер порта из реестра, если он был изменен, иначе используем порт 50001 connect(ui->portSpinBox, SIGNAL(valueChanged(int)), this, SLOT(portChanged())); settings = new QSettings("HKEY_LOCAL_MACHINE\\SOFTWARE\\Caesium Tools\\Send Hotkey", QSettings::NativeFormat); ui->portSpinBox->setValue(settings->value("UDP Port", "50001").toInt()); // создаем 3 пункта контекстного меню settingsAction = new QAction(tr("&Settings"), this); connect(settingsAction, SIGNAL(triggered()), this, SLOT(settingsClick())); helpAction = new QAction(tr("&Help"), this); connect(helpAction, SIGNAL(triggered()), this, SLOT(needHelp())); quitAction = new QAction(tr("&Quit"), this); connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); // создаем само контекстное меню, добавляем в него созданные только что пункты trayIconMenu = new QMenu(this); trayIconMenu->addAction(settingsAction); trayIconMenu->addAction(helpAction); trayIconMenu->addAction(quitAction); // создаем значок в систсемном трее, добавляем контекстное меню, // делаем его видимым и сообщаем о нем пользователю trayIcon = new QSystemTrayIcon(this); trayIcon->setIcon(QIcon("button.png")); trayIcon->setContextMenu(trayIconMenu); trayIcon->show(); trayIcon->showMessage("Send Hotkey", "Send Hotkey is running!"); // соединяем сигнал активации значка в систсемном трее со слотом обработки этого события connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayIconClick(QSystemTrayIcon::ActivationReason))); // соединяем сигнал клика на строчку Help со слотом обработки этого события connect(ui->helpLabel, SIGNAL(linkActivated(QString)), this, SLOT(needHelp())); // устанавливаем флаги окна и значок диалогового окна this->setWindowFlags(Qt:: Dialog | Qt:: WindowStaysOnTopHint); this->setWindowIcon(QIcon("button.png")); } // стандартный деструктор Window::~Window() { delete ui; } // обработка события закрытия диалогового окна: просто скрываем окно // и сообщаем пользователю, что программа продолжает работу в трее void Window::closeEvent(QCloseEvent *event) { this->hide(); trayIcon->showMessage("Send Hotkey", "Send Hotkey continue running!"); event->ignore(); } // обрабатываем событие активации значка в трее: просто показываем диалоговое окно void Window::trayIconClick(QSystemTrayIcon::ActivationReason reason) { if(reason!=QSystemTrayIcon::Context) this->showNormal(); } // обрабатываем пункт контекстного меню Settings void Window::settingsClick() { this->showNormal(); } // обрабатываем смену порта, сохраняем новый порт в реестре, связываем новый порт с сокетом void Window::portChanged(void) { settings->setValue("UDP Port", ui->portSpinBox->value()); udpSocket.close(); udpSocket.bind(ui->portSpinBox->value()); } // обработка датаграмм UDP, отправка кодов нажатия и отпускания клавиш в ОС void Window::sendHotkeys(void) { QByteArray b; b.resize(udpSocket.pendingDatagramSize()); udpSocket.readDatagram(b.data(), b.size()); for(int i=0; i<b.length(); i++) keybd_event(b[i], 0, 0, 0); for(int i=b.length()-1; i>=0; i--) keybd_event(b[i], 0, KEYEVENTF_KEYUP, 0); } // обработка зароса помощи (строка Help в диалоговом окне программы или пункт Help контекстного меню) void Window::needHelp(void) { this->hide(); QProcess::execute("hh.exe help.chm"); }
В качестве инструмента для создания инсталлятора отлично подошел еще один свободный продукт - Inno Setup. Инсталляторы с его помощью создаются быстро и качественно, а множество встроенных примеров и понятная справка ускоряют процесс. В общем, рекомендую.
Ну и если уж вы дошли до этого текста, то, вероятно, для тестирования программы Send Hotkey вам пригодится отличная Freeware-утилита UDP Test Tool. Скачивается после регистрации.
Саму программу Send Hotkey можно скачать прямо здесь: Send_Hotkey_1.1.001_Setup. Я протестировал ее на виртуальных Windows XP SP2 и Windows 7 x64. Буду рад отзывам о реальном применении моей программы!
0 Комментарии。