Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Разработка GUI в шаблоне диалога


Автор: S.A.G. 19.7.2009, 19:21
Как можно решить проблему не точного преобразования dialog units -> pixels? Т.е., я понимаю, можно определять и изменять на пару px координаты всех не совсем точно расположенных контролов, но неужели этим реально занимаются? smile

Может, есть какие-то альтернативные пути решения этой проблемы?

Автор: GremlinProg 19.7.2009, 19:37
Цитата(S.A.G. @  19.7.2009,  21:21 Найти цитируемый пост)
Как можно решить проблему не точного преобразования dialog units -> pixels? Т.е., я понимаю, можно определять и изменять на пару px координаты всех не совсем точно расположенных контролов, но неужели этим реально занимаются?

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

нужно просто перейти на диалоговые координаты полностью, тогда не будет разницы, сколько пикселов в юните

Цитата(S.A.G. @  19.7.2009,  21:21 Найти цитируемый пост)
Может, есть какие-то альтернативные пути решения этой проблемы?

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

Автор: S.A.G. 19.7.2009, 20:36
Цитата(GremlinProg @  19.7.2009,  19:37 Найти цитируемый пост)
нужно просто перейти на диалоговые координаты полностью

Что это значит и как это сделать?

Автор: GremlinProg 19.7.2009, 21:27
значит не использовать пикселы, по возможности
я же показывал примеры: http://msdn.microsoft.com/en-us/library/bb775794(VS.85).aspx
Код

hwndCombo1 = CreateWindow("COMBOBOX", "", 
                CBS_DROPDOWN | WS_CHILD | WS_VISIBLE, 
                (6 * LOWORD(dwBaseUnits)) / 4, 
                (2 * HIWORD(dwBaseUnits)) / 8, 
                (100 * LOWORD(dwBaseUnits)) / 4, 
                (50 * HIWORD(dwBaseUnits)) / 8, 
                hwnd, NULL, hinst, NULL);


тут нужно помнить только одну весчь: GetDialogBaseUnits возвращает базовые юниты для системного шрифта, поэтому, если используешь в диалоге свой шрифт, нужно либо самому их извлекать, с помощью GetTextMetrics (обязательно выбирая, при этом заданный шрифт в девайс), либо использовать MapDialogRect, который это делает автоматически,
НО он будет это делать только при условии:
Цитата(MapDialogRect @ MSDN)

If the dialog box template has the DS_SETFONT or DS_SHELLFONT style, the base units are the average width and height, in pixels, of the characters in the font specified by the template. 


ну и все расчеты желательно ориентировать не на пересчет пиксел -> диалоговый юнит, а наоборот: диалоговый юнит -> пиксел,

к примеру: нужно нарисовать на диалоге отрезок [a,b],
если a и b - изначально вычисляется и преобразуется в диалоговых юнитах, то этот отрезок всегда будет преобразован в пикселы пропорционально всем объектам диалога, в момент его разработки, независимо от того, какой в дальнейшем будет использоваться шрифт этого диалога

но даже если потребуется обратное преобразование - ничего страшного нет, если использовать стандарты:
Цитата(MapDialogRect @ MSDN)

...to convert dialog template units to pixels, use the following formulas: 


pixelX = MulDiv(templateunitX, baseunitX, 4);
pixelY = MulDiv(templateunitY, baseunitY, 8);
    

Similarly, to convert from pixels to dialog template units, use the following formulas: 


templateunitX = MulDiv(pixelX, 4, baseunitX);
templateunitY = MulDiv(pixelY, 8, baseunitY);



MulDiv здесь тоже имеет свой вес, т.к. он вычисляет именно отношение, округляя его к ближайшему целому: (p1 * p2) / p3
когда есть сомнения, лучше всегда использовать документированные методы, такие как MulDiv, даже для таких простых вычислений

Автор: GremlinProg 19.7.2009, 21:42
да, в примерах от майкрософта считается, что диалог использует именно системный шрифт, поэтому там так часто встречается GetDialogBaseUnits, не забывай, это частный случай

Автор: S.A.G. 19.7.2009, 21:44
GremlinProg, у меня есть 2 контрола в шаблоне диалога. Один должен быть размещен строго в след за другим, т.е., если горизонтальная координата 1 контрола = x, то, соответственно, второго - x+1. В файле ресурсов это просто выставляется, на картинке то, что надо. При запуске программы, между контролами появляется зазор 1-2px. Выходит, что в этом, а также других похожих случаях, необходимо программно корректировать координаты контролов. Это можно сделать, используя диалоговые единицы (в таком случае, при смене шрифта все будет ОК) или пикселы, но без этого обойтись нельзя?

Автор: GremlinProg 19.7.2009, 21:58
в каком смысле x+1?

