Рейтинговые книги
Читем онлайн Программирование на Visual C++. Архив рассылки - Алекс Jenter

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 15 16 17 18 19 20 21 22 23 ... 156

Теперь в файл mypropsheet.h (где объявлен класс CMyPropSheet) пишем:

#include "proppage1.h" // делаем классы страниц видимыми

#include "proppage2.h"

class CMyPropSheet: public CPropertySheet {

 …

protected:

 CPropPage1 page1; // первая страница

 CPropPage2 page2; // вторая страница

 …

}

Чтобы добавить страницы к окну свойств, необходимо в каждый из конструкторов CMyPropSheet вставить по две следующие строчки:

AddPage(&page1);

AddPage(&page2);

Таким образом, мы сделали страницы-закладки частью нашего окна свойств. Настал момент теперь решить, где вы собираетесь хранить настройки вашего приложения. Я это обычно делаю в классе главного окна, по причине легкости доступа, но ничто не мешает вам хранить их там, где удобнее, причем не обязательно все вместе. Неплохой вариант – хранить их в классе приложения, даже с некоторой точки зрения он более логичный.

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

class CMainFrame: public CFrameWnd {

 …

public:

 struct Options {

  CString str;

  BOOL val;

 } options;

 …

}

В конструкторе CMainFrame поля структуры options установите в начальные значения. Их можно задать жестко, но обычно сохраненные ранее значения загружаются из файла или реестра , иначе вы быстро доведете пользователя вашей программы до белого каления, заставляя его менять параметры после каждого запуска.

Теперь вставьте обработчик события, возникновение которого должно приводить к выводу на экран вашего окна свойств (например, выбор пункта меню "Сервис|Параметры…"). В обработчике вы устанавливаете параметры, после чего выводите окно свойств. Если пользователь нажал "OK", то после закрытия окна свойств нужно обновить структуру options:

#include "mypropsheet.h"

void CMainFrame::OnToolsOptions() {

 CMyPropSheet ps("Параметры приложения", this, 0);

 ps.page1.m_strEdit = options.str;   // настраиваем закладки

 ps.page2.m_isChecked = options.val; // соответственно текущим параметрам

 if (ps.DoModal() == IDOK) // если пользователь нажал OK

 {

  options.str = ps.page1.m_strEdit; // сохраняем параметры

  options.val = ps.page2.m_isChecked;

 }

}

Вот и все, что касается элементарного использования класса CPropertySheet для создания окна свойств. Как видите, работать с ним довольно просто. В одном из следующих выпусков я расскажу вам о задействовании кнопки "Применить" ("Apply"), о нетривиальном использовании этого класса для создания мастеров (wizards), а также о расширенном классе CPropertySheetEx.

ВОПРОС-ОТВЕТ

Q. Возникла вот такая задачка. Имеется некоторое разбиение SDI на несколько view при помощи сплиттеров (A). Как его изменить не убивая окна (на B или C)?

  +--+----+     +--+----+    +--+----+

  |  |    |     |  |    |    +  +    +

  +--+----+     +--+    |    +  +----+

  |       |     |  |    |    +  +    +

A +-------+   B +--+----+  C +--+----+

Nikita Zeemin

A. Для создания окна сплиттера в MFC служит класс CSplitterWnd. Этот класс предоставляет функции для создания вида (CreateView) и удаления вида DeleteView) в заданной панели, но не предоставляет функции, которая позволила бы перенести вид из одной панели в другую. Чтобы проделать это вручную, нужно понимать, каким образом связаны объект класса CSplitterWnd и объекты дочерних видов CView.

CSplitterWnd может иметь не более 16 панелей по горизонтали и столько же по вертикали. Таким образом, он может сожержать не более 256 панелей. Каждой панели соответствует уникальный идентификатор, который и назначается тому виду, который в этой панели находится. Отображение координат панели на её идентификатор выполняет функция int CSplitterWnd::IdFromRowCol(int row, int col);

На самом деле после целой серии ASSERT'ов она просто возвращает значение

AFX_IDW_PANE_FIRST + row * 16 + col

где AFX_IDW_PANE_FIRST — константа, объявленная в MFC.

Это подсказывает простой способ перемещения вида из одной панели в другую: нужно всего лишь подменить его идентификатор, после чего вызвать CSplitterWnd::RecalcLayout для обновления содержимого сплиттера. Если изначально вид не являлся дочерним окном сплиттера и требуется поместить его в одну из панелей, то необходимо также поменять ему родителя с помощью функции CWnd::SetParent. Таким образом функция, вставляющая вид в заданную панель, может выглядеть примерно так:

class CMySplitter : public CSplitterWnd {

 …

