ВОПРОС - как заморозить окно?

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
BV
Thinker
Thinker
Аватара пользователя
 
Сообщения: 3987
Зарегистрирован: 12.09.2004 (Вс) 0:55
Откуда: Молдавия, г. Кишинёв

ВОПРОС - как заморозить окно?

Сообщение BV » 14.01.2005 (Пт) 23:47

У меня такая ситуация:
Я создаю окно и делаю его Child окном PictureBox'а на моей форме. ВОПРОС – подскажите, как мне сделать так, чтобы его (созданное окно) нельзя было перемещать (нужно зафиксировать в одной позиции).

Тем не менее мне нужно, чтобы вся остальная функциональность окна сохранялась.
А окна я создаю из ресурсов в EXE и DLL файлах (см. проект "Resource Viewer").

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 15.01.2005 (Сб) 4:13

Ну, первое что приходит в голову - сабклассить WM_WINDOWPOSCHANGING
Изображение

Юстас
Бывалый
Бывалый
 
Сообщения: 200
Зарегистрирован: 24.10.2003 (Пт) 5:05

Сообщение Юстас » 15.01.2005 (Сб) 12:28

Зафиксировать по отношению к чему? К пикчербоксу? Или по отношению к форме? Или зафиксировать по отношению к десктопу?

BV
Thinker
Thinker
Аватара пользователя
 
Сообщения: 3987
Зарегистрирован: 12.09.2004 (Вс) 0:55
Откуда: Молдавия, г. Кишинёв

Сообщение BV » 15.01.2005 (Сб) 13:55

2 Юстас

Только по отношению к PictureBox'у.

И можно что-то поподробнее, нежели WM_WINDOWPOSCHANGING :?

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 15.01.2005 (Сб) 15:20

Изображение

Юстас
Бывалый
Бывалый
 
Сообщения: 200
Зарегистрирован: 24.10.2003 (Пт) 5:05

Сообщение Юстас » 15.01.2005 (Сб) 16:38

Если для дочернего окна наличие заголовка (non-client area) необязательно, установи ему стиль WS_POPUP, тогда и таскать не за что будет. Если заголовок нужен, то можно обрабатывать сообщение WM_MOVING, и в lParam возвращать указатель на RECT, который описывает положение и размеры окна при создании.

SergeySV2
Новичок
Новичок
 
Сообщения: 33
Зарегистрирован: 06.01.2005 (Чт) 22:06

Сообщение SergeySV2 » 15.01.2005 (Сб) 17:18

Я вот вообще-то тоже не очень понял, сам как раз создаю дочерние окна (правда на лету) и хрен их куда утащищь, это надо еще покодить, ты что за окно то создаешь???

Тебе придется описать все очень подробно, потому что все поведение окна строится на тех стилях (обычный и расширенный) + классе на котором он создан.

Вот например, создаю дочернее окно:
класс:
With wndcls
.style = CS_OWNDC Or CS_HREDRAW Or CS_VREDRAW
.lpszClassName = myClassName
......

создание окна и задание стилей
arContr(9).hwnd = CreateWindowEx(ByVal 0&, myClassName, _
"привет", WS_VISIBLE Or WS_CHILD Or _
WS_BORDER Or WS_VSCROLL Or WS_HSCROLL,.....

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

BV
Thinker
Thinker
Аватара пользователя
 
Сообщения: 3987
Зарегистрирован: 12.09.2004 (Вс) 0:55
Откуда: Молдавия, г. Кишинёв

Сообщение BV » 15.01.2005 (Сб) 19:14

Для решения всех вопросов:

http://bbs.vbstreets.ru/viewtopic.php?t=12540

Скачайте исходники и в модуле ShowResource просмотрите функцию ShowDialog :arrow:

Юстас
Бывалый
Бывалый
 
Сообщения: 200
Зарегистрирован: 24.10.2003 (Пт) 5:05

Сообщение Юстас » 15.01.2005 (Сб) 19:44

Ну это наверное, тебе нужно :) У тебя ведь вопрос возник.

BV
Thinker
Thinker
Аватара пользователя
 
Сообщения: 3987
Зарегистрирован: 12.09.2004 (Вс) 0:55
Откуда: Молдавия, г. Кишинёв

Сообщение BV » 15.01.2005 (Сб) 21:09

2 Юстас

