Экспертная система Delphi.int.ru

Сообщество программистов
Общение, помощь, обмен опытом

Логин:
Пароль:
Регистрация | Забыли пароль?

Delphi.int.ru Expert

Другие разделы портала

Переход к вопросу:

#   

Статистика за сегодня:  


Лучшие эксперты

Подробнее »



Вопрос # 5 625

/ вопрос открыт /

Приветствую, уважаемые эксперты! Я скомпилил окно, в котором нет заголовка и имеется возможность убирать/восстанавливать кнопку окна на панеле задачь.

У меня есть 3 вопроса:

* Как отредактировать меню "ALT+SPACE" - нужно полностью его заменить на своё;
* Как отредактировать контекст кнопки на панели задачь - аналогично нужно заменить его на свой;
* Как можно найти в окне определённый объект, переместить в его центр указатель мыши, сменить его вид (указателя) и отправить сообщение, что нажата левая кнопка мыши - это замена процедуры "Переместить" для контекстного меню, чтоб можно было сделать это только с помощью клавиатуры;

Спасибо

К вопросу прикреплён файл. Загрузить » (срок хранения: 60 дней с момента отправки вопроса)

Приложение:
  1. WinXP SP3 x86 :: Delphi XE


Фео Вопрос ожидает решения (принимаются ответы, доступен мини-форум)

Вопрос задал: Фео (статус: Посетитель)
Вопрос отправлен: 7 сентября 2011, 00:36
Состояние вопроса: открыт, ответов: 1.

Ответ #1. Отвечает эксперт: Вадим К

Здравствуйте, Фео!
Это называется "системное меню окна". Заменить можно, просто немного нестандартно.
вначале с помощью GetSystemMenu получаем хендл. Потом с помощью DeleteMenu удаляем ненужные пункты (может быть и можно все сразу удалить, но я такого не знаю). А потом с помощью InsertMenu наставляем нужных. Для деталей читаем тут и тут.
А вот меню на панели задач - тут чуточку интересней. В старых версиях делфи (до 2007 вроде), это было отдельное окно и системное меню нужно менять отдельно. Потом появилась возможность делать кнопку на панели задач прямо от окна (в этом случае системное меню должно совпадать). Тут я могу порекомендовать только эксперименты.

По поводу последнего пункта... тут в принципе нет ничего сложного.
- найти элемент... приложение Ваше? в чем проблема?
- найти середину элемента... ещё проще. Top и Left элемента знаем, width и height тоже.
x := left+width div 2;
y := top + height div 2;
понятно, что пиксели неделимые и не всегда получится строго по центру.
- переместить курсор... тут приходит на помощь функция SetCursorPos, которой нужно передать правильные координаты. Правильные, потому что те, которые получены выше - они относительно родительского компонента. Поэтому есть метод у компонента ScreenToClient и ClientToScreen (тут примеры)
- сменить вид курсора... одна строка:) вот так
Screen.Cursor := crCross или какой там точно нужно, выбирайте.
- переместить. Приложение то Ваше, зачем посылать нажатие клавиши, просто запоминаете флаг "нужно перемещать" и дальше правильно обрабатываете стрелки.

Ответ отправил: Вадим К (статус: Академик)
Время отправки: 7 сентября 2011, 10:47
Оценка за ответ: 5

Комментарий к оценке: Спасибо, буду разбираться, я только начал изучать программирование

Мини-форум вопроса

Всего сообщений: 18; последнее сообщение — 17 сентября 2011, 00:19; участников в обсуждении: 3.
Фео

