Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Visual Basic [игнор отключен] [закрыт для гостей] / API: глюки с измен. стиля WS_BORDER / 9 сообщений из 9, страница 1 из 1
10.02.2004, 18:35
    #32404729
SergeySV
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
API: глюки с измен. стиля WS_BORDER
Взялся за задачку создания popup окна и управления им средствами API. Все это понадобилось для Access, ну знаете чтобы типа Hinta висело с текстом и другой ерундой. Написал свой маленький класс реализующий управление окном.

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

Симпотоны: после изменения стиля окна (удаляем у него стиль WS_BORDER), пиксели рамки остаются как есть - черными. Кидаем поверх чужое окно, убираем и видим - все наше окно перерисовалось, а в этой рамке остались чужие пиксели. т.е. получаются какие-то неприкаенные краевые НИЧЕЙНЫЕ пиксели. Если окно через MoveWindow передвинуть, то рамку окрасится в белый(а может и в серый) цвет и переедет за окном.

Единственный способ которым я это одолел - это изменение размеры окна. Достаточно на 1 пиксель увеличить/уменьшить ширину/высоту окна и все ТИП-ТОР.

Мои рассуждения: последив за окном через Spy++ я увидел что при изменение размера окна, к нему приходит сообщение WM_NCPAINT - оно отвечает за перерисовку НЕКЛИЕНТСКОЙ части окна. Ну чтож, это понятно, рамку относится к неклиентской части окна.
Тогда я решил сымитировать и послал:
SendMessage(hWnd, WM_NCPAINT, 0&/1&, 0&) - ничего не произошло. Ни 0 , ни с 1 в wParam не хочет обновлять, хотя оно доходит до окна. Присмотревшись через Spy++ увидел что через MoveWindow у сообщения WM_NCPAINT в wParam передается конкретный hReg регион. Тут я задумался моежт в этом трабл, но какой тогда регион имеется ввиду и главное где его брать. Решил зделать так:
hdc = GetWindowDC(vchWnd)
hRg = CreateRectRgn(20, 20, 50, 20) ' соотв. размерам окна
Call SelectClipRgn(hdc, hRg)
Call SendMessage(vchWnd, WM_NCPAINT, hRg, 0&)
т.е. создал свой регион с размерами окна и его подсунул - НИФИГА.

Подскажите всезнающий All как же правильно обновлять окно после изменения стиля окна, отмены border?
Можно конечно дважды применить MoveWindow, ну как это несеръезно.....хочется докопаться до сути.

Чтобы все могли посмотреть на это безобразие, я сляпал аккуратный примерчик, это mdb файл Access, там на форме все понятно, практически весь код в модуле clsPopup. Но так как здесь на форуме выложить ему не могу (кстати а почему не сделают, удобная вещь ведь), то готов выслать его всем любопытным (176 кб.)

Заранее спасибо за любую помощь и советы.
...
Рейтинг: 0 / 0
10.02.2004, 20:07
    #32404819
Нуф-нуф
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
API: глюки с измен. стиля WS_BORDER
"Биты стиля обычно отражают текущее состояние окна, но изменение стиля при помощи функции SetWindowLong не приводит к соответствующему изменпнию окна (по крайней мере, не сразу). Некоторые биты стиля могут успешно изменяться во время работы программы, однако изменение большинства битов правльно действует лишь при создании окна... ...В документации Microsoft не сказано, какие биты стиля могут изменяться во время работы программы; следовательно, вы должны изменять их на свой страх и риск и только после тщательных экспериментов". (С) Дан Эпплман

Можно мне глянуть?
...
Рейтинг: 0 / 0
10.02.2004, 21:32
    #32404863
SergeySV_home
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
API: глюки с измен. стиля WS_BORDER
Интересно....

Но судя по моим экспериментам это возможно. Просто мне не очень нравится использовать для этого двойной вызов MoveWindow, когда можно заменить его одним SendMessage(,WM_NCPAINT,,)

Ок. с утра вышлю
...
Рейтинг: 0 / 0
11.02.2004, 10:07
    #32405103
SergeySV
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
API: глюки с измен. стиля WS_BORDER
Нуф-нуф: Файл к тебе ушел.