есть к примеру прямоугольник: [l,t,r,b], если ты хочешь поставить справа за ним второй, то координаты второго будут [r,t,rr,b], а не [r + 1,t,rr,b], т.к. правая и нижняя координата в GDI всегда учитывает этот пиксел, чтобы при вычислении габаритов можно было использовать простую формулу: right - left, bottom - top

а прямоугольник [r + 1,t,rr,b] даже с пиксельными координатами будет отставать от первого на 1 пиксел
просто, такие недочеты становятся заметными именно на диалогах, т.к. в юнит может помещаться по нескольку пикселов ("пиксел" становится больше)

Автор: S.A.G. 19.7.2009, 22:05
GremlinProg,

Код
    LTEXT           " Открыть ",IDC_STATIC1,18,16,32,8
    LTEXT           " Преобразовать ",IDC_STATIC2,50,16,54,8
    LTEXT           " Сохранить ",IDC_STATIC3,104,16,39,8


3 LTEXT один за другим. На картинке в редакторе ресурсов подряд, в запущенном приложении - с зазорами.

Автор: GremlinProg 19.7.2009, 22:30
Цитата(S.A.G. @  20.7.2009,  00:05 Найти цитируемый пост)
На картинке в редакторе ресурсов подряд, в запущенном приложении - с зазорами.

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

в редакторе ресурсов нужно набрать Ctrl + T, чтобы увидеть диалог, который будет реально показан

если по прежнему лишние пикселы, значит, скорее всего, меняешь шрифт программно, уже после создания контролов
в таких случаях, нужно просто пересчитать координаты всех контролов и задать им новые

Автор: S.A.G. 19.7.2009, 22:35
Цитата(GremlinProg @  19.7.2009,  22:30 Найти цитируемый пост)
увидеть это можно только поставив бордер

Или задав BkColor уже программно, который и выявляет недостатки преобразования dialog units -> pixels.

Если сбацать приличный и аккуратный интерфейс в шаблоне диалога, то, скорей всего, понадобится еще и программная доработка, так? На что я и сетую.

Автор: GremlinProg 20.7.2009, 11:45
Цитата(S.A.G. @  20.7.2009,  00:35 Найти цитируемый пост)
Если сбацать приличный и аккуратный интерфейс в шаблоне диалога, то, скорей всего, понадобится еще и программная доработка, так? На что я и сетую.

если интерфейс пиксельный, то да, понадобится,
все что в духе "отойти от края четко 3 пиксела и поставить эдит", хотя ни кто не мешает "отойти от края и 3 единицы",
просто это будет уже "резиновый" интерфейс,
везде есть свои плюсы

Автор: S.A.G. 20.7.2009, 12:02
Цитата(GremlinProg @  20.7.2009,  11:45 Найти цитируемый пост)
если интерфейс пиксельный, то да, понадобится,


Код
hwndCombo1 = CreateWindow("COMBOBOX", "", 
                CBS_DROPDOWN | WS_CHILD | WS_VISIBLE, 
                (6 * LOWORD(dwBaseUnits)) / 4, 
                (2 * HIWORD(dwBaseUnits)) / 8, 
                (100 * LOWORD(dwBaseUnits)) / 4, 
                (50 * HIWORD(dwBaseUnits)) / 8, 
                hwnd, NULL, hinst, NULL);


Это ведь тоже пиксельный, только здесь COMBOBOX создается вручную и dialog units -> pixels преобразуются непосредственно пере вызовом функции. Функция в конечном итоге оперирует всегда только пикселами. С помощью dialog units контрол нельзя переместить всего на 1 пиксел в любую сторону.

В этих формулах
Код
pixelX = (templateunitX * baseunitX) / 4 
pixelY = (templateunitY * baseunitY) / 8


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

Мне кажется, что "серьезные" интерфейсы приходится сильно корректировать - определять координаты контролов, подгонять их, т.е. все это "выравнивание" в редакторе ресурсов теряет всякий смысл. Это мне показалось не рациональным, поэтому я усомнился, может быть чего-то на самом деле не знаю.

Автор: GremlinProg 20.7.2009, 12:55
Цитата(S.A.G. @  20.7.2009,  14:02 Найти цитируемый пост)
С помощью dialog units контрол нельзя переместить всего на 1 пиксел в любую сторону.

можно, но это будет частный случай (выбери просто шрифт c отношением ширины и высоты как 4 : 8)
юниты для того и сделаны, чтобы отвязаться от таких частных случаев, не нравится - значит ищи пиксельные редакторы ресурсов, но это ИМХО - несерьезно

зачем вообще координаты стали привяывать к шрифту?
чтобы GUI был всегда читабельным

когда он может быть нечитабельным?
вот простой пример:
Код

RECT rc;
::SetRect(&rc,10,10,100,20);
::DrawText(hdc,_T("пошла Маша на базар"),-1,&rc,0);