Что ты имел ввиду?
Если проект, то я готовлю его следующую версию, где хочу переделать многие вещи - отображение HexDump, строк, меню и ДИАЛОГОВ.
Но вот проблема стала на моём пути :( , и мне её ОЧЕНЬ нужно решить.

SergeySV2
Новичок
Новичок
 
Сообщения: 33
Зарегистрирован: 06.01.2005 (Чт) 22:06

Сообщение SergeySV2 » 15.01.2005 (Сб) 23:52

Прикольно, я тоже занимаюсь диалогами, токо я принципально не гружу из RS-файлов, а делаю subclassing и добавляю свои дочерние окна-контролы на лету..........

ну а на счет пойти.. скачать...найти... запустить.. разобраться ....и рассказать...... я туда не пойду, мне лично лень... если человек не может на словах объяснить суть проблемы... :roll:

Юстас
Бывалый
Бывалый
 
Сообщения: 200
Зарегистрирован: 24.10.2003 (Пт) 5:05

Сообщение Юстас » 16.01.2005 (Вс) 0:15

Что-то я понял, что ты нашел решение проблемы по ссылке :)

для начала: сделал, чтобы диалог не вылазил за пределы пикчербокса. Вот измененная процедура из модуля:

Код: Выделить всё
Public Function ShowDialog(ByVal ResName As String, pb As PictureBox) As Boolean
Dim rc As RECT, rcPic As RECT, ParentRct As RECT, ChildRct As RECT
Dim x As Long, y As Long
'Вот здесь возникает ошибка (при попытке отображения некоторых диалогов программа умирает, а всё потому,
'что функция слишком требовательна), которую я пока так и не смог решить, и
'если кто знает, огромная просьба прислать мне решение.
hDialog = CreateDialogParam(hModule, ResName, pb.hwnd, 0, 0)
If IsWindow(hDialog) Then
If GetParent(hDialog) = pb.hwnd Then
Call GetWindowRect(hDialog, rc)
Call MoveWindow(hDialog, 0, 0, rc.Right - rc.Left, rc.Bottom - rc.Top, 1)
pb.Move 0, 0, (rc.Right - rc.Left) * Screen.TwipsPerPixelX, (rc.Bottom - rc.Top + 24) * Screen.TwipsPerPixelY
Else
Call GetWindowRect(hDialog, rc)
Call GetWindowRect(pb.hwnd, rcPic)
'---------------------------------------------------
SetParent hDialog, FrmMain.PFrame.hwnd
Call GetClientRect(FrmMain.PFrame.hwnd, ParentRct)
Call GetWindowRect(hDialog, ChildRct)
x = (ParentRct.Right - ChildRct.Right + ChildRct.Left) \ 2
y = (ParentRct.Bottom - ChildRct.Bottom + ChildRct.Top) \ 2
Call MoveWindow(hDialog, x, y, ChildRct.Right - ChildRct.Left, ChildRct.Bottom - ChildRct.Top, 1)
'----------------------------------------------------------------------------------
End If
Call ShowWindow(hDialog, SW_NORMAL)
ShowDialog = True
End If
End Function


Изменения выделены, думаю найдешь.
Сейчас попробую заморозить перемещение диалога.

P.S.
Не забудь добавить объявления GetClientRect и SetParent

Юстас
Бывалый
Бывалый
 
Сообщения: 200
Зарегистрирован: 24.10.2003 (Пт) 5:05

Сообщение Юстас » 16.01.2005 (Вс) 0:18

SergeySV2

Если тебе лень, то не надо захламлять своими откровениями топик.

Юстас
Бывалый
Бывалый
 
Сообщения: 200
Зарегистрирован: 24.10.2003 (Пт) 5:05

Сообщение Юстас » 16.01.2005 (Вс) 1:31

BV
Диалоги ведь выводятся, только чтобы посмотреть их вид. Никаких действий они не производят. Поэтому можно сделать очень просто: вставить после Call ShowWindow(hDialog, SW_NORMAL):

EnableWindow hDialog, 0

BV
Thinker
Thinker
Аватара пользователя
 
Сообщения: 3987
Зарегистрирован: 12.09.2004 (Вс) 0:55
Откуда: Молдавия, г. Кишинёв

Сообщение BV » 16.01.2005 (Вс) 1:56

2 Юстас

Про EnableWindow я уже давно думал, но ведь это будет выглядеть по моему не очень...

2 SergeySV2

ну а на счет пойти.. скачать...найти... запустить.. разобраться ....и рассказать...... я туда не пойду, мне лично лень... если человек не может на словах объяснить суть проблемы...


