Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Ресайзинг диалога и перепозиционирование контролов, все работает, но может, можно проще? 
:(
    Опции темы
Dreamer_0x01
Дата 1.11.2005, 21:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Терминатор
**


Профиль
Группа: Участник
Сообщений: 780
Регистрация: 14.4.2005
Где: Санкт-Петербург

Репутация: 9
Всего: 12



Столкнулся с такой проблемой.
Нужно обрабатывать изменение пользователем размеров диалога.
Диалог содержит в себе контролы, которые тоже надо репозиционировать.
Для этого я обрабатываю событие WM_SIZING.

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

Проблем в том, что координаты прямоугольника, передающиеся обработчику этого сообщения, соответствуют координатам прямоугольника ВСЕГО окна.
(как например, если бы мы пользовались функцией GetWindowRect()).
Но часть площади окна занято на заголовок окна(системное меню), а также на рисование объемной рамочки вокруг окна.
Оставшееся "рабочее" пространство окна можно узнать с помощью функции
GetClientRec(). Но проблема в том, что если ее вызвать непосредственно в обработчике данного события, то она вернет координаты прямоугольника, соответствующего "старым" границам окна, существовавшего до момента начала изменения его размеров.

Мне пришлось вычислять место, занимаемое системным меню и объемной рамочкой, и в обработчике события его учитывать.
Все работает.
Но у менятакое чувство, что можно было все сделать проще.
МОЖНО ИЛИ НЕТ?

вот код, аналогичный моему:
Код

// test_resizeDlg.h : header file
#pragma once

class Ctest_resizeDlg : public CDialog
{
public:
    Ctest_resizeDlg(CWnd* pParent = NULL);    // standard constructor
    enum { IDD = IDD_TEST_RESIZE_DIALOG };

protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    HICON m_hIcon;
    virtual BOOL OnInitDialog();
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    DECLARE_MESSAGE_MAP()
private:
    CButton *cb[4]; //мои элементы, например, кнопочки
    int v_menu_size;//вертикальный размер,занимаемый системным меню и бордером
    int g_border_size;//горизонтальный размер, занимаемый бордером
public:
    virtual BOOL DestroyWindow();
    afx_msg void OnSizing(UINT fwSide, LPRECT pRect);
};






Код

// test_resizeDlg.cpp : implementation file

BEGIN_MESSAGE_MAP(Ctest_resizeDlg, CDialog)
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    //}}AFX_MSG_MAP
    ON_WM_SIZING()
END_MESSAGE_MAP()

BOOL Ctest_resizeDlg::OnInitDialog()
{
    CDialog::OnInitDialog();
    SetIcon(m_hIcon, TRUE);            // Set big icon
    SetIcon(m_hIcon, FALSE);        // Set small icon

    CRect cr;//С помощью него узнаем размеры системного меню и бордеров
    this->GetWindowRect(cr);//сначала узнаем размеры окна
    this->v_menu_size=cr.Height();
    this->g_border_size=cr.Width();
    this->GetClientRect(cr);//и потом вычитаем из него клиентские размеры
    this->v_menu_size-=cr.Height();
    this->g_border_size-=cr.Width();
    for(int i=0;i<4;i++)//для примера делаем четыре кнопки, располагаем их 2х2
    {
        int l,t,r,b,ls,hs;
        CString str;
        this->cb[i]=new CButton();
        ls=cr.Width()/2;hs=cr.Height()/2;
        l=(i%2)*ls;
        r=l+ls;
        t=(i/2)*hs;
        b=t+hs;
        str.Format("Кнопка %d",i);
        cb[i]->Create(str,BS_PUSHBUTTON|WS_CHILD|WS_VISIBLE,CRect(l,t,r,b),this,i+1000);
    }
    return TRUE;  
}

BOOL Ctest_resizeDlg::DestroyWindow()
{
    for(int i=0;i<4;i++)
    {
        this->cb[i]->DestroyWindow();
        delete cb[i];
    }

    return CDialog::DestroyWindow();
}

void Ctest_resizeDlg::OnSizing(UINT fwSide, LPRECT pRect)
{
    CDialog::OnSizing(fwSide, pRect);
    //в прямоугольнике pRect хранятся координаты "внешних" границ
    //а нам нужны клиентские координаты
    //поэтому в OnInitDialog() вычислено смещение
    /*если здесь вызвать GetClientRec(....),
    то результат будет содержать "старые" координаты */
    for(int i=0;i<4;i++)//ресайз контролов (в нашем случае - наших кнопок)
    {
        /*расстановка кнопок - такая же, как в OnInitDialog(),
        но приходится учитывать смещение размеров 
        заголовка окна и объемных границ окна*/
        int l,t,r,b,ls,hs;
        ls=(pRect->right-pRect->left-this->g_border_size)/2;//вот здесь учтем смещение
        hs=(pRect->bottom-pRect->top-this->v_menu_size)/2;//и здесь
        l=(i%2)*ls;
        r=l+ls;
        t=(i/2)*hs;
        b=t+hs;
        cb[i]->SetWindowPos(this,l,t,r-l,b-t,SWP_NOZORDER);
    }
}


Это сообщение отредактировал(а) Dreamer_0x01 - 1.11.2005, 21:03


--------------------
Нет ничего невозможного. Есть цели, и есть время и силы на их достижение.
PM ICQ   Вверх
nikf
Дата 1.11.2005, 21:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 127
Регистрация: 6.6.2005
Где: город-герой Жирно вск

Репутация: 1
Всего: 1



WM_SIZING lParam - pointer to RECT
PM MAIL   Вверх
Dreamer_0x01
Дата 1.11.2005, 22:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Терминатор
**


Профиль
Группа: Участник
Сообщений: 780
Регистрация: 14.4.2005
Где: Санкт-Петербург

Репутация: 9
Всего: 12



ну да, но поинтер он именно на ПОЛНЫЙ RECT, который занимает ВСЕ ОКНО.
А мне нужен КЛИЕНТСИЙ!


--------------------
Нет ничего невозможного. Есть цели, и есть время и силы на их достижение.
PM ICQ   Вверх
Earnest
Дата 2.11.2005, 14:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Цитата(Dreamer_0x01 @ 1.11.2005, 21:01)
Но у менятакое чувство, что можно было все сделать проще.

Боюсь, нет. Вот наоборот - можно, т.е. по заданному клиенту вычислить размер всего окна (AdjustWindowRectEx), а вот по всему окну вычислить клиента - не знаю такой функции.

Однако я бы тебе предложила другой подход: создай мэп(контрол->позиция относительно WindowRect), а потом при изменени размеров окна все рисуй согласно полученному ректу, и все.


--------------------
...
PM   Вверх
Coocky
Дата 2.11.2005, 17:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


GUI гуру
****


Профиль
Группа: Участник Клуба
Сообщений: 2879
Регистрация: 16.2.2004
Где: Украина. Запорожь е

Репутация: 25
Всего: 62



Цитата
Но проблема в том, что если ее вызвать непосредственно в обработчике данного события, то она вернет координаты прямоугольника, соответствующего "старым" границам окна, существовавшего до момента начала изменения его размеров

Вставлю свою ламерскую морду.
Может подойдет WM_WINDOWPOSCHANGING ?

Это сообщение отредактировал(а) Coocky - 2.11.2005, 18:00


--------------------
Верю в смерть после жизни, в любовь после секса ,в крем после бритья smile        
PM ICQ   Вверх
Earnest
Дата 2.11.2005, 19:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Нет, WM_WINDOWPOSCHANGING не подойдет. Во-первых, оно содержит тот же RECT всего окна, а во-вторых - приходит только один раз, непосредственно перед установкой размеров окна, а не как нужно Терминатору - во время ресайзинга.

Появилась дикая мысль - послать окну запрос WM_NCCALCSIZE с параметрами wParam=false, lParam=&(WindowRect). Судя по описанию, окно должно пересчитать этот рект в клиенский:

Цитата

If wParam is FALSE, lParam points to a RECT structure. On entry, the structure contains the proposed window rectangle for the window. On exit, the structure should contain the screen coordinates of the corresponding window client area.


Но как это будет себя вести во время обработки WM_SIZING - не могу сказать.


--------------------
...
PM   Вверх
Coocky
Дата 2.11.2005, 19:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


GUI гуру
****


Профиль
Группа: Участник Клуба
Сообщений: 2879
Регистрация: 16.2.2004
Где: Украина. Запорожь е

Репутация: 25
Всего: 62



Цитата(Earnest @ 2.11.2005, 19:25)
Нет, WM_WINDOWPOSCHANGING не подойдет. Во-первых, оно содержит тот же RECT всего окна, а во-вторых - приходит только один раз, непосредственно перед установкой размеров окна, а не как нужно Терминатору - во время ресайзинга.

Да я уже понял..(попробывал smile )

Цитата(Earnest @ 2.11.2005, 19:25)
Появилась дикая мысль - послать окну запрос WM_NCCALCSIZE с параметрами wParam=false, lParam=&(WindowRect). Судя по описанию, окно должно пересчитать этот рект в клиенский:

Незнаю, в жизни не использовал никогда.. smile



--------------------
Верю в смерть после жизни, в любовь после секса ,в крем после бритья smile        
PM ICQ   Вверх
Dreamer_0x01
Дата 2.11.2005, 20:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Терминатор
**


Профиль
Группа: Участник
Сообщений: 780
Регистрация: 14.4.2005
Где: Санкт-Петербург

Репутация: 9
Всего: 12



Цитата(Earnest @ 2.11.2005, 14:32)
днако я бы тебе предложила другой подход: создай мэп(контрол->позиция относительно WindowRect), а потом при изменени размеров окна все рисуй согласно полученному ректу, и все.


В принципе, суть метода та же.
мне при размещении контролов придется учитывать смещение ClientRect относительно WindowRect, чтобы контролы не вылезли за пределы клиентской области. И тоскать за собой уже не смещение, а этот мэп.
Все равно что называется "в два действия", как и у меня.



Цитата(Earnest @ 2.11.2005, 19:25)
а не как нужно Терминатору

Эт хто? Я Dreamer!
smile


Цитата(Earnest @ 2.11.2005, 19:25)
Появилась дикая мысль - послать окну запрос WM_NCCALCSIZE с параметрами wParam=false, lParam=&(WindowRect). Судя по описанию, окно должно пересчитать этот рект в клиенский:


Цитата 

If wParam is FALSE, lParam points to a RECT structure. On entry, the structure contains the proposed window rectangle for the window. On exit, the structure should contain the screen coordinates of the corresponding window client area.


Но как это будет себя вести во время обработки WM_SIZING - не могу сказать.


А вот фигово ведет. Структуру заполняет левыми значениями, правильные они получаются только тогда, когда окно перересуется. (то есть отработает WM_SIZE, когда пользователь отпустит мышку). Во время WM_SIZING оно по-видимому определять эти прямоугольники не умеет.



--------------------
Нет ничего невозможного. Есть цели, и есть время и силы на их достижение.
PM ICQ   Вверх
Dreamer_0x01
Дата 3.11.2005, 16:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Терминатор
**


Профиль
Группа: Участник
Сообщений: 780
Регистрация: 14.4.2005
Где: Санкт-Петербург

Репутация: 9
Всего: 12



Coocky
Earnest

Где же вы???


--------------------
Нет ничего невозможного. Есть цели, и есть время и силы на их достижение.
PM ICQ   Вверх
Coocky
Дата 3.11.2005, 17:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


GUI гуру
****


Профиль
Группа: Участник Клуба
Сообщений: 2879
Регистрация: 16.2.2004
Где: Украина. Запорожь е

Репутация: 25
Всего: 62



Dreamer_0x01
Я здесь, но на данный момент помочь ничем не могу..
Смотри, я сам вопросы задаю, дел по горло, некогда даже потренироваться на твоем коде.. smile


--------------------
Верю в смерть после жизни, в любовь после секса ,в крем после бритья smile        
PM ICQ   Вверх
Earnest
Дата 3.11.2005, 18:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Цитата(Dreamer_0x01 @ 2.11.2005, 20:38)
А вот фигово ведет.

Ну, я и не обещала, что будет хорошо. Но я не сомневалась, что ты не применешь поэкспериментировать (и всем расскажешь). За что спасибо. smile

Цитата(Dreamer_0x01 @ 2.11.2005, 20:38)
Все равно что называется "в два действия", как и у меня.

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

И какая тебе разница, что там будет храниться в базовом классе? Хоть 10 мэпов. Главное, чтобы основную логику конкретного окна не застило.


--------------------
...
PM   Вверх
Dreamer_0x01
Дата 6.11.2005, 13:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Терминатор
**


Профиль
Группа: Участник
Сообщений: 780
Регистрация: 14.4.2005
Где: Санкт-Петербург

Репутация: 9
Всего: 12



Цитата(Earnest @ 3.11.2005, 18:59)
Ну, я и не обещала, что будет хорошо. Но я не сомневалась, что ты не применешь поэкспериментировать (и всем расскажешь). За что спасибо.


Это вот тебе спасибо за участие и дельные мысли.

Цитата(Earnest @ 3.11.2005, 18:59)
И какая тебе разница, что там будет храниться в базовом классе? Хоть 10 мэпов.


а как же увеличение размера кода? Ведь моя программа будет вывешена на сайте нашего предприятия, чтобы клиенты могли скачивать ее для настройки наших приборов. И хоть я понимаю, что использование MFC в обмен на простоту использования дает увеличение кода и снижение скорости работы исполняемого кода, но все-таки злоупотреблять такими фактами не стоит. Не каждому понравится выкачивать многометровые файлы с сайта. Опять же, к использованию ресурсов мне тоже следует относиться осторожно, так как у многих заказчиков все еще стоят Win95 на первых пентиумах....


--------------------
Нет ничего невозможного. Есть цели, и есть время и силы на их достижение.
PM ICQ   Вверх
AlexPro
Дата 13.11.2005, 10:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 157
Регистрация: 9.11.2005
Где: Санкт-Петербург

Репутация: 3
Всего: 4



Видимо, я чего-то не улавливаю, но мне непонятно, к чему такие сложности. Чем не угодил WM_SIZE? Вся обработка ведется в OnSize. Получаешь размеры клиентской области функцией GetClientRect() для диалогового окна и двигаешь или меняешь размеры своих контролов как тебе понравится. Все происходит в режиме реального времени. Или этот путь черезчур прост? smile
PM MAIL   Вверх
Dreamer_0x01
Дата 13.11.2005, 23:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Терминатор
**


Профиль
Группа: Участник
Сообщений: 780
Регистрация: 14.4.2005
Где: Санкт-Петербург

Репутация: 9
Всего: 12



Цитата(AlexPro @ 13.11.2005, 10:27)
Все происходит в режиме реального времени


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



--------------------
Нет ничего невозможного. Есть цели, и есть время и силы на их достижение.
PM ICQ   Вверх
The Thing
Дата 14.11.2005, 00:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 286
Регистрация: 6.9.2004

Репутация: 1
Всего: 3



Dreamer_0x01
Юзай сообщения ON_WM_GETMINMAXINFO()
Сюда приходит сообщение раньше всего...

Код

MainFrame.h
afx_msg void OnGetMinMaxInfo(MINMAXINFO *lpMMI);

MainFrame.cpp
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    //{{AFX_MSG_MAP(CMainFrame)
                ...
    ON_WM_GETMINMAXINFO()
    ON_WM_SIZE()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

Добавлено @ 00:35
забыл...
Код

void CMainFrame::OnGetMinMaxInfo(MINMAXINFO *lpMMI)
{
//не забудь
    CFrameWnd::OnGetMinMaxInfo(lpMMI);
}

Добавлено @ 00:42
Да, забыл объяснить.. сюда как раз и приходят сообщения которые пытается поймать Dreamer_0x01... т.е. сообщения приходят при изменение размеры.. правдо может возникнуть некоторая проблема с отрисовкой контролов.. но ето все решаемо.. и вопрос №2.


--------------------
Правильность работы программы зависит от двух велечин.
В нужном месте должны стоять нолик и еденичка.
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Visual C++/MFC/WTL | Следующая тема »


 




[ Время генерации скрипта: 0.1258 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.