стоит лишь поменять размеры шрифта, и весь твой пиксельный GUI - на смарку, т.к. строка может заехать за габариты пиксельного прямоугольника

а вот здесь такого не будет (с условиями, о которых говорилось выше):
Код

RECT rc;
::SetRect(&rc,10,10,100,20);
::MapDialogRect(hwnd,&rc);
::DrawText(hdc,_T("пошла Маша на базар"),-1,&rc,0);

координаты поставил те же, для примера,
в реальных условиях их, конечно, надо подогнать

причем при смене шрифта должны смениться не только параметры графики в контролах,
но и размеры самих контролов с графикой, и контролов, их содержащих
(от оно как закручено)

вот когда идет такой учет в GUI, то тут уже и можно говорить о "серьезным" подходе,
т.к. GUI программируется не только под одного пользователя (программиста)

тут можно найти аналогию, если вспомнить HTML и о вечных их проблемах с адаптацией к браузерам и осям,
такие юниты используются и там, и совсем не для понту, а как раз в практических целях,
т.к. разработчик, по сути, вообще не знает, каким сочетанием шрифтов будет отображаться его GUI

Автор: S.A.G. 20.7.2009, 14:02
Цитата(GremlinProg @  20.7.2009,  12:55 Найти цитируемый пост)
можно, но это будет частный случай (выбери просто шрифт c отношением ширины и высоты как 4 : 8)

Если ширина шрифта = 4, а высота = 8, то да - dialog units = pixels. Но таких шрифтов, помоему, нет в природе. smile Или что-то путаю?

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

Автор: GremlinProg 20.7.2009, 14:31
Цитата(S.A.G. @  20.7.2009,  16:02 Найти цитируемый пост)
Если ширина шрифта = 4, а высота = 8, то да - dialog units = pixels.

ну да, а если нужно, чтобы делилось нацело, то достаточно соотношения 4:8 (8,16; 12,24; ...)
Цитата(S.A.G. @  20.7.2009,  16:02 Найти цитируемый пост)
Но таких шрифтов, помоему, нет в природе.

сейчас чего только нет...

можно поэкспериментировать: поймать диалог на WM_CREATE или на WM_NCCREATE и поставить такой виртуальный шрифт (создать его через CreateFont), а в ресурсе указать что шрифт системный, чтобы диалоговые функции его не переустанавливали сами, но DS_SETFONT установить, чтобы MapDialogRect заглядывал в WM_GETFONT, или вообще - перекрыть WM_GETFONT (тогда в ресурсе можно указать любой шрифт)

не знаю как будут при этом отображаться тексты,
но раз тебя интересуют исключительно координаты - попробуй, что получится?

Цитата(S.A.G. @  20.7.2009,  16:02 Найти цитируемый пост)
Выходит, корректировки интерфейса не избежать, если нужно соблюсти маленькие расстояния между контролами.

выходит так

Автор: GremlinProg 20.7.2009, 14:52
Цитата(GremlinProg @  20.7.2009,  16:31 Найти цитируемый пост)
в ресурсе указать что шрифт системный, чтобы диалоговые функции его не переустанавливали сами

тут могут быть проблемы:
Цитата

DS_SHELLFONT Indicates that the dialog box should use the system font. The typeface member of the extended dialog box template must be set to MS Shell Dlg. Otherwise, this style has no effect. It is also recommended that you use the DIALOGEX Resource, rather than the DIALOG Resource. For more information, see Dialog Box Fonts. 

The system selects a font using the font data specified in the pointsize, weight, and italic members. The system passes a handle to the font to the dialog box and to each control by sending them the WM_SETFONT message. For descriptions of the format of this font data, see DLGTEMPLATEEX.
 
думаю лучше будет просто переопределить WM_GETFONT, вообще не указывая ни какой информации о шрифте в ресурсах:
Цитата

If neither DS_SHELLFONT nor DS_SETFONT is specified, the extended dialog box template does not include the font data.

Автор: S.A.G. 20.7.2009, 15:17
Цитата(GremlinProg @  20.7.2009,  14:31 Найти цитируемый пост)
выходит так

Спасибо, мне просто нужно было увидеть это подтверждение. Целесообразность baseunits в диалогах понимаю.

Автор: GremlinProg 20.7.2009, 15:27
Цитата(S.A.G. @  20.7.2009,  17:17 Найти цитируемый пост)
мне просто нужно было увидеть это подтверждение.

от хитрый )

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

Автор: S.A.G. 20.7.2009, 15:37
Цитата(GremlinProg @  20.7.2009,  15:27 Найти цитируемый пост)
от хитрый )

Нет, я не хитрый, я ведь задаю вопросы.

Попробую этот эксперимент после того как решу задачу.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)