Ну а кто же тебя заставляет-то? А засорять форум кучей ненужных слов и кода я не собираюсь.

Юстас
Бывалый
Бывалый
 
Сообщения: 200
Зарегистрирован: 24.10.2003 (Пт) 5:05

Сообщение Юстас » 16.01.2005 (Вс) 10:13

Попытка сабклассинга диалога путём указания новой DialogProc, равно как и указания DialogProc непосредственно при создании диалога приводит к одинаковому результату - программа падает.
А без сабклассинга чтобы реагировать на захват заголовка диалога, остается только хук на мышиные сообщения WM_MOUSEMOVE :( Это надо dll писать (не на VB)
Либо EnableWindow. Либо какое-нибудь кривое решение в таймере (например постоянно двигать в одно и то же место)

P.S.
Мне ещё в детстве мама говорила: не связывайся с диалогами! Делай нормальные окошки :)

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 16.01.2005 (Вс) 10:49

Юстас писал(а):Попытка сабклассинга диалога путём указания новой DialogProc, равно как и указания DialogProc непосредственно при создании диалога приводит к одинаковому результату - программа падает.

Во-первых, менять надо не DialogProc, а WindowProc. Стандартно, через SetWindowLong.
Во-вторых, если программа падает - значит, ты где-то ошибся :-) Показывай свой код.
Изображение

SergeySV2
Новичок
Новичок
 
Сообщения: 33
Зарегистрирован: 06.01.2005 (Чт) 22:06

Сообщение SergeySV2 » 16.01.2005 (Вс) 12:14

Присоединяюсь, sublassing работает с диалогами нормально, так как и остальными окна

....если конечно не забывать про наличие еще GetParent(hwndDialog)

Юстас
Бывалый
Бывалый
 
Сообщения: 200
Зарегистрирован: 24.10.2003 (Пт) 5:05

Сообщение Юстас » 16.01.2005 (Вс) 16:47

tyomitch

Можешь назвать хоть SukaBlaProc, суть не меняется: четыре параметра, определенные требования к возвращаемому значению при тех или иных сообщениях как в случае обработки так и пропуска сообщения. Они в основном тем и различаются, какие значения возвращаются.

Хоть SetWindowLong\GWL_WNDPROC, хоть непосредственно в CreateDialogParam указывать адрес процедуры - программа выпадает. Даже не присылая в процедуру первого сообщения - WM_INITDIALOG.

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 16.01.2005 (Вс) 16:51

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

Юстас
Бывалый
Бывалый
 
Сообщения: 200
Зарегистрирован: 24.10.2003 (Пт) 5:05

Сообщение Юстас » 16.01.2005 (Вс) 16:51

Вот это: "Во-первых, менять надо не DialogProc, а WindowProc. Стандартно, через SetWindowLong" - говорит о том, что ты даже не глянул код, что привел автор по ссылке. Сходи и посмотри.

Юстас
Бывалый
Бывалый
 
Сообщения: 200
Зарегистрирован: 24.10.2003 (Пт) 5:05

Сообщение Юстас » 16.01.2005 (Вс) 17:07

Код приводил автор в своей ссылке. Сходите с посмотрите.

В процедуре использовалось два варианта указания DialogProc

1.
Код: Выделить всё
NewProcAddr = GetWndProcAddr(AddressOf SubDlgProc)
hDialog = CreateDialogParam(hModule, ResName, pb.hwnd, NewProcAddr, 0)


2.
Код: Выделить всё
NewProcAddr = GetWndProcAddr(AddressOf SubDlgProc)
OldProcAddr = SetWindowLong(hDialog, GWL_WNDPROC, NewProcAddr)


Ну и сама поцедура:

Код: Выделить всё
Public Function SubDlgProc(ByVal hWin As Long, uMsg As Long, wParam As Long, lParam As Long) As Long
    Dim Rct As RECT
    Dim MoveRect As RECT
    Const WM_INITDIALOG As Long = &H110
   
    If uMsg = WM_INITDIALOG Then
        SetWindowLong hWin, 0, 1
        'SubDlgProc = 1
    Else
        SubDlgProc = DefWindowProc(ByVal hWin, ByVal uMsg, ByVal wParam, ByVal lParam)
    End If
End Function


В процедуре либо DefWindowProc (для первого случая) либо CallWindowProc OldProcAddr (для второго).


GSerg, твоя ссылка сабклассит не диалог. С простой формой приведенная мной схема тоже работает вполне устойчиво. С диалогом - почему-то нет. Почему - не знаю

