Вход/Регистрация
Программирование на Visual C++. Архив рассылки
вернуться

Jenter Алекс

Шрифт:

На вопрос из выпуска №27 о пунктирной рамке вокруг кнопки: 

Предложенный Александром Шаргиным вариант с тулбаром врядли можно признать удовлетворительным. Диалог не получит сообщение от тулбара да и программное создание кнопки… Можно, конечно, но… :-( . Наиболее приемлемый выход – использование самопрорисовывающихся элементов управления. Достоинство этого метода – нарисовать можно всё, что угодно! :-))). А в вопросе Максима Чучуйко есть ещё подвопрос: А должна ли кнопка вообще получать фокус?.

В общем, плоскую кнопку, не получающую фокус совсем сделать достаточно просто:

1) Создаём класс

CFlatButton: public CButton;

2) Добавляем переменные:

protected:

 BOOL bMouseCaptured;

 CWnd* pOldFocus;

В конструкторе инициализируем:

 bMouseCaptured = FALSE;

 pOldFocus = NULL;

3) Добавляем методы:

protected:

 void CFlatButton::SetOldFocus {

// Закомментировать тело метода, если кнопка может получать фокус.

if (pOldFocus) pOldFocus->SetFocus;

pOldFocus =NULL;

}

Добавляем обработчики сообщений:

 void CFlatButton::OnSetFocus(CWnd* pOldWnd) {

CButton::OnSetFocus(pOldWnd);

if (!pOldFocus) // Дабы не было проблем с модальными окнами, вызываемыми по нажатию этой кнопки.

pOldFocus = pOldWnd;

 }

 void CFlatButton::OnLButtonUp(UINT nFlags, CPoint point) {

CButton::OnLButtonUp(nFlags, point);

CRect rectBtn;

GetClientRect(rectBtn);

if (rectBtn.PtInRect(point) && GetCapture != this) {

bMouseCaptured = TRUE;

SetCapture;

Invalidate(FALSE);

}

SetOldFocus;

 }

 void CFlatButton::OnMouseMove(UINT nFlags, CPoint point) {

CRect rectBtn;

GetClientRect(rectBtn);

if (rectBtn.PtInRect(point)) {

BOOL bNeedUpdate =FALSE;

if (!bMouseCaptured) bNeedUpdate = TRUE;

bMouseCaptured = TRUE;

SetCapture;

if (bNeedUpdate) Invalidate(FALSE);

} else {

bMouseCaptured = FALSE;

ReleaseCapture;

SetOldFocus;

Invalidate(FALSE);

}

CButton::OnMouseMove(nFlags, point);

 }

И, самое интересное… :-))) Перекрываем виртуальный метод:

void CFlatButton::DrawItem(LPDRAWITEMSTRUCT lpDIS) {

 // Test WS_TABSTOP

 ASSERT(!(GetStyle & WS_TABSTOP)); 

 CDC* pDC = CDC::FromHandle(lpDIS->hDC);

 CRect rectAll;

 GetClientRect(rectAll);

 CString text;

 GetWindowText(text);

 int save = pDC->SaveDC;

 CRect rectText(rectAll);

 rectText.DeflateRect(2,2);

 CBrush bkBr(GetSysColor(COLOR_3DFACE));

 pDC->FillRect(rectAll,&bkBr);

 UINT state = lpDIS->itemState;

 if (state & ODS_SELECTED) {

// Нажатое состояние

rectText.OffsetRect(1,1);

pDC->DrawEdge(rectAll, BDR_SUNKENOUTER, BF_RECT);

 } else {

if (bMouseCaptured) {

pDC->DrawEdge(rectAll, BDR_RAISEDINNER, BF_RECT);

}

 }

 pDC->DrawText(text, rectText, DT_SINGLELINE|DT_VCENTER|DT_CENTER|DT_TOP);

 pDC->RestoreDC(save);

}

Использование: очень просто. Ставим на шаблоне диалога кнопку, убираем стиль WS_TABSTOP, ставим стиль WS_OWNERDRAW. В ClassWizard'е сопоставляем ей переменную типа CButton, затем тип переменной вручную меняем на CFlatButton. И всё. Далее – как с обычной кнопкой. У меня (VC++ 5.0) – работает.

Дмитрий Сулима
В ПОИСКАХ ИСТИНЫ

Q. Как включать в проект незарегистрированный компонент ActiveX? Вернее он на моей машине зарегистрирован, а на другой нет, и в результате этого программа на той машине вообще не запускается.

Сергей Лобачев

Это все на сегодня. Удачи вам!

Алекс Jenter jenter@mail.ru Красноярск, 2000.

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

Выпуск №30 от 28 января 2001 г.

Здравствуйте, дорогие друзья!