 void InsertView(int nRow, int nCol, CWnd *pView) {

  pView->SetParent(this);

  pView->SetDlgCtrlID(IdFromRowCol(nRow, nCol));

 }

 …

}

Аналогичным образом вид переносится "в юрисдикцию" главного окна приложения, порождённого от CFrameWnd:

class CMyFrame : public CFrameWnd {

 …

 void InsertView(CWnd *pView) {

  pView->SetParent(this);

  pView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);

 }

 …

}

Имея в руках эти две функции, можно без труда решить поставленную задачу, располагая виды как на рис. A, B, C или любым другим способом. Ещё раз замечу, что после всех перемещений необходимо вызывать CSplitterWnd::RecalcLayout и CFrameWnd::RecalcLayout.

Alexander Shargin ОБРАТНАЯ СВЯЗЬ

Alexander Shargin, воистину герой сегодняшнего выпуска, в письме с ответом на предыдущий вопрос также недоумевал по поводу вопроса прошлого выпуска, где требовалось минимизировать CPropertySheet:

…Честно говоря, я не понимаю, о чём идёт речь. Я буду очень вам признателен, если вы объясните мне, в чём проблема. Дело в том, что я создал визардом приложение на базе диалога, а затем просто заменил диалог на объект класса CMySheet, порождённого от CPropertySheet. После чего добавил пару вкладок (типа CPropertyPage) и вызов ModifyStyle(0, WS_MINIMIZEBOX) в обработчике OnCreate. В результате этих несложных операций получилось приложение, главное окно которого без проблем сворачивается на панель задач.

Я посмотрел приаттаченный им проект и убедился, что Александр совершенно прав. После чего я сам проделал то же самое с новым проектом, и получил такой же результат. Итак, вся загвоздка была в том, что ModifyStyle нужно было вызывать не из OnInitDialog, а из OnCreate!

После этого я задумался, откуда же у класса CPropertySheet вообще есть метод OnInitDialog, ведь сам класс является прямым наследником CWnd. Оказалось, что этот метод, наряду с DoModal, был добавлен туда искусственно, чтобы обращение с классом напоминало обращение с CDialog. Не знаю, почему бы Microsoft просто не сделать CPropertySheet наследником CDialog, но наверное у них были свои причины (хотя здесь можно и посомневаться ;)

Я переслал письмо Александра человеку, задавшему вопрос, и получил от него положительный ответ – у него тоже все заработало.

Вот, оказывается, как просто открывался ларчик! Не надо было перехватывать WM_NCLBUTTONDOWN, не нужно было делать callback функцию… (решение автора вопроса)…

И еще – насчет минимизации в левый нижний угол – видимо это был частный случай поведения, вызванный моими манипуляциями со стилями ;-)

Напоследок хочу процитировать Win32 Q&A из MSDN, чтобы абсолютно точно уяснить для всех

Как Windows определяет, нужно ли выводить кнопку приложения на панель задач

Правила эти довольно просты, хотя и не очень хорошо документированы. Когда вы создаете окно, Windows проверяет его расширенный стиль. Если установлен стиль WS_EX_APPWINDOW (определенный как 0x00040000), на панель задач выводится кнопка окна. Если же установлен стиль WS_EX_TOOLWINDOW (0x00000080), то кнопка не выводится. Не следует создавать окна, где установлены оба эти стиля.

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

И последнее замечание: прежде чем тестировать что-либо из вышеописанного, панель задач проверяет, установлен ли стандартный стиль видимости WS_VISIBLE. Если нет, то окно спрятано, и показывать кнопку нет никакого смысла. Стили WS_EX_APPWINDOW, WS_EX_TOOLWINDOW и информация о принадлежности окна проверяются ТОЛЬКО при установленном  WS_VISIBLE.

Jeffrey Richter В ПОИСКАХ ИСТИНЫ

Q. У меня программа с использованием MFC и Doc/View. Я вставил RichEditCtrl во вью. (2-ой версии). Установил шрифт с помощью сообщения SetCharFormat. Внимание, вопрос: почему если я ввожу текст с клавиатуры и использую ReplaceText функцию (не сообщение!) фонты различные? Вроде это сообщение не менялось у второй версии. Заранее спасибо за ответ.

Игорь

Это все на сегодня. Пока!

© Алекс Jenter mailto:[email protected] Красноярск, 2000.

Программирование на Visual C++

1 ... 15 16 17 18 19 20 21 22 23 ... 156
На этой странице вы можете бесплатно читать книгу Программирование на Visual C++. Архив рассылки - Алекс Jenter бесплатно.
Похожие на Программирование на Visual C++. Архив рассылки - Алекс Jenter книги

Оставить комментарий