BV
Thinker
Thinker
Аватара пользователя
 
Сообщения: 3987
Зарегистрирован: 12.09.2004 (Вс) 0:55
Откуда: Молдавия, г. Кишинёв

Сообщение BV » 16.01.2005 (Вс) 17:09

Вижу, становится всё интересней...
Сабкласить и я пытался, но в итоге получал "Программа совершила... и коврик будет свёрнут :evil: "
Но ведь, наверно, есть же метод, который может обездвижить окно. По крайней мере это смогли сделать разработчики Restorator'а.

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 16.01.2005 (Вс) 17:13

Извращенец, измени описание...

Public Function SubDlgProc(ByVal hWin As Long, byval uMsg As Long, byval wParam As Long, byval lParam As Long) As Long
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

BV
Thinker
Thinker
Аватара пользователя
 
Сообщения: 3987
Зарегистрирован: 12.09.2004 (Вс) 0:55
Откуда: Молдавия, г. Кишинёв

Сообщение BV » 16.01.2005 (Вс) 18:29

2 GSerg

А в чём там собственно извращение? По мне так всё нормально...

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 16.01.2005 (Вс) 18:33

Извращение в том, что ты получаешь от апишки число, к примеру, 5, а твоя функция интерпретирует его как указатель, и пытается читать по адресу 0x00000005, после чего и сворачивается...
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 16.01.2005 (Вс) 19:18

Юстас писал(а):tyomitch

Можешь назвать хоть SukaBlaProc, суть не меняется: четыре параметра, определенные требования к возвращаемому значению при тех или иных сообщениях как в случае обработки так и пропуска сообщения. Они в основном тем и различаются, какие значения возвращаются.

Хоть SetWindowLong\GWL_WNDPROC, хоть непосредственно в CreateDialogParam указывать адрес процедуры - программа выпадает. Даже не присылая в процедуру первого сообщения - WM_INITDIALOG.

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

В частности, SetWindowLong\GWL_WNDPROC и параметр в CreateDialogParam задают разные вещи.

Не веришь - загляни spyxx-ом в любые два диалога (т.е. окна с классом "#32770") любых программ и сравни адреса оконных процедур. Они (сюрприз!) совпадут.

Теперь понятно? ;-)
Изображение

BV
Thinker
Thinker
Аватара пользователя
 
Сообщения: 3987
Зарегистрирован: 12.09.2004 (Вс) 0:55
Откуда: Молдавия, г. Кишинёв

Сообщение BV » 16.01.2005 (Вс) 19:41

2 GSerg

Функцию "SubDlgProc" писал не я.

2 tyomitch

А ответ желательно было бы подкрепить кодом.

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 16.01.2005 (Вс) 20:01

BV писал(а):А ответ желательно было бы подкрепить кодом.

Да на удовольствие.

Вверху MdlOther:
Код: Выделить всё
Private Const WM_WINDOWPOSCHANGING = &H46
Private Type WINDOWPOS
    hwnd As Long
    hWndInsertAfter As Long
    x As Long
    y As Long
    cx As Long
    cy As Long
    flags As Long
End Type
Private pLastWndProc As Long, sx As Long, sy As Long


Внизу MdlOther:
Код: Выделить всё
Public Sub Subclass(ByVal hDialog As Long)
Static hLastDlg As Long
If hLastDlg Then SetWindowLong hLastDlg, GWL_WNDPROC, pLastWndProc
pLastWndProc = SetWindowLong(hDialog, GWL_WNDPROC, AddressOf DlgWndProc)
End Sub
Public Sub SavePosition(ByVal x As Long, ByVal y As Long)
sx = x: sy = y
End Sub
Private Function DlgWndProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
If uMsg = WM_WINDOWPOSCHANGING Then
    Dim wp As WINDOWPOS
    CopyMemory wp, ByVal lParam, Len(wp)
    wp.x = sx
    wp.y = sy
    CopyMemory ByVal lParam, wp, Len(wp)
Else
    DlgWndProc = CallWindowProc(pLastWndProc, hwnd, uMsg, wParam, lParam)
End If
End Function