В принципе возможно проще сделать так. Там всего лишь одна форма с 5 кнопками и модуль класса, кто хочет посмотреть может просто создать в Access аналогичные пустые и заполнить их следующим текстом.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
Класс-модуль clsPopup:

'=============================================================================================
'=============================================================================================
'
'                    Класс-модуль для управления окном типа Hint
'
' версия от:  10 . 02 . 04 
'=============================================================================================
'=============================================================================================
Option Compare Database
Option Explicit

' функ. API
Private Declare Function CreateWindowEx Lib "user32" Alias "CreateWindowExA" (ByVal dwExStyle As Long, ByVal lpClassName As String, ByVal lpWindowName As String, ByVal dwStyle As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hWndParent As Long, ByVal hMenu As Long, ByVal hInstance As Long, lpParam As Any) As Long
Private Declare Function ShowWindow Lib "user32" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
Private Declare Function DestroyWindow Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Private Declare Function MoveWindow Lib "user32" (ByVal hwnd As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal bRepaint As Long) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function RedrawWindow Lib "user32" (ByVal hwnd As Long, lprcUpdate As Any, ByVal hrgnUpdate As Long, ByVal fuRedraw As Long) As Long
Private Declare Function UpdateWindow Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function GetClipRgn Lib "gdi32" (ByVal hdc As Long, ByVal hRgn As Long) As Long
Private Declare Function IntersectClipRect Lib "gdi32" (ByVal hdc As Long, ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
Private Declare Function SelectClipRgn Lib "gdi32" (ByVal hdc As Long, ByVal hRgn As Long) As Long
Private Declare Function OffsetClipRgn Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long) As Long
Private Declare Function CreateEllipticRgn Lib "gdi32" (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private Declare Function GetWindowDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hdc As Long) As Long
Private Declare Function CreateRectRgn Lib "gdi32" (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
Private Declare Function InvalidateRect Lib "user32" (ByVal hwnd As Long, lpRect As Any, ByVal bErase As Long) As Long


' структуры API
Private Type RECT
  left As Long
  top As Long
  right As Long
  bottom As Long
End Type
' константы API
Private Const WS_CHILD = &H40000000  ' окно является дочерним
Private Const WS_BORDER = &H800000 ' окно с рамкой
Private Const WS_POPUP = &H80000000  ' окно является всплывающим
Private Const WS_CLIPSIBLINGS = &H4000000 ' запрещает дочернему окну рисовать поверх другого дочернего окна
Private Const WS_EX_TOOLWINDOW = &H80  ' окно представляет собой кнопку, содержащую растр вместо текста.
                                       ' Т.о. окно с таким стилем не попадет на панель задач
Private Const WS_EX_TRANSPARENT = &H20 ' окно является прозрачным и не скрывает окна под собой
Private Const GWL_STYLE = (- 16 )
Private Const GWL_HINSTANCE = (- 6 )
Private Const GWL_WNDPROC = - 4 
Private Const SW_NORMAL =  1  ' отобразить окно
Private Const SW_HIDE = 0   ' скрыть окно
Private Const WM_NCPAINT = &H85
Private Const WM_SIZE = &H5
Private Const SIZE_RESTORED = &H0

Private Const RDW_INVALIDATE = &H1
Private Const RDW_INTERNALPAINT = &H2
Private Const RDW_ERASE = &H4
Private Const RDW_VALIDATE = &H8
Private Const RDW_NOINTERNALPAINT = &H10
Private Const RDW_NOERASE = &H20
Private Const RDW_NOCHILDREN = &H40
Private Const RDW_ALLCHILDREN = &H80
Private Const RDW_UPDATENOW = &H100
Private Const RDW_ERASENOW = &H200
Private Const RDW_FRAME = &H400
Private Const RDW_NOFRAME = &H800
' для RedrawWindow
Private Const API_TRUE = 1&




' свойства класса
Private vchWnd As Long        ' hWnd нашего окна
Private vcbBorder As Boolean  ' наличие border
Private vclX As Long   ' положение окна, X
Private vclY As Long   ' положение окна, Y
Private vclWidth As Long   ' размер окна, по X
Private vclHeight As Long   ' размер окна, по Y


Private Sub Class_Initialize()
  Dim hWndAccess As Long
  Dim hInst As Long
  
  ' hWnd гл. окна Access
  hWndAccess = Application.hWndAccessApp
  ' получение hInstance Access
  hInst = GetWindowLong(hWndAccess, GWL_HINSTANCE)
  ' инициал. свойства окна(и нашего класса)
  vclX = 100
  vclY = 80
  vclWidth = 50
  vclHeight = 25
  vcbBorder = True
  ' создание окна
  vchWnd = CreateWindowEx(WS_EX_TOOLWINDOW,  "STATIC" ,  "привет" , WS_POPUP Or WS_BORDER, vclX, vclY, vclWidth, vclHeight, hWndAccess,  0 , hInst, ByVal  0 &)
  
End Sub

Private Sub Class_Terminate()
  ' уничтожаем наше окно
  If vchWnd > 0 Then _
    DestroyWindow vchWnd
End Sub

'  -------------------------------------------------------------------------
 
'            МЕТОДЫ  КЛАССА
'  -------------------------------------------------------------------------
 
Public Sub Show()
  ' показать окно
   ShowWindow vchWnd, SW_NORMAL
End Sub

Public Sub Hide()
  ' crhsnm окно
   ShowWindow vchWnd, SW_NORMAL
End Sub

Public Sub MoveSize(x As Long, y As Long, width As Long, height As Long)
  ' сохраняем в свойствах класса
  vclX = x
  vclY = y
  vclWidth = width
  vclHeight = height
  ' передвигаем окно
  MoveWindow vchWnd, vclX, vclY, vclWidth, vclHeight,  1 
End Sub

' -------------------------------------------------------------------------
'            СВОЙСТВА  КЛАССА
' -------------------------------------------------------------------------

' установка/получение рамки
'-----------------
Public Property Let Border(ByVal bolBorder As Boolean)
  Dim lStyle As Long
  Dim hRg As Long, hdc As Long
  
  If vchWnd > 0 Then
    ' получаем текущий стиль окна
    lStyle = GetWindowLong(vchWnd, GWL_STYLE)
    ' устанав. нужный бит
    If bolBorder Then
      lStyle = lStyle Or WS_BORDER
    Else
      lStyle = lStyle And (Not WS_BORDER)
    End If
    ' устанвл. новый стиль
    lStyle = SetWindowLong(vchWnd, GWL_STYLE, lStyle)
    
    '---------------------------------------------
    ' очередной вариант: через отправку WM_NCPAINT
    '---------------------------------------------
'    hdc = GetWindowDC(vchWnd)
'    hRg = CreateRectRgn(19, 19, 51, 21)
'    Call SelectClipRgn(hdc, hRg)
'    ' посылаем WM_NCPAINT сообщение
'    Call SendMessage(vchWnd, WM_NCPAINT, hRg, 0&)
'    ' освобождаем память
'    ReleaseDC vchWnd, hdc
'    DeleteObject hRg
     
    ' ---------------------------------------------
 
    ' или такой вариант: через RedrawWindow
    ' ---------------------------------------------
 
    Call RedrawWindow(vchWnd, ByVal  0 &, ByVal  0 &, RDW_INVALIDATE Or RDW_FRAME Or RDW_UPDATENOW)
   
    ' обновляем окно (на всякий случай)
    Call InvalidateRect(vchWnd, ByVal 0&, API_TRUE)
    Call UpdateWindow(vchWnd)
  
    ' запоминаем выбранный border
    vcbBorder = bolBorder
  End If
End Property

Public Property Get Border() As Boolean
  Border = vcbBorder
End Property

' получение hWnd
' -----------------
 
Public Property Get hwnd() As Long
  hwnd = vchWnd
End Property

' получение координат окна
' -----------------
 
Public Property Get x() As Long
  x = vclX
End Property
Public Property Get y() As Long
  y = vclY
End Property
Public Property Get width() As Long
  width = vclWidth
End Property
Public Property Get height() As Long
  height = vclHeight
End Property

************************************************************
************************************************************
************************************************************
 Код  Формы - frmMain

Option Compare Database
Option Explicit

' объявляем глобальную переменную -
' - наш экземпляр класса - POPUP окна
Dim a As clsPopup

Private Sub Кнопка0_Click()
  ' создаем окно
  Set a = New clsPopup
  ' покажем окно
  a.Show
End Sub

Private Sub Кнопка3_Click()
  ' уничтожаем окно
  Set a = Nothing
End Sub

Private Sub Кнопка4_Click()
  ' убираем рамку у окна
  a.Border = False
End Sub

Private Sub Кнопка5_Click()
  ' передвигаем форму НЕ меняя размеры
  Call a.MoveSize(a.x + 30, a.y + 30, a.width, a.height)
End Sub

Private Sub Кнопка6_Click()
   ' НЕ передвигаем форму, а просто МЕНЯЕМ размеры
  Call a.MoveSize(a.x, a.y, a.width +  5 , a.height)
End Sub



...
Рейтинг: 0 / 0
11.02.2004, 22:21
    #32406408
Нуф-нуф
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
API: глюки с измен. стиля WS_BORDER
Посмотрел... Единственное что могу пока сказать:
Кнопка "Изменить размеры окна" (извиняюсь за такое описаний действий с окном) генерирует среди прочих сообщений окну сообщение WM_NCCALCSIZE, по которому пересчитывается размер неклиентской области и только после этого окно получает WM_NCPAINT...
Будет время и силы (и если всё еще останется необходимость в этом) покапаю в эту сторону... позже... Но и ты копай :)
Итогом поделишься, есл... хм... когда докопаешся? :)
...
Рейтинг: 0 / 0
12.02.2004, 10:14
    #32406669
