Привет всем!
Так уж сложилось, что до сих пор мой опыт программирования предназначался для создания узкоспециализированных приложений. Так, профессиональное знание 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 Комментарии。