Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: linuxoid от Октябрь 11, 2007, 15:33



Название: Помогите пожалуйста обратиться к окну
Отправлено: linuxoid от Октябрь 11, 2007, 15:33
Ситуация следующая: я в QProcess выполняю команду вследствии которой открывается окно с программой. Так вот как мне обратиться к этому окну в событии???
Я хочу передать при нажатии на кнопку в своём виджете исскуственное событие нажатия клавиши клавиатуры, а чтобы это сделать мне нужно как-то обратиться к нему!Может быть есть какое-нить событие перехватывающее появление нового окна?помогите чем кто может пожалуйста!


Название: Re: Помогите пожалуйста обратиться к окну
Отправлено: Steven_Orko от Октябрь 11, 2007, 15:54
Никак. То, что ты хочешь сделать, можно только с помощью платформо-зависимых средств. Посмотри доки по оконным менеджерам и т.д. и т.п. В для Windows - findWindow по имени окна, в Linux XQueryTree и просматриваешь атрибуты окна.


Название: Re: Помогите пожалуйста обратиться к окну
Отправлено: linuxoid от Октябрь 12, 2007, 08:01
а сигналов случаем нету для такого дела?


Название: Re: Помогите пожалуйста обратиться к окну
Отправлено: Steven_Orko от Октябрь 12, 2007, 08:43
Используя QProcess, ты запускаешь НОВЫЙ процесс.

1. Для того, чтобы один процесс что-то сообщил другому, необходимо использовать DCOP или DBus (Возможен вариант самописного механизма обмена). Совсем не обязательно, что разработчик программы, чей процесс ты пытаешься запустить, вообще знаешь о таких вещах. Возможно они появились позже момента создания программы.
2.
Для получения сообщения тебе в своей программе также необходима привязка к DCOP или DBus. Это у тебя есть?
3. Ну и предпоследнее. Откуда постороннему процессу знать, что ты хочешь получить от него сообщение о появлении окна? И какого именно окна? Верно, не знает.
4. Если говорить о QProcess, то класс слишком разрастется, если в него еще добавить распознавание, что за процесс запускается: с GUI или без.

Вот такими рассуждениями приходим к выводу, что сигнала специального нет.

Как я уже говорил, тебе надо просто после запуска процесса перебрать все созданные окна на предмет наличия окна запускаемого процесса. Название окна ты ведь знаешь. Сравнишь, получишь  какой-нибудь UID или HANDLE окна. Ну а дальше уже посылай ему сообщения. Все это делается только платформо-зависимыми средствами. Для Linux тебе придется использовать Xlib, для винды не помню имя либы, но по названию функции FindWindow в MSDN найдешь ее описание.
Тут уже как тебе будет легче. Если для одной платформы, то ее и используй, если для двух, то условная компиляция тебе в руки. )))


Название: Re: Помогите пожалуйста обратиться к окну
Отправлено: Emc от Октябрь 12, 2007, 14:16
ну можно слушать standardOutput - а при открытие окна выдавать спец сообщение (winId например), а потом QWidget::find ( WId id )


Название: Re: Помогите пожалуйста обратиться к окну
Отправлено: T800 от Октябрь 17, 2007, 13:07
Ну если пошла такая пьянка, то для общения между процессами (даже между разными программами на одной машине) можно и TCP/IP-стек использовать. А вот если хочется имитировать именно ввод с клавиатуры, то придется использовать платформу.


Название: Re: Помогите пожалуйста обратиться к окну
Отправлено: linuxoid от Октябрь 19, 2007, 09:43
НУ спасибо люди добрые!Вы меня конечно не обрадовали, но информации вполне достаточно для продвижения!С П А С И Б О!


Название: Re: Помогите пожалуйста обратиться к окну
Отправлено: linuxoid от Октябрь 19, 2007, 16:29
Чё то я никак не могу продвинуться может будут у кого ещё какие нить соображения ???


Название: Re: Помогите пожалуйста обратиться к окну
Отправлено: Racheengel от Октябрь 22, 2007, 22:43
та вторая прога тоже твоя?
или нет?


Название: Re: Помогите пожалуйста обратиться к окну
Отправлено: linuxoid от Октябрь 23, 2007, 13:31
НЕД


Название: Re: Помогите пожалуйста обратиться к окну
Отправлено: Steven_Orko от Октябрь 23, 2007, 17:28
Рассказываю, как это можно сделать под Линукс описанным мною выше способом, ибо под Винду щас ничего не пишу.

Часть 1.
1. Запускаешь ту программу, в окно которой тебе надо послать сообщение.
2. Смотришь название окна.

Часть вторая.
Существует несколько спецификация для оконных менеджеров. Некоторые оконные менеджеры могут вообще ее не поддерживать. Однако, исторически склалось, что в Линуксе окно имеет несколько атрибутов. Один из аттрибутов - это как раз то самое название окна, которое ты видишь на экране в полосочке наверху.
Читаем XLIB Reference Manual и видим, что за получение значения этого аттрибута отвечает функция

