How to make 3D-look for dynamically created CEdit?
Как сделать трёхмерный CEdit, когда он создаётся динамически?
Read in English a little below.
В соответствии с тем, что я писал несколько постов назад, стараюсь донести до других частичку своего опыта. То, на что я убил несколько часов. Ввиду особой важности (куча народа ищет ответ по интернетам), привожу опыт сразу на двух языках. Сначала на английском.
EN:
(read in English)
Before you begin reading, you need to know, that every control in Windows is a window.
I was using MFC (waratte mo ii yo) and I had to make some CEdit edit-fields at runtime, create it dynamically. I wrote:
where:
ix -- loop variable;
dlg_data[ix] -- structure with some data;
dlg_data[ix].m_edtField -- pointer to CEdit control;
bVis -- boolean, true if CEdit must be created visible;
rRect -- calculated coordinates of control in CRect;
this -- pointer to class-variable, derieved from CWnd;
dlg_data[ix].m_nedtFieldID -- ID for control, generated at runtime.
This sentence, as I thought, created CEdit for me, but it was without border, like this:

I read some documentation and decided to use WS_BORDER, so I modified sentense:
The border appeared, but it was plain, like this:

I wanted 3D-looking border. I read a little more, and understood, that I need to set the so-called "extended window style". The value must be WS_EX_CLIENTEDGE. I replaced WS_BORDER with this:
This had no effect. It was really stupid decision, as I figured out later. I continued to read. I switched to Google and forums.
I learned, that extended window style can be set only in special parameter by using CerateEx(...), not usual Create(...). So I wrote:
This obviously won't work, because I didn't register WCLASS_EDIT1 windows class. I tried to register it, then I tried NULL and then I tried the standard "edit" class (I must begin with it =( ):
The result was the same: window creation failed. GetLastError returned 0x00000579 (0x0579, 0x579, 1041): "Invalid menu handle". Why? I have no menu in this dialog!
Then I thought that control's parent window is not my dialog and tried to set the parent window explicitly (using SetParent(...)). But I was wrong, the parent window was correct.
I gave up with CreateEx, and returned to usual Create, because I learned the great function ModifyStyleEx. This function modifies extended style on-the-fly! I decided to use it. So I wrote:
This compiled and ran normally, but the control has no border. Why? I explicitly set the border. I continued to read.
I learned, that border style cannot be modified with ModifyStyleEx. It can be set only on creation. The reason is unknown.
So I MUST use CreateEx(...). But windows creation fails. Why? I read forums a little more and thank godness! I found the reason. Only in one place this was described.
CreateEx need explicitly set window style WS_CHILD. The reason is unknown.
Notice, that usual Create can be successfully called without WS_CHILD. So, the final version was:
dlg_data[ix].m_edtField->CreateEx(
WS_EX_CLIENTEDGE,
"edit",
"PREFIX_EDIT1",
(bVis?WS_VISIBLE:0)|ES_NUMBER|ES_RIGHT|WS_CHILD,
rRect,
this,
dlg_data[ix].m_nedtFieldID);
This works:

RU:
(читать на русском)
Перед началом чтения убедитесь, что вы знаете, что каждый контрол (элемент управления) в винде -- это тоже окно, как и то, на чём он лежит.
Вы будете смеяться, но мне приходится использовать MFC (2011 год на дворе!). Задача была в том, чтобы создать на лету несколько CEdit. Я написал:
где:
ix -- переменная цикла;
dlg_data[ix] -- структура с данными динамических контролов;
dlg_data[ix].m_edtField -- указатель на CEdit;
bVis -- флаг видимости CEdit, если истина, создаём видимым;
rRect -- расчитанные координаты контрола, запиханные в CRect;
this -- указатель на переменную-класс, класс наследник CWnd;
dlg_data[ix].m_nedtFieldID -- ID контрола, сгенерированный специально для этого.
Как я и думал, эта строчка вывела CEdit, но без рамки, вот так:

Я почитал документацию и решил использовать WS_BORDER, получилось вот что:
Рамка появилась, но была плоской, вот такой:

Я же хотел обычную трёхмерную. Я почитал ещё немного и понял, что мне нужно установить так называемый "расширенный стиль окна" ("extended window style"). Установить его надо в WS_EX_CLIENTEDGE. Я заменил WS_BORDER:
Ничего не изменилось. Делать так было глупо, как я понял позднее. Я продолжил чтение, переключившись с документаци на гугл и форумы.
Я узнал, что расширенный стиль окна может быть установлен, но не в том же параметре, где обычный стиль, а в другом, специальном и использовать надо CerateEx(...), а не обычный Create(...). Так что я написал:
Очевидно, это не заработало, ведь я не зарегистрировал класс окна WCLASS_EDIT1. Я попробовал его зарегистрировать, потом написать NULL, а потом я попробовал стандартный класс окна "edit" (с этого надо было начинать =( ):
Результат был тот же: окно не создавалось. GetLastError вовзращал 0x00000579 (0x0579, 0x579, 1041): "Неверный дескриптор меню" ("Invalid menu handle"). С какого хрена? У меня в диалоге нет меню!
Потом я подумал, может быть родительское окно у контрола установлено неверно? Я попробовал назначить его явно с помощью SetParent(...). Я ошибался, родительское окно было установлено верно.
Я плюнул на CreateEx, и вернулся к обычному Create, ведь я узнал о замечательной функции ModifyStyleEx. Она позволяет менять расширенный стиль прямо на лету! Я решил использовать её. Я написал:
Это компилировалось и работало без ошибок, однако у контрола рамки по-прежнему не было. Почему? Я же явно указал стиль рамки. Я продолжил чтение.
Я выяснил, что стиль рамки по неизвестной причине не может быть изменён на лету с помощью ModifyStyleEx. Его можно установить только при создании с помощью CreateEx.
Таким образом, мне ПРИДЁТСЯ использовать CreateEx(...). Но создать окно не удаётся. Почему? Я ещё немного почитал форумы и слава богам выяснил причину. Правда написано это было только в одном месте.
CreateEx трубует явного указания обычного стиля как WS_CHILD. Почему -- неизвестно.
Заметьте, что обычный Create может быть успешно вызван и без WS_CHILD. Итак, финальная версия:
Это работает:

Как сделать трёхмерный CEdit, когда он создаётся динамически?
Read in English a little below.
В соответствии с тем, что я писал несколько постов назад, стараюсь донести до других частичку своего опыта. То, на что я убил несколько часов. Ввиду особой важности (куча народа ищет ответ по интернетам), привожу опыт сразу на двух языках. Сначала на английском.
EN:
(read in English)
Before you begin reading, you need to know, that every control in Windows is a window.
I was using MFC (waratte mo ii yo) and I had to make some CEdit edit-fields at runtime, create it dynamically. I wrote:
dlg_data[ix].m_edtField->Create(
(bVis?WS_VISIBLE:0)|ES_NUMBER|ES_RIGHT,
rRect,
this,
dlg_data[ix].m_nedtFieldID);
where:
ix -- loop variable;
dlg_data[ix] -- structure with some data;
dlg_data[ix].m_edtField -- pointer to CEdit control;
bVis -- boolean, true if CEdit must be created visible;
rRect -- calculated coordinates of control in CRect;
this -- pointer to class-variable, derieved from CWnd;
dlg_data[ix].m_nedtFieldID -- ID for control, generated at runtime.
This sentence, as I thought, created CEdit for me, but it was without border, like this:

I read some documentation and decided to use WS_BORDER, so I modified sentense:
dlg_data[ix].m_edtField->Create(
(bVis?WS_VISIBLE:0)|ES_NUMBER|ES_RIGHT|WS_BORDER,
rRect,
this,
dlg_data[ix].m_nedtFieldID);
The border appeared, but it was plain, like this:

I wanted 3D-looking border. I read a little more, and understood, that I need to set the so-called "extended window style". The value must be WS_EX_CLIENTEDGE. I replaced WS_BORDER with this:
dlg_data[ix].m_edtField->Create(
(bVis?WS_VISIBLE:0)|ES_NUMBER|ES_RIGHT|WS_EX_CLIENTEDGE,
rRect,
this,
dlg_data[ix].m_nedtFieldID);
This had no effect. It was really stupid decision, as I figured out later. I continued to read. I switched to Google and forums.
I learned, that extended window style can be set only in special parameter by using CerateEx(...), not usual Create(...). So I wrote:
dlg_data[ix].m_edtField->CreateEx(
WS_EX_CLIENTEDGE,
"WCLASS_EDIT1",
"PREFIX_EDIT1",
(bVis?WS_VISIBLE:0)|ES_NUMBER|ES_RIGHT,
rRect,
this,
dlg_data[ix].m_nedtFieldID);
This obviously won't work, because I didn't register WCLASS_EDIT1 windows class. I tried to register it, then I tried NULL and then I tried the standard "edit" class (I must begin with it =( ):
dlg_data[ix].m_edtField->CreateEx(
WS_EX_CLIENTEDGE,
"edit",
"PREFIX_EDIT1",
(bVis?WS_VISIBLE:0)|ES_NUMBER|ES_RIGHT,
rRect,
this,
dlg_data[ix].m_nedtFieldID);
The result was the same: window creation failed. GetLastError returned 0x00000579 (0x0579, 0x579, 1041): "Invalid menu handle". Why? I have no menu in this dialog!
Then I thought that control's parent window is not my dialog and tried to set the parent window explicitly (using SetParent(...)). But I was wrong, the parent window was correct.
I gave up with CreateEx, and returned to usual Create, because I learned the great function ModifyStyleEx. This function modifies extended style on-the-fly! I decided to use it. So I wrote:
dlg_data[ix].m_edtField->Create(
(bVis?WS_VISIBLE:0)|ES_NUMBER|ES_RIGHT,
rRect,
this,
dlg_data[ix].m_nedtFieldID);
dlg_data[ix].m_edtField->ModifyStyleEx(0,WS_EX_CLIENTEDGE);
This compiled and ran normally, but the control has no border. Why? I explicitly set the border. I continued to read.
I learned, that border style cannot be modified with ModifyStyleEx. It can be set only on creation. The reason is unknown.
So I MUST use CreateEx(...). But windows creation fails. Why? I read forums a little more and thank godness! I found the reason. Only in one place this was described.
CreateEx need explicitly set window style WS_CHILD. The reason is unknown.
Notice, that usual Create can be successfully called without WS_CHILD. So, the final version was:
dlg_data[ix].m_edtField->CreateEx(
WS_EX_CLIENTEDGE,
"edit",
"PREFIX_EDIT1",
(bVis?WS_VISIBLE:0)|ES_NUMBER|ES_RIGHT|WS_CHILD,
rRect,
this,
dlg_data[ix].m_nedtFieldID);
This works:

RU:
(читать на русском)
Перед началом чтения убедитесь, что вы знаете, что каждый контрол (элемент управления) в винде -- это тоже окно, как и то, на чём он лежит.
Вы будете смеяться, но мне приходится использовать MFC (2011 год на дворе!). Задача была в том, чтобы создать на лету несколько CEdit. Я написал:
dlg_data[ix].m_edtField->Create(
(bVis?WS_VISIBLE:0)|ES_NUMBER|ES_RIGHT,
rRect,
this,
dlg_data[ix].m_nedtFieldID);
где:
ix -- переменная цикла;
dlg_data[ix] -- структура с данными динамических контролов;
dlg_data[ix].m_edtField -- указатель на CEdit;
bVis -- флаг видимости CEdit, если истина, создаём видимым;
rRect -- расчитанные координаты контрола, запиханные в CRect;
this -- указатель на переменную-класс, класс наследник CWnd;
dlg_data[ix].m_nedtFieldID -- ID контрола, сгенерированный специально для этого.
Как я и думал, эта строчка вывела CEdit, но без рамки, вот так:

Я почитал документацию и решил использовать WS_BORDER, получилось вот что:
dlg_data[ix].m_edtField->Create(
(bVis?WS_VISIBLE:0)|ES_NUMBER|ES_RIGHT|WS_BORDER,
rRect,
this,
dlg_data[ix].m_nedtFieldID);
Рамка появилась, но была плоской, вот такой:

Я же хотел обычную трёхмерную. Я почитал ещё немного и понял, что мне нужно установить так называемый "расширенный стиль окна" ("extended window style"). Установить его надо в WS_EX_CLIENTEDGE. Я заменил WS_BORDER:
dlg_data[ix].m_edtField->Create(
(bVis?WS_VISIBLE:0)|ES_NUMBER|ES_RIGHT|WS_EX_CLIENTEDGE,
rRect,
this,
dlg_data[ix].m_nedtFieldID);
Ничего не изменилось. Делать так было глупо, как я понял позднее. Я продолжил чтение, переключившись с документаци на гугл и форумы.
Я узнал, что расширенный стиль окна может быть установлен, но не в том же параметре, где обычный стиль, а в другом, специальном и использовать надо CerateEx(...), а не обычный Create(...). Так что я написал:
dlg_data[ix].m_edtField->CreateEx(
WS_EX_CLIENTEDGE,
"WCLASS_EDIT1",
"PREFIX_EDIT1",
(bVis?WS_VISIBLE:0)|ES_NUMBER|ES_RIGHT,
rRect,
this,
dlg_data[ix].m_nedtFieldID);
Очевидно, это не заработало, ведь я не зарегистрировал класс окна WCLASS_EDIT1. Я попробовал его зарегистрировать, потом написать NULL, а потом я попробовал стандартный класс окна "edit" (с этого надо было начинать =( ):
dlg_data[ix].m_edtField->CreateEx(
WS_EX_CLIENTEDGE,
"edit",
"PREFIX_EDIT1",
(bVis?WS_VISIBLE:0)|ES_NUMBER|ES_RIGHT,
rRect,
this,
dlg_data[ix].m_nedtFieldID);
Результат был тот же: окно не создавалось. GetLastError вовзращал 0x00000579 (0x0579, 0x579, 1041): "Неверный дескриптор меню" ("Invalid menu handle"). С какого хрена? У меня в диалоге нет меню!
Потом я подумал, может быть родительское окно у контрола установлено неверно? Я попробовал назначить его явно с помощью SetParent(...). Я ошибался, родительское окно было установлено верно.
Я плюнул на CreateEx, и вернулся к обычному Create, ведь я узнал о замечательной функции ModifyStyleEx. Она позволяет менять расширенный стиль прямо на лету! Я решил использовать её. Я написал:
dlg_data[ix].m_edtField->Create(
(bVis?WS_VISIBLE:0)|ES_NUMBER|ES_RIGHT,
rRect,
this,
dlg_data[ix].m_nedtFieldID);
dlg_data[ix].m_edtField->ModifyStyleEx(0,WS_EX_CLIENTEDGE);
Это компилировалось и работало без ошибок, однако у контрола рамки по-прежнему не было. Почему? Я же явно указал стиль рамки. Я продолжил чтение.
Я выяснил, что стиль рамки по неизвестной причине не может быть изменён на лету с помощью ModifyStyleEx. Его можно установить только при создании с помощью CreateEx.
Таким образом, мне ПРИДЁТСЯ использовать CreateEx(...). Но создать окно не удаётся. Почему? Я ещё немного почитал форумы и слава богам выяснил причину. Правда написано это было только в одном месте.
CreateEx трубует явного указания обычного стиля как WS_CHILD. Почему -- неизвестно.
Заметьте, что обычный Create может быть успешно вызван и без WS_CHILD. Итак, финальная версия:
dlg_data[ix].m_edtField->CreateEx(
WS_EX_CLIENTEDGE,
"edit",
"PREFIX_EDIT1",
(bVis?WS_VISIBLE:0)|ES_NUMBER|ES_RIGHT|WS_CHILD,
rRect,
this,
dlg_data[ix].m_nedtFieldID);
Это работает:

@темы: Программирование, Борьба с техникой, Статьи