В MdlShowResource.ShowDialog:
Код: Выделить всё
hDialog = CreateDialogParam(hModule, ResName, pb.hwnd, 0, 0)
If IsWindow(hDialog) Then
If GetParent(hDialog) = pb.hwnd Then
Call GetWindowRect(hDialog, rc)
Call MoveWindow(hDialog, 0, 0, rc.Right - rc.Left, rc.Bottom - rc.Top, 1)
pb.Move 0, 0, (rc.Right - rc.Left) * Screen.TwipsPerPixelX, (rc.Bottom - rc.Top + 24) * Screen.TwipsPerPixelY
SavePosition 0, 0
Else
Call GetWindowRect(hDialog, rc)
Call GetWindowRect(pb.hwnd, rcPic)
Call MoveWindow(hDialog, rcPic.Left, rcPic.Top, rc.Right - rc.Left, rc.Bottom - rc.Top, 1)
SavePosition rcPic.Left, rcPic.Top
End If
Call ShowWindow(hDialog, SW_NORMAL)
Subclass hDialog
ShowDialog = True
End If


Наверное, можно красивее - я не разбирался глубоко с логикой приложения в целом ;-)

Кстати, у тебя там баг: если вытащить окно проги из-под показываемого диалога, получается некрасиво ;-)
Изображение

Юстас
Бывалый
Бывалый
 
Сообщения: 200
Зарегистрирован: 24.10.2003 (Пт) 5:05

Сообщение Юстас » 16.01.2005 (Вс) 20:04

SergeySV2
Внеси в модуль эти изменения, так работает, и добавь необходимые декларации функций и структуры WINDOWPOS

Код: Выделить всё
Public NewProcAddr As Long, OldProcAddr As Long, ChildRct As RECT
Dim X As Long, Y As Long, W As Long, H As Long
'------------------------------------------------------------------------------
Public Function ShowDialog(ByVal ResName As String, pb As PictureBox) As Boolean
Dim rc As RECT, rcPic As RECT, ParentRct As RECT

Const HWND_NOTOPMOST As Long = -2
Const SWP_NOSENDCHANGING As Long = &H400
Const SWP_NOSIZE As Long = &H1
Const SWP_SHOWWINDOW As Long = &H40
Const SWP_HIDEWINDOW As Long = &H80
hDialog = CreateDialogParam(hModule, ResName, pb.hwnd, 0, 0)
If IsWindow(hDialog) Then
If GetParent(hDialog) = pb.hwnd Then
Call GetWindowRect(hDialog, rc)
Call MoveWindow(hDialog, 0, 0, rc.Right - rc.Left, rc.Bottom - rc.Top, 1)
pb.Move 0, 0, (rc.Right - rc.Left) * Screen.TwipsPerPixelX, (rc.Bottom - rc.Top + 24) * Screen.TwipsPerPixelY
Else
Call GetWindowRect(hDialog, rc)
Call GetWindowRect(pb.hwnd, rcPic)
'---------------------------------------------------

Call GetWindowRect(FrmMain.PFrame.hwnd, ParentRct)
Call GetWindowRect(hDialog, ChildRct)
SetParent hDialog, FrmMain.PFrame.hwnd
X = (ParentRct.Right - ParentRct.Left - ChildRct.Right + ChildRct.Left) \ 2
Y = (ParentRct.Bottom - ParentRct.Top - ChildRct.Bottom + ChildRct.Top) \ 2
W = ChildRct.Right - ChildRct.Left
H = ChildRct.Bottom - ChildRct.Top
Call MoveWindow(hDialog, X, Y, W, H, 1)
'----------------------------------------------------------------------------------
End If
Call ShowWindow(hDialog, SW_NORMAL)
NewProcAddr = GetWndProcAddr(AddressOf SubDlgProc)
OldProcAddr = SetWindowLong(hDialog, GWL_WNDPROC, AddressOf SubDlgProc)
ShowDialog = True
End If
End Function
'-----------------------------------------------------------------------------

Function GetWndProcAddr(ByVal lWndProc As Long) As Long
    GetWndProcAddr = lWndProc
End Function
Public Function SubDlgProc(ByVal hWin As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    Dim wp As WINDOWPOS
    Const WM_WINDOWPOSCHANGING As Long = &H46

    If uMsg = WM_WINDOWPOSCHANGING Then
        wp.cx = W
        wp.cy = H
        wp.X = X
        wp.Y = Y
        wp.hwnd = hWin
        RtlMoveMemory ByVal lParam, wp, Len(wp)
    Else
        SubDlgProc = CallWindowProc(OldProcAddr, hWin, uMsg, wParam, lParam)
    End If
End Function
'==============================================



tyomich, я примерно представляю себе разницу между Def и Window

След.

Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: Google-бот и гости: 0

    TopList  
cron