Status XFetchName(Display *display,  Window w, char **window_name_return).
Первый параметр - это структура дисплея, которую ты можешь получить через qt_xdisplay() (Qt 3 series).
Второй параметр - это идентификатор окна, у которого надо подсмотреть название.
В третий параметр возвращается само название. Только фигня в том, что эта строка может быть в разных форматах.
Так, например, если название только из латинских букв, то это будет обычный string, если там есть национальные буквы, то это будет скорее всего COMPOUD_STRING, если не ошибся с написанием типа.

Часть 3.
Как я уже говорил про спецификации для оконных менеджеров, их много. Но есть одна спецификация, которой стараются придерживаться KDE и Gnome, - это icccm. Причем есть несколько версий, на данный момент последняя 2 с хвостиком.
Также на сайте KDE можно найти спецификацию для их оконного менеджера, в которой уже есть новый атрибут у окна, содержащий его название, причем в UNICODE, что несколько облегчает жизнь. Причем, там же упоминается, что, если этот новый атрибут окна существует, то надо использовать именно его. Я считываю его таким образом:

Код:
int iCount = 0;
Atom atom_NET_WM_NAME = XInternAtom(qt_xdisplay(), "_NET_WM_NAME", false);
Atom* pAtoms = XListProperties(qt_xdisplay(), wID, &iCount);

bool bExist = false;
for (int iIndex = 0; iIndex < iCount; ++iIndex)
{
if (pAtoms[iIndex] == atom_NET_WM_NAME)
{
bExist = true;
break;
}
}

if (bExist)
{
std::vector<unsigned char> propertyValue = charProperty(atom_NET_WM_NAME, wID);
return toTypeUTF8_STRING(propertyValue);
} else
{
QString strWM_NAME;
char *cName;
Status retCode = XFetchName(qt_xdisplay(), wID, &cName);
strWM_NAME = cName;
if (0 != retCode) XFree(cName);
return strWM_NAME;
}

Часть 4.
Тебе надо перебрать все открытые окна, на премет нахождения того, которое тебе надо. Я в своей недоделанной проге делаю так:
Код:
Window* lstChldWindow; //Массив дочерних окон корневого окна
unsigned int iCountChildWindow;   //Количество элементов в массиве
//Получаю массив дочерних окон корневого окна
Status iResult = XQueryTree(qt_xdisplay(), static_cast<Window>(wID), &rootWindow, &parentWindow, &lstChldWindow, &iCountChildWindow);

Далее, для каждого окна из этого массива можно опять получить список дочерних окон, и так рекурсивно просмотреть все видимые окна, пока не найдешь то, которое тебе надо по названию.
Узнать, видимое окно, или нет, можно из результатов выполнения функции:

Код:
XWindowAttributes attrWnd;
XGetWindowAttributes(qt_xdisplay(), wID, &attrWnd);
Здесь все просто:
Первый параметр - указатель на структуру дисплея.
Второй - идентификатор окна,
Третий - указатель на структуру аттрибутов окна.

Ремарка. Сорри, возможно я тебя запутал. На самом деле, имя окна и другая инфа - это свойства окна, а вот аттрибуты - это было только что выше.

Часть 5.
Тут ты уже имеешь идентификатор окна, которое тебе надо. Осталось послать ему событие. Для этого Xlib тоже имеет необходимые функции:

Код:
XSendEvent(Display* display, Window w, Bool propagate, long event_mask, XEvent* event_send);


typedef struct {
        int type;
        unsigned long serial;
        Bool send_event;
        Display *display;
        Window window;
        Atom message_type;
        int format;
        union {
                 char b[20];
                 short s[10];
                 long l[5];
              } data;
} XClientMessageEvent;


Часть заключительная.
В итоге, то самое стороннее окно получит событие от сервера X, как если бы это событие породил пользователь. Вот и все. Тебе осталось почитать маны по Xlib, и у тебя все получится.

Чтобы это сделать для Винды, попроси еще кого-нибудь. Но алгоритм все равно тот же: найти окно, послать ему сообщение средствами платформы (в данном случае Винды).


P.S. Орфографию не проверяю, т.к. уже уходить надо. Удачи.



Название: Re: Помогите пожалуйста обратиться к окну
Отправлено: Tonal от Октябрь 24, 2007, 06:44
Да, для винды примерно так же.
FindWindow - поиск по имени или классу (можно подсмотреть Spy++ или подобными утилитами)
И посылка нужного сообщения.

Кроме того, есть функции для эмуляции действий мыши или клавиатуры.


Название: Re: Помогите пожалуйста обратиться к окну
Отправлено: linuxoid от Октябрь 24, 2007, 08:49
ну спасибо Дружище!!о таком подробном ответе можно было только мечтать) Теперь есть от чего оттолкнуться!Обращайся если нужно будет помочь ;)