Фео (статус: Посетитель), 11 сентября 2011, 11:26 [#1]:

помогите пожалуйста разобраться где тут что

FillChar(Item, SizeOf(TMenuItemInfo), 0);
with Item do
begin
cbSize := SizeOf(TMenuItemInfo);
fMask := MIIM_TYPE or MIIM_ID;
fType := MFT_STRING;
dwTypeData := '&My menu button';
wID := MyButtonID;
end;
{ Добавим свою кнопку }
InsertMenuItem(GetSystemMenu(Handle, False), SC_CLOSE, False, Item);
end;
Вадим К

Вадим К (статус: Академик), 11 сентября 2011, 19:52 [#2]:

1 строка - обнулили всю структуру (не по каждому же полю проходить вручную)
потом куча строк, где заносятся разные параметры для нового элемента меню (названия, идентификаторы, состояние и так далее).
И в предпоследней строки заполненный и настроенный пункт добавляется в меню.
Галочка "подтверждения прочтения" - вселенское зло.
Фео

Фео (статус: Посетитель), 11 сентября 2011, 20:13 [#3]:

т.е добавление пунктов в меню будет состоять из вот этого кода:

with Item do
begin
cbSize := SizeOf(TMenuItemInfo);
fMask := MIIM_TYPE or MIIM_ID;
fType := MFT_STRING;
dwTypeData := '&My menu button';
wID := MyButtonID;
end;
{ Добавим свою кнопку }
InsertMenuItem(GetSystemMenu(Handle, False), SC_CLOSE, False, Item);

для разных пунктов мне нужно будет присваивать новые значения вместо вот этих: "Item", "MFT_STRING", "'&My menu button'", "MyButtonID" - я правильно понимаю?

А можно ещё про оба False в InsertMenuItem пояснить?

Всё-таки я не пойму как прикрутить к созданной строке код своего обработчика, ведь у меня нестандартное окно и стандартные обработчики просто не могут работать правильно :-( Судя из этого кода строка должна дублировать строку "Закрыть", но при клике на ней ничего не происходит
Вадим К

Вадим К (статус: Академик), 11 сентября 2011, 22:11 [#4]:

По поводу двух False. Это системные функции, поэтому все очень хорошо написано в msdn.
По поводу "первого false"

Цитата:

The action to be taken. If this parameter is FALSE, GetSystemMenu returns a handle to the copy of the window menu currently in use. The copy is initially identical to the window menu, but it can be modified. If this parameter is TRUE, GetSystemMenu resets the window menu back to the default state. The previous window menu, if any, is destroyed.

Грубо говоря, если там false, то будет хендл на то меню, которое видимо в данный момент, если true, то текущее меню будет удалено, заменено на стандартное и будет ссылка на него.
По поводу второго false сказано такое

Цитата:

Controls the meaning of uItem. If this parameter is FALSE, uItem is a menu item identifier. Otherwise, it is a menu item position.

То есть, оно определяет, как ведет себя предыдущий параметр. Нужен идентификатор меню - false, нужен порядковый номер - true.

По поводу добавления. Не нужно забывать о строке обнуления. А то структура для определения пункта меню имеет много полей и потом будут "чудеса":). А так, да, это тот код, который нужен. Только нужно вписывать нужные параметры. А тут они во всей красе расписаны.

А вот обработчики лучше свои самостоятельно прописать. Больше контроля. Вот и пример как делать.
Галочка "подтверждения прочтения" - вселенское зло.
Фео

Фео (статус: Посетитель), 13 сентября 2011, 02:16 [#5]:

Вот ещё ссылка по поводу системного меню в вашу коллекцию http://delphicikk.atw.hu/listaz.php?id=2238&oldal=2

В какую сторону рыть по поводу контекстного меню кнопки в панели задачь? Где можно прочитать что за это вообще отвечает, погуглить толком не получается - выдаёт только скрытие кнопки с панели в основном %) В МСДН на прямую искать не знаю как надо, по каким словам :-(
Вадим К

Вадим К (статус: Академик), 13 сентября 2011, 10:30 [#6]:

а что на данный момент получилось с системным меню для кнопки в таскбаре? и какая версия делфи?
Галочка "подтверждения прочтения" - вселенское зло.
bugmenot

bugmenot (статус: 3-ий класс), 13 сентября 2011, 12:06 [#7]:

Окно - Application.Handle
виконання програми розпочинається з того самого мiсця, де призупинилося.

Фео

Фео (статус: Посетитель), 13 сентября 2011, 17:09 [#8]:

Я пока не разобрался с этим, ищу мануал по винапи, чтобы понять куда рыть вообще... версия всё та же, что и указзана в стартовом посте, вопросе т.е - Делфи ХЕ , Винда ХР

В принципе если найдётся перехват правого клика на кнопке в таскбаре, то - это даже в разы лучше :-)
Вадим К

Вадим К (статус: Академик), 13 сентября 2011, 17:44 [#9]:

в случае делфи XE системное меню главного окна и кнопки на таскбаре должно совпадать. Если только не включен режим совместимости.
Галочка "подтверждения прочтения" - вселенское зло.
Фео

Фео (статус: Посетитель), 13 сентября 2011, 17:53 [#10]:

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

С системным меню я поспешил, сначала работало, когда была добавлена только одна процедура, потом перестало после добавления ещё двух оставшихся. Когда окно развёрнуто - меню не появляется, вместо сворачивания выполняется разворачивание %) Помогите пожалуйста разобраться где я накосячил :-( Думаю это из-за объявления кучи новых переменных как локальные, но они мне нужны.

Проект на DXE можно скачать от сюда:
Ссылка для скачивания файла 3.zip
http://file.qip.ru/file/Mqx9v51s/3_online.html ( 101,22 Кб )

{*****************************************}

private
{ Private declarations }
procedure WMSysCommand(var Msg: TWMSysCommand);
message WM_SYSCOMMAND;

public
{ Public declarations }
WinPrp: array [1..4] of Integer;

end;

var
Form2: TForm2;

const
SC_MyMax = $0E10;
SC_MyMove = $0E20;
SC_MyMin = $0E30;

implementation

{$R *.dfm}

procedure TForm2.FormCreate(Sender: TObject);
var
Maximize, Minimize, Move : TMenuItemInfo;
hMenuHandle, PopupMenu, SysMenu: HMENU;
Result: Boolean;
begin
{Проверяем необходимость рисования рамки окна для возможности изменения
размера окна, в случае ошибки восстанавливаем параметры окна}
if Align = alNone
then BorderStyle := bsSizeable
else
if Align = alClient
then BorderStyle := bsNone
else begin
Align := alNone;
BorderStyle := bsSizeable;
Width := 600;
Height := 350;
Top := 20;
Left := 20;
end;

{Рисуем окно без заголовка}
SetWindowLong(Handle, GWL_STYLE, GetWindowLong(Handle, GWL_STYLE) and
not WS_CAPTION or WS_BORDER);
Height := Height - GetSystemMetrics(SM_CYCAPTION);
Refresh;

{Удаляем стандартные обработчики}
hMenuHandle := GetSystemMenu(Handle, false);
If hMenuHandle <> 0
Then Begin
DeleteMenu(hMenuHandle, SC_RESTORE, MF_BYCOMMAND);
DeleteMenu(hMenuHandle, SC_MAXIMIZE, MF_BYCOMMAND);
DeleteMenu(hMenuHandle, SC_MINIMIZE, MF_BYCOMMAND);
DeleteMenu(hMenuHandle, SC_MOVE, MF_BYCOMMAND);
End;

PopupMenu := CreatePopupMenu;
Assert(PopupMenu <> 0);

{ Добавим свою кнопку #0}
FillChar(Maximize, SizeOf(TMenuItemInfo), 0);
with Maximize do
begin
cbSize := SizeOf(TMenuItemInfo);
fMask := MIIM_TYPE or MIIM_ID;
fType := MFT_STRING;
dwTypeData := 'Maximize/&Restore';
wID := SC_MyMax;
end;
Result := InsertMenuItem(GetSystemMenu(Handle, false), 0, false, Maximize);
Assert(Result, 'InsertMenuMax failed');

{ Добавим свою кнопку #1}
FillChar(Move, SizeOf(TMenuItemInfo), 0);
with Move do
begin
cbSize := SizeOf(TMenuItemInfo);
fMask := MIIM_TYPE or MIIM_ID;
fType := MFT_STRING;
dwTypeData := 'Mo&ve';
wID := SC_MyMove;
end;
Result := InsertMenuItem(GetSystemMenu(Handle, false), 0, false, Move);
Assert(Result, 'InsertMenuMove failed');

{ Добавим свою кнопку #3}
FillChar(Minimize, SizeOf(TMenuItemInfo), 0);
with Minimize do
begin
cbSize := SizeOf(TMenuItemInfo);
fMask := MIIM_TYPE or MIIM_ID;
fType := MFT_STRING;
dwTypeData := '&Minimize';
wID := SC_MyMin;
end;
Result := InsertMenuItem(GetSystemMenu(Handle, false), 0, false, Minimize);
Assert(Result, 'InsertMenuMin failed');

end;

procedure TForm2.Label1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
const sc_dragmove = $f012;
begin
releasecapture;
Form2.Perform(wm_syscommand, sc_dragmove, 0);
end;

procedure TForm2.SpeedButton11Click(Sender: TObject);
begin
close;
end;

procedure TForm2.SpeedButton12Click(Sender: TObject);
begin
If Form2.Align <> alClient
Then begin
WinPrp[1] := Form2.Left;
WinPrp[2] := Form2.Top;
WinPrp[3] := Form2.Width;
WinPrp[4] := Form2.Height;
Form2.Align := alClient;
end
Else begin
Form2.Align := alNone;
Form2.Left := WinPrp[1];
Form2.Top := WinPrp[2];
Form2.Width := WinPrp[3];
Form2.Height := WinPrp[4];
end;
FormCreate(Sender);
end;

procedure TForm2.SpeedButton13Click(Sender: TObject);
begin
ShowWindow(Application.Handle, SW_SHOW); // показываем окно формы;
Application.MainForm.Show; // забираем фокус в окно;
ShowWindow(Application.Handle, WM_SETFOCUS); // забираем фокус на таскбар;
ShowWindow(Application.Handle, BM_SETSTATE); // кликаем;
ShowWindow(Application.Handle, WM_KILLFOCUS); // отдаём фокус системе;
end;

{*****************************************}

procedure TForm2.WMSysCommand(var Msg: TWMSysCommand);
var X1, X2, X, Y: Integer;
Sender: TObject;
Button: TMouseButton;
Shift: TShiftState;
const mbLeft = TMouseButton(0);
begin
if (Msg.CmdType and SC_MyMax) = $0E10
then Begin
SpeedButton12Click(Sender);
Msg.Result := 0;
End
else
if (Msg.CmdType and SC_MyMove) = $0E20
then Begin
X1 := Form2.Left + Label3.Left + Round(Label3.Width / 2);
X2 := Form2.Left + Round(Form2.Width / 2);
if X1 > X2 then X := X2 else X := X1;
Y := Form2.Top + 24;
SetCursorPos(X,Y);
mouse_event(MOUSEEVENTF_LEFTDOWN or MOUSEEVENTF_ABSOLUTE,
X, Y, 0, 0);
Label1MouseDown(Sender, Button, Shift, X, Y);
Msg.Result := 0;
End
else
if (Msg.CmdType and SC_MyMin) = $0E30
then Begin
SpeedButton13Click(Sender);
Msg.Result := 0;
End
else inherited;
end;
bugmenot

bugmenot (статус: 3-ий класс), 14 сентября 2011, 04:35 [#11]:

Цитата (Фео):

ShowWindow(Application.Handle, WM_SETFOCUS); // забираем фокус на таскбар;
ShowWindow(Application.Handle, BM_SETSTATE); // кликаем;
ShowWindow(Application.Handle, WM_KILLFOCUS); // отдаём фокус системе;

Что это за фокусы?
виконання програми розпочинається з того самого мiсця, де призупинилося.

Фео

Фео (статус: Посетитель), 14 сентября 2011, 09:30 [#12]:

Это свёртывание окна без кнопки, эмуляцией клика по прикрученной к нему кнопке, иначе окно не свёртывается корректно :-( в этом коде есть маленький косяк - окно при запуске открывается всегда свёрнутым, но меня это даже устраивает

Если быть точным - косяк скорей всего во второй строке процедуры - я не знаю более подходящего способа забрать фокус программно
Вадим К

Вадим К (статус: Академик), 14 сентября 2011, 10:41 [#13]:

Помнится мне, что в библиотеке JVCL был какой то компонент, который системным меню рулил, достаточно к нему было прикрутить стандартный popup.
Галочка "подтверждения прочтения" - вселенское зло.
bugmenot

bugmenot (статус: 3-ий класс), 14 сентября 2011, 20:32 [#14]:

Цитата (Фео):

Это свёртывание окна без кнопки, эмуляцией клика по прикрученной к нему кнопке

Это был риторический вопрос, имеющий целью заставить написавшего взглянуть в документацию и воскликнуть "ой, бя, что за хню я написал-то!" и быстро стереть пока никто больше не увидел.
виконання програми розпочинається з того самого мiсця, де призупинилося.

Фео

Фео (статус: Посетитель), 14 сентября 2011, 22:08 [#15]:

Bugmenot, если такой умный напиши мне аналог, идея кода взята из журнала Хакер, функцию я взял первую попавшуюся, которая способна слать мессаги АПИ, а больше мне ничё не надо, читать я умею и мне совершенно фиолетово что вам не нравится.

Для всех: Косяк я нашёл, щас буду исправлять, там пару строк кода изменить, просто тупо не учёл свойств при текущих параметрах *Pardon*

Осталось исправить срабатывание разворачивания, вместо сворачивания - хотелось бы найти причину ибо это грамотнее, чем заменять вложенную процедуру на её содержимое. Помогите пожалуйста с этим.

Нашёл вот такую статью по контексту на таск баре http://www.delphisources.ru/pages/faq/base/tasks_man_popup.html правда ещё не смотрел что это такое.
bugmenot

bugmenot (статус: 3-ий класс), 15 сентября 2011, 18:31 [#16]:

Цитата (Фео):

если такой умный ... больше мне ничё не надо ... мне совершенно фиолетово что вам не нравится
Это ты своим одноклассникам на переменке такое высказывай.

Цитата (Фео):

читать я умею ... идея кода взята из журнала Хакер
Если умел бы читать - не читал бы журнал для школоты, а заглядывал бы в справочник.

Цитата (Фео):

функцию я взял первую попавшуюся, которая способна слать мессаги АПИ
Несколько случайных идентификаторов из Windows.pas собрал в кучку и удивляешься что не почему-то не работает?

Цитата (Фео):

напиши мне аналог
В чем мой интерес?
виконання програми розпочинається з того самого мiсця, де призупинилося.

Фео

Фео (статус: Посетитель), 15 сентября 2011, 22:08 [#17]:

Bugmenot, Во-первых я нигде не учусь и у меня нет одноклассников и учителей, поступать лет 10 назад надо было, мне уже давно не 14-24, но у меня нет такой возможности, если вы бы хоть чуть сами что-то соображали давно бы заметили, что эти 3 строчки которые вы не поняли прикрасно работают и меня всё устраивает как они работают, а мои вопросы косаются совершенно другого. Если у вас нет интереса - не пишите больше на этом сайте вообще, да и на др тоже, поскольку здесь задают вопросы начинающие программисты на которые отвечают такие же поситители как я, а так же достаточно опытные программисты, лично я начал изучать программирование две недели назад. И ещё - мне не в лом воспользоваться ссылкой имеющейся внизу на каждой из страниц сайта.
bugmenot

bugmenot (статус: 3-ий класс), 17 сентября 2011, 00:19 [#18]:

Цитата (Фео):

мне уже давно не 14-24 ...
прикрасно ... косаются ... поситители

Fail. «Временами школьник может весьма успешно маскироваться под взрослого, хотя его нет-нет, да и выдаст мелкая оплошность» :­-­D

Цитата (Фео):

я начал изучать программирование две недели назад

Не выйдет из тебя программиста, займись чем-нибудь попроще.

Цитата (Фео):

здесь задают вопросы начинающие программисты на которые отвечают такие же поситители как я

О да, расскажи нам еще о сути /expert/ и как ты её молниеносно постиг за 5 дней :­-­D
виконання програми розпочинається з того самого мiсця, де призупинилося.

Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.

Версия движка: 2.6+ (26.01.2011)
Текущее время: 16 ноября 2024, 16:02
Выполнено за 0.02 сек.