2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу 1, 2  След.
 
 Splitter Window (MFC)
Сообщение09.04.2006, 18:07 
Аватара пользователя


18/02/06
61
Moscow
Вот я хочу сделать 2 сегмента окна, разделенных сплиттером.
И чтобы сплиттер был посередине, а пользователь не мог его перемещать.
Я делаю следующие изменения в коде, сденерированном VC++6
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/,
CCreateContext* pContext)
{

VERIFY(m_wndSplitter.CreateStatic(this,2,1));
VERIFY(m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CBmp1View),CSize(100,100), pContext));
VERIFY(m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CBmp1View),CSize(100,100), pContext));
return TRUE;

}

Класс CBmp1View у меня есть, но при попытке собрать bmp1.exe выдается ошибка:

error C2653: 'CBmp1View' : is not a class or namespace name
error C2065: 'classCBmp1View' : undeclared identifier
error C2653: 'CBmp1View' : is not a class or namespace name

Да еще вдобавок, сплиттер все равно перемещается с помощью мышки ((([/b]

 Профиль  
                  
 
 
Сообщение10.04.2006, 08:18 
Заслуженный участник
Аватара пользователя


12/10/05
478
Казань
М-дя... Я в VC++ не работаю (использую Builder).... а поэтому могу чего-то не понимать. В C++ Builder ежели я хочу двигать границы, то использую сплиттер, а если не хочу, то просто его не ставлю. Просто засовываю в одно окошко 2 компонента текстового редактора (к примеру) и выравниваю один по нижнему краю(Align = alBottom), другой - по клиентской области - (Align = alClient). В результате получаются 2 половинки окна, разделенных неподвижной границей. Мож, в MFC тоже можно сделать аналогично? Ну не в точности так, конечно.. Но мне кажется, в Вашем случае можно обойтись без сплиттера.

 Профиль  
                  
 
 
Сообщение10.04.2006, 16:30 


13/09/05
153
Москва
From MSDN:
Цитата:
Use the CreateStatic member function to create a static splitter window. The user can change only the size of the panes in a static splitter window, not their number or order.


Так что это ответ почему у Вас сплиттер "все равно перемещается".

А так, что первое приходит в голову - сделать свой CSplitterWndEx, в котором переписать обработчик OnLButtonDown (WM_LBUTTONDOWN) чтоб нельзя было передвигать - сделать его пустым, без вызова метода базового сплиттера.
Плюс к этому переписать OnSetCursor (WM_SETCURSOR) - тоже сделать пустым - чтоб не менялся курсор при наведении на сплиттер.

Можно вообще уйти от сплиттера, так как он Вам и не нужен вовсе - делаем свой класс окна - CTwoViewWnd с двумя мемберами (Вашими CView), в нем в OnCreate создаем эти два вида, в методе OnSize - делаем автомасштабирование, чтоб при изменение размеров окна два вида занимали четко половину области нашего окна (или были в некоторой заданной пропорции).
Дальше больше - можно переписать OnPaint в CTwoViewWnd - в нем рисовать рамочки для видов, чтоб отделить их визуально, при этом также переписать OnEraseBkgnd у нашего окна, так как виды сами все рисуют и подчищают.

 Профиль  
                  
 
 
Сообщение10.04.2006, 16:58 


13/09/05
153
Москва
А так - по MFC и прочим делам - практически все, что нужно, есть на http://www.codeproject.com/.

 Профиль  
                  
 
 
Сообщение10.04.2006, 17:03 
Супермодератор
Аватара пользователя


29/07/05
8248
Москва
Я не работал с такими типами окон, но с обычными работает следующий метод. Когда пользователь пытается изменить размер окна, перетаскивая границы, Windows посылает окну сообщение WM_SIZING. В нем передается указатель на Rect, содержащий размеры окна, которые будут после изменения размера. Обрабатывая это сообщение, программа может изменить эту структуру. Таким образом, можно, например, заставить размеры меняться только по определенным дискретным значениям. Или можно фактически запретить изменение размера, для этого надо устанавливать каждый раз размер окна, равный текущему.

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

Код:
ON_MESSAGE(WM_SIZING, SizingFunc)


и функция имела вид

Код:
afx_msg LRESULT CViewImage::SizingFunc(WPARAM wParam, LPARAM lParam)
{
   if(...)    
   {
      RECT *pRect = (RECT*)lParam;
      RECT CurRect;
      GetWindowRect(&CurRect);
      *pRect = CurRect;
   }
   return TRUE;
}


Почти уверен, что с вашими типами окон так или иначе работает та же система и можно запретить перетаскивание такими же средствами.

 Профиль  
                  
 
 
Сообщение10.04.2006, 18:18 


13/09/05
153
Москва
А я почти тоже самое и сказал:
или уродуем сплиттер так, чтоб он вообще перестал работать по назначению, или делаем свой CWnd, в котором переписываем обработчик WM_SIZE - и в нем при изменении масштаба изменять размеры и положение видов. В MFC это WM_SIZE и OnSize соответственно.

 Профиль  
                  
 
 
Сообщение10.04.2006, 20:25 
Аватара пользователя


18/02/06
61
Moscow
VLarin писал(а):
Можно вообще уйти от сплиттера, так как он Вам и не нужен вовсе - делаем свой класс окна - CTwoViewWnd с двумя мемберами (Вашими CView), в нем в OnCreate создаем эти два вида, в методе OnSize - делаем автомасштабирование, чтоб при изменение размеров окна два вида занимали четко половину области нашего окна (или были в некоторой заданной пропорции).
Дальше больше - можно переписать OnPaint в CTwoViewWnd - в нем рисовать рамочки для видов, чтоб отделить их визуально, при этом также переписать OnEraseBkgnd у нашего окна, так как виды сами все рисуют и подчищают.


Послушайте, вот вы сейчас пишете прямо как на Codeproject... Так же заумно. По-моему, эти все Кодопроекты - для тех, кто года 3 в VC++ сидит. А что делать, есть я только 3й день, как впервые эту прогу увидела?
Вот у меня же 2 класса CView абсолютно одинаковые, что же, мне просто в CTwoViewWnd 2 раза одно и то же прописать? А как я их потом отличать буду? Если мне надо к левой или правой половинке обратиться?
И вообще, вот эта ошибка, о которой я в первом сообщении писала, она теперь и для других классов выскакивает =( В чем может дело быть? Куда же классы пропадают?

 Профиль  
                  
 
 
Сообщение11.04.2006, 10:10 
Заслуженный участник
Аватара пользователя


12/10/05
478
Казань
Цитата:
Вот у меня же 2 класса CView абсолютно одинаковые, что же, мне просто в CTwoViewWnd 2 раза одно и то же прописать? А как я их потом отличать буду? Если мне надо к левой или правой половинке обратиться?

Вам просто надо создать 2 экземпляра этого класса (класса CView), я так понимаю.
Код:
class CTwoViewWnd
{
    CWiew view1, view2;
    ......
};

 Профиль  
                  
 
 
Сообщение11.04.2006, 14:45 


13/09/05
153
Москва
Написал MFC-пример - как уйти от сплиттера и показать два объекта на одном виде.
В примере сделал два варианта - с использованием CWnd-derived классов и с использованием CView-derived классов в качестве левых и правых окон.
Пример здесь.

В кратце - главный вид ничего вообще не делает кроме как рисует рамочки для двух (можно и больше) своих мемберов. Сами мемберы - это CWnd или CView-derived, так что можно прицепить что-угодно.

Цитата:
Вот у меня же 2 класса CView абсолютно одинаковые, что же, мне просто в CTwoViewWnd 2 раза одно и то же прописать? А как я их потом отличать буду? Если мне надо к левой или правой половинке обратиться?


Делаем два (или более) мембера - я назвал их m_wndLeft и m_wndRight - и так и обращаемся к ним
Код:
m_wndLeft.GetClientRect(rect);


Цитата:
error C2653: 'CBmp1View' : is not a class or namespace name
error C2065: 'classCBmp1View' : undeclared identifier
error C2653: 'CBmp1View' : is not a class or namespace name


Это, как я понимаю, Вы просто забыли подключить нужный header-файл.

 Профиль  
                  
 
 
Сообщение11.04.2006, 15:38 


13/09/05
153
Москва
По поводу CSplitterWnd - здесь есть свои тонкости - MFC не дает создать с помощью Class Wizard класс, унаследованый от CSplitterWnd. Так что, далаем класс CSplitterWndEx наследованным от CWnd (generic CWnd).
Затем проходимся по получившимся файлам и меняем CWnd на CSplitterWnd.

Дальше - Вам нужно заблокировать передвижение сплиттера - смотрим в оригинал - WINSPLIT.CPP (находится в папке с MFC - по умолчанию это C:\Program Files\Microsoft Visual Studio\VC98\MFC\SRC\) и думаем что можно сделать:))

Посмотрев на работу можно сделать следующие выводы - 1. При нажатии на него отображается линия перемещения. 2. При подведении мышки к нему меняется курсор.

Значит нам нужно в своем CSplitterWndEx переписать обработчики нажатия на левую кнопу и перемещения мыши. Смена курсора - это обычно WM_SETCURSOR - но, если посмотреть в WINSPLIT.CPP, то они там в обработчике этого сообщения ничего не меняют. Курсор меняется только при нажатии и перемещении мышки (в OnLButtonDown и OnMouseMove).
Так что нужно всего лишь сделать пустыми в своей реализации CSplitterWndEx эти два метода:
Код:
void CSplitterWndEx::OnLButtonDown(UINT nFlags, CPoint point)
{
//   CSplitterWnd::OnLButtonDown(nFlags, point);
}

void CSplitterWndEx::OnMouseMove(UINT nFlags, CPoint point)
{
//   CSplitterWnd::OnMouseMove(nFlags, point);
}


Создание сплиттера -
Код:
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
   CRect rect;
   GetWindowRect(rect);
   if (!m_wndSplitter.CreateStatic(this, 1, 2))
      return FALSE;

   if (!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CTestSplitterView), CSize(rect.Width()/2, rect.Height()), pContext))
      return FALSE;
   if (!m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CTestSplitterView), CSize(rect.Width()/2, rect.Height()), pContext))
      return FALSE;

   m_bSplitterInit = TRUE;
   return TRUE;
}


