Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.137.187.186] |
|
Страницы: (2) [1] 2 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Есть дочернее окно WC_STATIC со стилем
dwstylepicture = WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | SS_NOTIFY; picturehwnd = CreateWindowEx(WS_EX_CLIENTEDGE, WC_STATIC, NULL, dwstylepicture, 0, 0, 0, 0, hdlg, (HMENU) 1001, hinstance, NULL); Если скролл создан как отдельный э.у, тогда сообщения WM_HSCROLL или WM_VSCROLL А если создан скролл как встроенный, тогда какие сообщения ? Нашел что при использовании SS_NOTIFY обрабатывается сообщение WM_COMMAND Как из него получить SB_LINELEFT, SB_LINERIGHT и т.д ? |
Сообщ.
#2
,
|
|
|
Наверняка функцией Set/GetScrollInfo.
|
Сообщ.
#3
,
|
|
|
Цитата Mr.Brooks @ Если скролл создан как отдельный э.у, тогда сообщения WM_HSCROLL или WM_VSCROLL А если создан скролл как встроенный, тогда какие сообщения ? При скроллинге мышью встроенные скроллы шлют эти же сообщения, а скролл через клавиатуру они вообще не поддерживают - его нужно добавлять ручками путем обработки сообщения WM_KEYDOWN. См. How to Create a Keyboard Interface for Standard Scroll Bars |
Сообщ.
#4
,
|
|
|
Зачем понадобилось менять элемент управления скролл на встроенный скролл. Ответ на рисунке
Прикреплённая картинка
Добавлено Теперь появилась проблема статик со встроенным скроллом не шлет сообщений. Если установлен SS_NOTIFY то приходит сообщение WM_COMMAND вот код LRESULT CALLBACK WndProcTable(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { HDC hdc; HWND hparent; hparent = GetParent(hwnd); switch (message) { case WM_CREATE: hdc = GetDC(hwnd); ReleaseDC(hwnd, hdc); return 0; case WM_SIZE: TableResize(hwnd); return 0; case WM_KEYDOWN: MessageBox(NULL, "WM_KEYDOWN", "Message", MB_OK); // <-- сообщение не приходит switch (LOWORD(wparam)) { case VK_TAB: TableFocus(); break; case VK_ESCAPE: SendMessage(hwnd, WM_CLOSE, NULL, NULL); break; } return 0; case WM_HSCROLL : MessageBox(NULL, "WM_HSCROLL", "Message", MB_OK); // <-- сообщение не приходит return 0; case WM_VSCROLL : MessageBox(NULL, "WM_VSCROLL", "Message", MB_OK); // <-- сообщение не приходит return 0; case WM_COMMAND: switch (LOWORD(wparam)) { case 1000: switch (HIWORD(wparam)) { case LBN_SELCHANGE: TableListboxChange(hparent); break; } break; case 1001: MessageBox(NULL, "1001", "Message", MB_OK); // <-- сообщение приходит !!! но как взять например SB_LINELEFT //switch (HIWORD(wparam)) //{ //case SB_LINELEFT: // MessageBox(NULL, "SB_LINELEFT", "Message", MB_OK); // break; //} break; case 1002: // break; case 1003: // break; case 1004: SendMessage(hwnd, WM_CLOSE, NULL, NULL); break; } return 0; case WM_LBUTTONDOWN: TableLButtonDown(hwnd); return 0; case WM_LBUTTONUP: TableLButtonUp(hwnd); return 0; case WM_MOUSEMOVE: TableMouseMove(hwnd, message, wparam, lparam); return 0; case WM_PAINT: TablePaint(hwnd); return 0; case WM_ERASEBKGND: return 0; case WM_CLOSE: EnableWindow(hparent, TRUE); SetFocus(hparent); BringWindowToTop(hparent); ShowWindow(hwnd, SW_HIDE); DestroyWindow(hwnd); return 0; } return DefWindowProc(hwnd, message, wparam, lparam); } LRESULT CALLBACK WndProcTableSubclassing(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { int i, n; HWND hwndfocus; n = GetDlgCtrlID(hwnd) - 1000; switch (message) { case WM_KEYDOWN: switch (LOWORD(wparam)) { case VK_TAB: TableFocus(); break; case VK_ESCAPE: SendMessage(GetParent(e::tablehwnd[0]), WM_CLOSE, NULL, NULL); break; } break; case WM_MOUSEMOVE: TableMouseMove(GetParent(e::tablehwnd[0]), message, wparam, lparam); break; case WM_NCMOUSEMOVE: TableMouseMove(GetParent(e::tablehwnd[0]), message, wparam, lparam); break; case WM_LBUTTONUP: hwndfocus = GetFocus(); for (i=0; i<e::tablehwndubound; i++) { if (e::tablehwnd[i] == hwndfocus) { e::focus = i; } } break; case WM_HSCROLL: MessageBox(NULL, "Subclassing - WM_HSCROLL", "Message", MB_OK); // <-- сообщение не приходит break; case WM_VSCROLL: MessageBox(NULL, "Subclassing - WM_VSCROLL", "Message", MB_OK); // <-- сообщение не приходит break; } return CallWindowProc(e::tablewndproc[n], hwnd, message, wparam, lparam); } |
Сообщ.
#5
,
|
|
|
Сообщ.
#6
,
|
|
|
Цитата Mr.Brooks @ Теперь появилась проблема статик со встроенным скроллом не шлет сообщений. Скорее всего, "скролл" шлёт все те-же самые сообщения. Но шлёт он их своему паренту, т.е. статику. Значит, чтобы их обработать, надо делать сабклассинг. (т.е. получить доступ к оконной процедуре статика) --- Можно пойти на компромисс - не обрабатывать эти сообщения в самой оконной процедуре статика (если это не совсем удобно). Предусмотрим пересылку сообщений скролл-статику главному окну, паренту статика. И уже все манипуляции скроллами попробуем делать в оконной процедуре главного окна, т.е. то, что ты и хочешь. |
Сообщ.
#7
,
|
|
|
У меня и сделан сабклассинг WndProcTableSubclassing
// e::tablehwnd[0] = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTBOX, NULL, dwstylelistbox, 0, 0, 0, 0, hdlg, (HMENU) 1000, hinstance, NULL); e::tablehwnd[1] = CreateWindowEx(WS_EX_CLIENTEDGE, WC_STATIC, NULL, dwstylepicture, 0, 0, 0, 0, hdlg, (HMENU) 1001, hinstance, NULL); e::tablehwnd[2] = CreateWindowEx(0, WC_BUTTON, "Apply", dwstylebutton, 0, 0, 0, 0, hdlg, (HMENU) 1002, hinstance, NULL); e::tablehwnd[3] = CreateWindowEx(0, WC_BUTTON, "OK", dwstylebutton, 0, 0, 0, 0, hdlg, (HMENU) 1003, hinstance, NULL); e::tablehwnd[4] = CreateWindowEx(0, WC_BUTTON, "Cancel", dwstylebutton, 0, 0, 0, 0, hdlg, (HMENU) 1004, hinstance, NULL); // e::tablehwndubound = 5; hfont = (HFONT) GetStockObject(DEFAULT_GUI_FONT); for (i=0; i<e::tablehwndubound; i++) { SendMessage(e::tablehwnd[i], WM_SETFONT, (WPARAM) hfont, NULL); e::tablewndproc[i] = (WNDPROC) SetWindowLong(e::tablehwnd[i], GWL_WNDPROC, (LONG) WndProcTableSubclassing); } // ... но туда сообщения тоже не приходят case WM_HSCROLL: MessageBox(NULL, "Subclassing - WM_HSCROLL", "Message", MB_OK); // <-- сообщение не приходит break; case WM_VSCROLL: MessageBox(NULL, "Subclassing - WM_VSCROLL", "Message", MB_OK); // <-- сообщение не приходит break; Добавлено или это нужно сделать сабклассинг внутри сабклассинга ? |
Сообщ.
#8
,
|
|
|
Цитата Mr.Brooks @ или это нужно сделать сабклассинг внутри сабклассинга ? Нет, каскадировать так прямо сразу не надо. Надо искать в чём дело. |
Сообщ.
#9
,
|
|
|
Вот как у меня было, когда работало (вариант где скроллы - это элементы управления):
// ... dwstylelistbox = WS_CHILD | WS_VISIBLE | WS_VSCROLL | LBS_NOTIFY | LBS_DISABLENOSCROLL | LBS_NOINTEGRALHEIGHT; dwstyletable = WS_CHILD | WS_VISIBLE | SS_WHITERECT | WS_CLIPCHILDREN; dwstylescrollbarhorz = WS_CHILD | WS_VISIBLE | SBS_HORZ; dwstylescrollbarvert = WS_CHILD | WS_VISIBLE | SBS_VERT; dwstylebutton = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON; // e::tablehwnd[0] = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTBOX, NULL, dwstylelistbox, 0, 0, 0, 0, hdlg, (HMENU) 1000, hinstance, NULL); e::tablehwnd[1] = CreateWindowEx(WS_EX_CLIENTEDGE, WC_STATIC, NULL, dwstyletable, 0, 0, 0, 0, hdlg, (HMENU) 1001, hinstance, NULL); e::tablehwnd[2] = CreateWindowEx(0, WC_SCROLLBAR, NULL, dwstylescrollbarhorz, 0, 0, 0, 0, e::tablehwnd[1], (HMENU) 1002, hinstance, NULL); e::tablehwnd[3] = CreateWindowEx(0, WC_SCROLLBAR, NULL, dwstylescrollbarvert, 0, 0, 0, 0, e::tablehwnd[1], (HMENU) 1003, hinstance, NULL); e::tablehwnd[4] = CreateWindowEx(0, WC_BUTTON, "Apply", dwstylebutton, 0, 0, 0, 0, hdlg, (HMENU) 1004, hinstance, NULL); e::tablehwnd[5] = CreateWindowEx(0, WC_BUTTON, "OK", dwstylebutton, 0, 0, 0, 0, hdlg, (HMENU) 1005, hinstance, NULL); e::tablehwnd[6] = CreateWindowEx(0, WC_BUTTON, "Cancel", dwstylebutton, 0, 0, 0, 0, hdlg, (HMENU) 1006, hinstance, NULL); // e::tablehwndubound = 7; hfont = (HFONT) GetStockObject(DEFAULT_GUI_FONT); for (i=0; i<e::tablehwndubound; i++) { SendMessage(e::tablehwnd[i], WM_SETFONT, (WPARAM) hfont, NULL); e::tablewndproc[i] = (WNDPROC) SetWindowLong(e::tablehwnd[i], GWL_WNDPROC, (LONG) WndProcTableSubclassing); } // ... LRESULT CALLBACK WndProcTable(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { HDC hdc; HWND hparent; hparent = GetParent(hwnd); switch (message) { case WM_CREATE: hdc = GetDC(hwnd); ReleaseDC(hwnd, hdc); return 0; case WM_SIZE: TableResize(hwnd); return 0; case WM_KEYDOWN: switch (LOWORD(wparam)) { case VK_TAB: TableFocus(); break; case VK_ESCAPE: SendMessage(hwnd, WM_CLOSE, NULL, NULL); break; } return 0; case WM_COMMAND: switch (LOWORD(wparam)) { case 1000: switch (HIWORD(wparam)) { case LBN_SELCHANGE: TableListboxChange(hparent); break; } break; case 1004: // break; case 1005: // break; case 1006: SendMessage(hwnd, WM_CLOSE, NULL, NULL); break; } return 0; case WM_LBUTTONDOWN: TableLButtonDown(hwnd); return 0; case WM_LBUTTONUP: TableLButtonUp(hwnd); return 0; case WM_MOUSEMOVE: TableMouseMove(hwnd); return 0; case WM_PAINT: TablePaint(hwnd); return 0; case WM_ERASEBKGND: return 0; case WM_CLOSE: EnableWindow(hparent, TRUE); SetFocus(hparent); BringWindowToTop(hparent); ShowWindow(hwnd, SW_HIDE); DestroyWindow(hwnd); return 0; } return DefWindowProc(hwnd, message, wparam, lparam); } LRESULT CALLBACK WndProcTableSubclassing(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { int n; n = GetDlgCtrlID(hwnd) - 1000; switch (message) { case WM_HSCROLL: switch (LOWORD(wparam)) { case SB_LINELEFT: e::tablestepx -= 1; TableShift(); break; case SB_LINERIGHT: e::tablestepx += 1; TableShift(); break; case SB_THUMBPOSITION: case SB_THUMBTRACK: TableShiftTrack(message, wparam); break; case SB_LEFT: e::tablestepx = 0; TableShift(); break; case SB_RIGHT: e::tablestepx = e::tablestepxubound; TableShift(); break; } return 0; case WM_VSCROLL: switch (LOWORD(wparam)) { case SB_LINEUP: e::tablestepy -= 1; TableShift(); break; case SB_LINEDOWN: e::tablestepy += 1; TableShift(); break; case SB_THUMBPOSITION: case SB_THUMBTRACK: TableShiftTrack(message, wparam); break; case SB_TOP: e::tablestepy = 0; TableShift(); break; case SB_BOTTOM: e::tablestepy = e::tablestepyubound; TableShift(); break; } return 0; case WM_KEYDOWN: switch (LOWORD(wparam)) { case VK_HOME : SendMessage (hwnd, WM_HSCROLL, SB_LEFT, 0L) ; break ; case VK_END : SendMessage (hwnd, WM_HSCROLL, SB_RIGHT, 0L) ; break ; case VK_PRIOR : SendMessage (hwnd, WM_VSCROLL, SB_TOP, 0L) ; break ; case VK_NEXT : SendMessage (hwnd, WM_VSCROLL, SB_BOTTOM, 0L) ; break ; case VK_UP : // break ; case VK_DOWN : // break ; case VK_LEFT : // break ; case VK_RIGHT : // break ; case VK_TAB: TableFocus(); break; case VK_ESCAPE: SendMessage(GetParent(e::tablehwnd[0]), WM_CLOSE, NULL, NULL); break; } break; } return CallWindowProc(e::tablewndproc[n], hwnd, message, wparam, lparam); } Добавлено Элементы управления скроллы были дочерними для окна и их сообщения, что логично, были в оконной процедуре субклассинге. Цитата Нет, каскадировать так прямо сразу не надо. А мне кажется что этот вариант очень логичен в данном слечае. Я бы для интереса все-таки сделал субклассинг каскадом. Но тут еще один вопрос: как тогда найти hwnd встроенных скроллов, ведь я их не создаю непосредственно ? |
Сообщ.
#10
,
|
|
|
Цитата Mr.Brooks @ Но тут еще один вопрос: как тогда найти hwnd встроенных скроллов, ведь я их не создаю непосредственно ? Встроенный скролл - это не отдельное окно, а просто картинка в неклиентской области основного окна. Соотв-но сообщения скроллинга генерятся в ответ на клики мышью в области скроллбара (после анализа WM_NCHITTEST) либо дефолтной процедурой самого окна, либо диспетчером сообщений RawInput ОС. Цитата Mr.Brooks @ case WM_VSCROLL : MessageBox(NULL, "WM_VSCROLL", "Message", MB_OK); // <-- сообщение не приходит Во-первых, судя по картинке #5, у тебя скролл не настроен, т.к. тамб растянут во всю высоту окна, т.е. скроллить нечего\некуда. Может поэтому и сообщения не генерятся (грубо говоря, скролл есть, но он не активен). Во-вторых, в процедуре сабклассинга ты что-то делаешь в ответ на WM_NCMOUSEMOVE - может там какой-то косяк закрался? Цитата Mr.Brooks @ case WM_COMMAND: ... MessageBox(NULL, "1001", "Message", MB_OK); // <-- сообщение приходит !!! но как взять например SB_LINELEFT Никак. Скорее всего WM_COMMAND приходит в ответ на WM_NCLBUTTONDOWN просто для того, чтобы информировать о клике на области, принадлежащей окну (тем более, если скролл не активен). А WM_VSCROLL должно генериться уже после WM_NCLBUTTONDOWN, и без всяких дублирований через WM_COMMAND. |
Сообщ.
#11
,
|
|
|
1) По поводу ненастроенных скроллов есть у меня там функция TableShift() ее назначение отслеживать сдвиг таблицы tablesize в окне tableframe
В ней я настраиваю скролл и заодно позицию пока = 0 (закоментированно). Первый раз вызваю при создании окна, далее при сдвиге таблице и при изменении размеров. То что на рисунке скролл почти на всю длину - случайность. Прилагаю другой рисунок. void TableShift() { int i, k, fx, sx, fy, sy, posx, posy, w, h; SCROLLINFO si; sx = e::tablesize[0]; fx = e::tableframe[0]; sy = e::tablesize[1]; fy = e::tableframe[1]; k = 0; w = 0; for (i=0; i<2; i++) { if ((e::tablesize[i] >= e::tableframe[i]) && (e::tableframe[i] > 0)) { si.cbSize = sizeof(si); si.fMask = SIF_ALL; si.nMin = 0; si.nMax = e::tablesize[i]; si.nPage = e::tableframe[i]; si.nPos = 0; //si.nPos = posy; SetScrollInfo(e::tablehwnd[1], i, &si, TRUE); EnableScrollBar(e::tablehwnd[1], i, ESB_ENABLE_BOTH); } else { //e::tablestepy = 0; //e::tabledy[0] = 0; //e::tablestepyubound = 0; EnableScrollBar(e::tablehwnd[1], i, ESB_DISABLE_BOTH); } } RedrawWindow(GetParent(e::tablehwnd[0]), NULL, NULL, RDW_INTERNALPAINT); } Прикреплённая картинка
Добавлено 2) По поводу WM_NCMOUSEMOVE что я там делаю. TableMouseMove() - Там обработчик работы сплиттера. void TableMouseMove(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { HDC hdc; POINT pt, splitter[2], d; RECT rect, wndrect; GetCursorPos(&pt); ScreenToClient(hwnd, &pt); GetClientRect(hwnd, &rect); splitter[0].x = 5 + e::tablesplitterx; splitter[0].y = 7; splitter[1].x = 5 + e::tablesplitterx + 4; splitter[1].y = 7 + rect.bottom - 44; if ((pt.x >= splitter[0].x) && (pt.x < splitter[1].x) && (pt.y >= splitter[0].y) && (pt.y < splitter[1].y)) { SetCursor(e::hcursor); } if (e::tablesplitterflag == 1) { if (pt.x != e::tablecurx && wparam & MK_LBUTTON) { hdc = GetWindowDC(hwnd); GetWindowRect(hwnd, &wndrect); d.x = wndrect.left; d.y = wndrect.top; ScreenToClient(hwnd, &d); TablePaintXorBar(hdc, e::tablecurx - d.x + 1, splitter[0].y - d.y + 1, 1, splitter[1].y - splitter[0].y - 2); TablePaintXorBar(hdc, pt.x - d.x + 1, splitter[0].y - d.y + 1, 1, splitter[1].y - splitter[0].y - 2); ReleaseDC(hwnd, hdc); e::tablecurx = pt.x; } } } |
Сообщ.
#12
,
|
|
|
(!) Сделал такую вещь вместо WC_STATIC создаю WC_BUTTON
//... e::tablehwnd[0] = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTBOX, NULL, dwstylelistbox, 0, 0, 0, 0, hdlg, (HMENU) 1000, hinstance, NULL); //e::tablehwnd[1] = CreateWindowEx(WS_EX_CLIENTEDGE, WC_STATIC, NULL, dwstylepicture, 0, 0, 0, 0, hdlg, (HMENU) 1001, hinstance, NULL); e::tablehwnd[1] = CreateWindowEx(WS_EX_CLIENTEDGE, WC_BUTTON, NULL, dwstylepicture, 0, 0, 0, 0, hdlg, (HMENU) 1001, hinstance, NULL); e::tablehwnd[2] = CreateWindowEx(0, WC_BUTTON, "Apply", dwstylebutton, 0, 0, 0, 0, hdlg, (HMENU) 1002, hinstance, NULL); e::tablehwnd[3] = CreateWindowEx(0, WC_BUTTON, "OK", dwstylebutton, 0, 0, 0, 0, hdlg, (HMENU) 1003, hinstance, NULL); e::tablehwnd[4] = CreateWindowEx(0, WC_BUTTON, "Cancel", dwstylebutton, 0, 0, 0, 0, hdlg, (HMENU) 1004, hinstance, NULL); //... результат при клике по вертикальному скроллу Прикреплённая картинка
Так что дело в самом статике. Вопрос: зачем нужны в статике скроллы, если их нельзя обработать. А если можно, то как это сделать. И второй: как альтернативный вариант может оставить скроллы как элементы управления, но тогда как изменить их стили, чтобы они в Windows 7 выглядели также как встроенный скролл у соседнего listbox ? |
Сообщ.
#13
,
|
|
|
Цитата Mr.Brooks @ Так что дело в самом статике. Вопрос: зачем нужны в статике скроллы, если их нельзя обработать. А если можно, то как это сделать. Наверное, на этот вопрос никто не сможет ответить - это надо самому исследовать. Ты же используешь "статик" как панель для размещения контролов, как я понял. Отсюда и проблемы. Можно спросить - а зачем ? Используй "обычное" окно подходящего стиля - без заголовка - вот и будет "панель". Всё заработает и саб-классинг не понадобится. |
Сообщ.
#14
,
|
|
|
Цитата Можно спросить - а зачем ? В VB6 и С# на которых я начинал есть PictureBox, а здесь - нет, вот я и сделал такую ассоциацию, что роль пикчербокса может выполнять STATIC. Значит не вышло. Цитата Используй "обычное" окно подходящего стиля - без заголовка - вот и будет "панель". Всё заработает и саб-классинг не понадобится. Это хорошая идея, правда, придется придумать как это красиво (лаконично) написать. Вопрос решен. Спасибо. |
Сообщ.
#15
,
|
|
|
Цитата Mr.Brooks @ Так что дело в самом статике. Вопрос: зачем нужны в статике скроллы, если их нельзя обработать. А если можно, то как это сделать. 1) Похоже, что да 2) Если почитать мсдн, то можно придти к выводу, что predefined window procedure статика "глушит" сообщения WM_NCLBUTTONDOWN и WM_NCHITTEST, поэтому сообщения скролла и не генерятся. Чтобы изменить это поведение можно попробовать в процедуре сабклассинга передавать эти сообщения не в CallWindowProc, а в DefWindowProc. Добавлено Цитата Mr.Brooks @ Цитата ЫукпШ @ Это хорошая идея, правда, придется придумать как это красиво (лаконично) написатьИспользуй "обычное" окно подходящего стиля - без заголовка - вот и будет "панель". Можно использовать простой трюк ("изврат") - подложить под статик без сколлбаров пустое окно со скроллбарами того же размера (клиентской части) и считать, что сообщения скролла этого окна относятся к статику. |