SergeySV
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
API: глюки с измен. стиля WS_BORDER
Мда... как то я не особо обратил на это внимание. Просто думал без пересчета размеров окна (как то я не обратил внимание, что именно НЕклиентской части) достаточно токо обновить..... вообщем осознал свою ошибку, пошел копать.

В идеале хотелось получить бы хорошо и легко настраиваемое окно. Такое окно потребовалось sasha_1, но мне захотелось сваять полноценный удобный класс, так сказать навека, чтобы потом уже не копаться каждый раз в константах и функциях API когда нужно окно определенного вида.
...
Рейтинг: 0 / 0
12.02.2004, 16:11
    #32407391
SergeySV
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
API: глюки с измен. стиля WS_BORDER
Да, действительно именно в этом сообщение передается указатель на структуру, в которой указывается размеры окна старый/новый, а также размер клиентской области (старой). Именно получив такую информацию винды опеределяют изменился ли размер неклиентской области для перерисовки. Кстати с помощью этого сообщения можно отобрать у окна часть клиентской области под свои нужды. Оказывается есть примеры модулей VB, которые подключатся к ст. TextBox, изменяют клиентскую область и берут перерисовку в неклиентской области на себя, например нумеруют строки TextBox. Да и просто таким образом можно отодвинуть текст от рамки окна, а то он вплотную по умол. идет.

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