Ну и можно сделать автомасштабирование видов при изменении размеров главного окна. Нужно сделать обрабочик сообщения WM_SIZE в CMainFrm - здесь важный момент, что при создании сплиттера (CSplitterWnd::CreateStatic) шлется сообщение WM_SIZE, а сам сплиттер еще до конца нами и не определен (виды то не добавили:)). Поэтому в мейнфрейм добавляем флажок m_bSplitterInit, а в OnSize проверяем это дело -
Код:
void CMainFrame::OnSize(UINT nType, int cx, int cy)
{
   CFrameWnd::OnSize(nType, cx, cy);
   if (m_bSplitterInit)
   {
      CRect rect;
      GetWindowRect(rect);
      m_wndSplitter.SetRowInfo(0, cy, 0);
      m_wndSplitter.SetColumnInfo(0, rect.Width()/2, 50);
      m_wndSplitter.SetColumnInfo(1, rect.Width()/2, 50);
      m_wndSplitter.RecalcLayout();
   }
}

 Профиль  
                  
 
 
Сообщение11.04.2006, 21:09 
Аватара пользователя


18/02/06
61
Moscow
VLarin
Какую среду вы используете? При попытке открыть файл .dsw мне выдается ошибка, что файл is invalid and will be removed from project workspace =(

Насчет класса bmp1 - этот клаас создал сам MFC при создании проекта, так что все хедеры на месте

 Профиль  
                  
 
 
Сообщение12.04.2006, 12:49 


13/09/05
153
Москва
Проект под Visual C++ 6.0. Попробуйте открыть из самой студии - File -> Open Workspace.
Должно работать. В любом случае у Вас есть все исходные файлы, попробуйте создать свой проект с таким же названием и добавить в него все файлы:)