Я очень рад вас всех вновь приветствовать! К сожалению, по не зависящим от меня причинам я не имел возможности выпускать рассылку вплоть до настоящего времени. Искренне прошу извинить за причиненные неудобства и такой вот вынужденный перерыв. Хочу развеять опасения некоторых товарищей: рассылку я закрывать не собираюсь. Начиная с сегодняшнего дня, выпуски будут опять выходить регулярно.

За это время количество подписчиков перевалило за 10 000 – действительно круглое число! Создавая рассылку, я и не предполагал, что она будет пользоваться такой популярностью – все-таки весьма специфичная тематика. Но это значит, что рассылка актуальна, и это не может не радовать. Что еще могу сказать – оставайтесь с нами, и скорее всего не пожалеете!

А теперь – let's get started!

СТАТЬЯ

Помнится, в одном из декабрьских выпусков шел у нас разговор о предотвращении запуска второй копии приложения. Тогда мы затронули тему использования объектов синхронизации, подробнее про которые я пообещал рассказать во второй части статьи про многозадачность. Тема эта хотя и очень интересная, но и довольно обширная; так что учитывая ограниченность места в одном выпуске, я освещу только самые важные для понимания моменты. Некоторые же второстепенные темы – такие, как предотвращение взаимного блокирования потоков, или оповещения об изменениях, – я здесь лишь упомяну, и (возможно) вынесу в дальнейшем в отдельную статью. Также в отдельную статью скорее всего выльется очень важная тема межпроцессного обмена данными (inter-process communication, IPC). Как скоро появятся эти статьи, будет зависеть от степени их востребованности. А пока представляю вашему вниманию давно обещанную вторую часть статьи про многозадачность.

Многозадачность и ее применение
Часть 2: Синхронизация потоков

Итак, в первой части статьи (см. №23) мы определили, что использование многопоточности находит себе широчайшее применение в самых различных программах и позволяет значительно повысить производительность и надежность приложений и системы в целом, сделать работу пользователя более комфортной, а также несколько упростить логику программы, производя естественное разделение обязанностей между потоками. Настоящий программист под Windows должен знать и уметь использовать преимущества операционной системы, одним из которых как раз и является вытесняющая многозадачность.

Необходимость синхронизации

Если вы помните, в Windows выполняются не процессы, а потоки. При создании процесса автоматически создается его основной поток. Этот поток в процессе выполнения может создавать новые потоки, которые, в свою очередь, тоже могут создавать потоки и т.д. Процессорное время распределяется именно между потоками, и получается, что каждый поток работает независимо.

Все потоки, принадлежащие одному процессу, разделяют некоторые общие ресурсы – такие, как адресное пространство оперативной памяти или открытые файлы. Эти ресурсы принадлежат всему процессу, а значит, и каждому его потоку. Следовательно, каждый поток может работать с этими ресурсами без каких-либо ограничений. Но так ли это в действительности? Вспомним, что в Windows реализованам вытесняющая многозадачность – это значит, что в любой момент система может прервать выполнение одного потока и передать управление другому. (Раньше использовался способ организации, называемый кооперативной многозадачностью. Система ждала, пока поток сам не соизволит передать ей управление. Именно поэтому в случае глухого зависания одного приложения приходилось перезагружать компьютер. Так была организована, например, Windows 3.1). Что произойдет, если один поток еще не закончил работать с каким-либо общим ресурсом, а система переключилась на другой поток, использующий тот же ресурс? Произойдет штука очень неприятная, я вам это могу с уверенностью сказать, и результат работы этих потоков может чрезвычайно сильно отличаться от задуманного. Такие конфликты могут возникнуть и между потоками, принадлежащими различным процессам. Всегда, когда два или более потоков используют какой-либо общий ресурс, возникает эта проблема.

Именно поэтому необходим механизм, позволяющий потокам согласовывать свою работу с общими ресурсами. Этот механизм получил название механизма синхронизации потоков (thread synchronization).

Структура механизма синхронизации

Что же представляет собой этот механизм? Это набор объектов операционной системы, которые создаются и управляются программно, являются общими для всех потоков в системе (некоторые – для потоков, принадлежащих одному процессу) и используются для координирования доступа к ресурсам. В качестве ресурсов может выступать все, что может быть общим для двух и более потоков – файл на диске, порт, запись в базе данных, объект GDI, и даже глобальная переменная программы (которая может быть доступна из потоков, принадлежащих одному процессу).

Объектов синхронизации существует несколько, самые важные из них – это взаимоисключение (mutex), критическая секция (critical section), событие (event) и семафор (semaphore). Каждый из этих объектов реализует свой способ синхронизации. Какой из них следует использовать в каждом конкретном случае вы поймете, подробно познакомившись с каждым из этих объектов. Также в качестве объектов синхронизации могут использоваться сами процессы и потоки (когда один поток ждет завершения другого потока или процесса); а также файлы, коммуникационные устройства, консольный ввод и уведомления об изменении (к сожалению, освещение этих объектов синхронизации выходит за рамки данной статьи).

  • Читать дальше
  • 1
  • ...
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: