-
Возникла проблема с контекстным меню для комбобокса.
Устанавливаю через SetAutoPopupMenu контекстное меню комбобоксу, но оно срабатывает только при нажатии правой кнопки на стрелочке, вызывающей выпадающий список. На самой строке редактирования комбобокса мое контекстное меню не вызывается.
Я так понимаю, что проблема в том, что комбобокс реализован действительно как комбинированная конструкция из строки ввода и выпадающего списка. По идее, если получить ссылку на саму строку ввода, то можно будет назначить контекстное меню и на строку ввода комбобокса. Вот только не соображу, как до нее добраться?
-
Вот код тестового проекта - самый необходимый минимум.
program Test;
uses Windows, Messages, KOL;
var form, combobox: PControl;
menu, ctxmenu: PMenu;
begin
form := NewForm(Applet, 'Test');
combobox := NewComboBox(form, []);
menu := NewMenu(form, 0, [], nil);
ctxmenu := NewMenu(form, 0, ['Cut', 'Copy', 'Paste'], nil);
combobox.SetAutoPopupMenu(ctxmenu);
Run(form);
end.
Контекстное меню вызывается только на стрелочке, а в той части комбобокса, где можно вводить - не срабатывает. Пытался добавить form.SetAutoPopupMenu(ctxmenu); Не помогает. В полном соответствии с написанным появляется контекстное меню у самой формы, но на комбобоксе - нет. На всякий случай - версии используемого компилятора и библиотек, хотя здесь это вряд ли существенно:
Lazarus-0.9.26.3-20365-fpc-2.2.4-20090603-cross-arm-wince-win32.exe
Lazarus-0.9.26.3-20365-fpc-2.2.4-20090603-win32.exe
kol-ce-2.80.3.zip
Причем не только в контексте дельфи и KOL, та же фигня на VC++ с комбобоксом. Весь инет обыскал, все поисковые сервера замучил - нет ничего о контекстном меню для комбобоксов. Любой другой контрол нормально работает с контекстным меню, но мне ведь нужен комбобокс!
-
Например, с помощью GetComboBoxInfo получаем хэндл едитбокса; подменяем оконную процедуру, в которой переопределяем реакцию на WM_CONTEXTMENU, et voilà: program Project1;
uses
Windows,
Messages,
KOL;
var
Form, CB: PControl;
Menu: PMenu;
CBInfo: TComboBoxInfo;
PrevWndProc: Integer;
procedure MenuItem(Dummy, Sender: PControl; Item: Integer);
begin
CB.Items[CB.CurIndex] := Menu.ItemText[item];
end;
function CBWndProc(Wnd: HWnd; Msg: Cardinal; wParam: Integer; lParam: Integer): Integer; stdcall;
var
R: TRect;
begin
if Msg = WM_CONTEXTMENU then
begin
if lParam < 0 then
begin
GetWindowRect(Wnd, R);
Menu.Popup((R.Left + R.Right) div 2, (R.Top + R.Bottom) div 2);
end
else
Menu.Popup(LoWord(lParam), HiWord(lParam));
Result := 0;
end
else
Result := CallWindowProc(Pointer(PrevWndProc), Wnd, Msg, wParam, lParam);
end;
function GetComboBoxInfo(hwndCombo:HWND;var pcbi:TCOMBOBOXINFO):BOOL; stdcall; external 'user32' name 'GetComboBoxInfo';
begin
Form := NewForm(nil, 'test');
CB := NewComboBox(Form, []);
CB.Add('Test');
Menu := NewMenu(CB, 0, ['1','2','3'], TOnMenuItem(MakeMethod(nil, @MenuItem)));
CBInfo.cbSize := SizeOf(CBInfo);
GetComboBoxInfo(CB.GetWindowHandle, CBInfo);
PrevWndProc := SetWindowLong(CBInfo.hwndItem, GWL_WNDPROC, Integer(@CBWndProc));
Run(Form);
end.
-
Смысл понятен, но что-то не получается, не понравилось ей описание TComboBoxInfo:
test.pas(6,26) Error: Identifier not found "TComboBoxInfo"
test.pas(6,26) Error: Error in type definition
Может, из-за того, что KOL не полностью портирована под WinCE? Попробовал собрать не под WinCE, а под Win32. Тоже ошибки вылезли:
ctxtest2.pas(15,5) Error: Illegal qualifier
ctxtest2.pas(15,5) Error: Illegal expression
Это на строке
CB.Items[CB.CurIndex] := Menu.ItemText[item];
Ладно, обработка не критична сейчас, закомментировал эту строку. Опять ей не нравится:
ctxtest2.pas(27,11) Error: Illegal qualifier
ctxtest2.pas(27,11) Error: Illegal expression
Это она ругается на
Menu.Popup((R.Left + R.Right) div 2, (R.Top + R.Bottom) div 2);
Что, у KOL'овского меню разве нет метода Popup?
-
P.S. Прошу прощения, Дмитрий К, за этими мыслями об ошибках компиляции забыл самое главное - спасибо за помощь!
-
Поправка: вторая часть проблемы оказалась тривиальной. Извиняюсь, это я просто скопировал приведенный код в файл, а надо было добавить {$mode delphi}, и всё стало под Win32 компилироваться, спасибо!
Осталась только проблема отсутствия описания TComboBoxInfo.
-
Еще одна попытка решить проблему. Попытался я добавить в код описание соответствующих типов, вот так:
type
tagCOMBOBOXINFO = record
cbSize: DWORD;
rcItem: TRect;
rcButton: TRect;
stateButton: DWORD;
hwndCombo: HWND;
hwndItem: HWND;
hwndList: HWND;
end;
TComboboxInfo = tagCOMBOBOXINFO;
PComboboxInfo = ^TComboboxInfo;
LPComboboxInfo = PComboboxInfo;
Странно, после этого программа собралась без ошибок, но... Вот только не запускается она на Windows Mobile девайсах. Издает неприятный писк при попытке запуска и не работает. Примерно такой звук, как если собрать программу под Win32, а пытаться запустить под WinCE...
-
Скорее всего, в WinCE нет GetComboBoxInfo. Нужно просто послать комбобоксу CB_GETCOMBOBOXINFO
-
Что-то не получается. Поставил вместо вызова GetComboBoxInfo такую строку:
CB.Perform(CB_GETCOMBOBOXINFO, 0, Integer(@CBInfo));
Компилируется, запускается... Контекстного меню нет :(
-
Самое неприятное заключается в том, что код с CB.Perform() под Win32 запускается и работает... Такое впечатление, что WinCE вообще не поддерживает сообщение GETCOMBOBOXINFO.
Нужен какой-то другой способ получения хэндла поля ввода комбобокса...
-
Попробовал в вызове SetWindowLong поставить первым параметром конструкцию GetWindow(CB.GetWindowHandle, GW_CHILD) Издевается - опять под Win32 работает, под WinCE точки не появляются.
-
> под WinCE точки не появляются.
А если так? program test;
uses
windows, messages, kol, aygshell;
var
Form, CB: PControl;
Menu: PMenu;
EdtWnd: Hwnd;
PrevWndProc: Cardinal;
function CBWndProc(Wnd: HWnd; Msg: Cardinal; wParam: Integer; lParam: Integer): Integer; stdcall;
var
shrg: SHRGINFO;
R: TRect;
begin
if Msg = WM_LBUTTONDOWN then
begin
shrg.cbSize := sizeof(shrg);
shrg.hwndClient := Wnd;
shrg.ptDown.x := LOWORD(lParam);
shrg.ptDown.y := HIWORD(lParam);
shrg.dwFlags := SHRG_RETURNCMD;
SHRecognizeGesture(shrg);
end;
if Msg = WM_CONTEXTMENU then
begin
if lParam < 0 then
begin
GetWindowRect(Wnd, R);
Menu.Popup((R.Left + R.Right) div 2, (R.Top + R.Bottom) div 2);
end
else
Menu.Popup(LoWord(lParam), HiWord(lParam));
Result := 0;
end
else
Result := CallWindowProc(Pointer(PrevWndProc), Wnd, Msg, wParam, lParam);
end;
begin
Form := NewForm(nil, 'test');
CB := NewComboBox(form, []);
Menu := NewMenu(CB, 0, ['1','2','3'], nil);
EdtWnd := GetWindow(CB.GetWindowHandle, GW_CHILD);
PrevWndProc := SetWindowLong(EdtWnd, GWL_WNDPROC, Integer(@CBWndProc));
Run(Form);
end.
-
А так работает. Спасибо огромное!
-
Удалено модератором
-
Удалено модератором
|