Цитата:
Насчет класса bmp1 - этот клаас создал сам MFC при создании проекта, так что все хедеры на месте


Да, но Вы создаете сплиттер и добавляете в него вид в теле CMainFrm, а в нем хедер вида не подключен. Кроме того, в CMainFrm прийдется подключить еще и хедер документа, так как в виде есть упоминание документа CMyDoc* GetDocument(), а хедер документа подключается в реализации вида.

 Профиль  
                  
 
 
Сообщение12.04.2006, 14:03 
Заслуженный участник
Аватара пользователя


12/10/05
478
Казань
У меня ваш проект в VC 6 вообще не компилится - говорит, что нет файла afxres.h. :(

 Профиль  
                  
 
 
Сообщение12.04.2006, 17:19 


13/09/05
153
Москва
To Sanyok:
Afxres.h - это просто у Вас пути к MFC в студии не прописаны -
Include files - "C:\Program Files\Microsoft Visual Studio\VC98\MFC\Include"
Library files - "C:\Program Files\Microsoft Visual Studio\VC98\MFC\Lib"

 Профиль  
                  
 
 
Сообщение13.04.2006, 07:40 
Аватара пользователя


18/02/06
61
Moscow
VLarin писал(а):
Да, но Вы создаете сплиттер и добавляете в него вид в теле CMainFrm, а в нем хедер вида не подключен. Кроме того, в CMainFrm прийдется подключить еще и хедер документа, так как в виде есть упоминание документа CMyDoc* GetDocument(), а хедер документа подключается в реализации вида.


То есть, когда я изменяю тело CMainFrm, то мне надо вносить изменения и в Bmp1.h, так что ли? И что надо туда дописать? Ведь, судя по тому, что до создания сплиттера, CMainFrm нормально работал с Cbmp1, хедер уже был подключен?

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 29 ]  На страницу 1, 2  След.

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



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

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group