SetWindowPos vchWnd, _
0&, 0&, 0&, 0&, 0&, _
SWP_NOSIZE Or SWP_NOMOVE Or SWP_NOZORDER Or _
SWP_NOACTIVATE Or SWP_NOOWNERZORDER Or SWP_FRAMECHANGED

Т.о. мы говорим виндам, что окно не поменяло: своего местоположения,размеров, положение по Z, активности, а изменился только frame и он требует перерисовки.

Вообщем, спасибо за помощь, пошел конопатить дальше. Первый вариант выложу в топике sasha_1, думаю лучше там продолжить дальнейшее обсуждение кода.
...
Рейтинг: 0 / 0
12.02.2004, 17:53
    #32407598
Нуф
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
API: глюки с измен. стиля WS_BORDER
Адресок топика Саши подкинешь? //сами мы не местные...
...
Рейтинг: 0 / 0
13.02.2004, 10:27
    #32408155
SergeySV
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
API: глюки с измен. стиля WS_BORDER
Нуф-Нуф: не обманывай меня не местные ... \r
\r
/topic/73109&hl=
...
Рейтинг: 0 / 0
Форумы / Visual Basic [игнор отключен] [закрыт для гостей] / API: глюки с измен. стиля WS_BORDER / 9 сообщений из 9, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]