KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программирование » Роджер Джек - Исчерпывающее руководство по написанию всплывающих подсказок

Роджер Джек - Исчерпывающее руководство по написанию всплывающих подсказок

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Роджер Джек, "Исчерпывающее руководство по написанию всплывающих подсказок" бесплатно, без регистрации.
Перейти на страницу:

 //{{AFX_MSG_MAP(CODListBox)

 // NOTE – the ClassWizard will add and remove mapping macros here.

 //}}AFX_MSG_MAP

END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////

// CODListBox message handlers

void CODListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) {

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

 ASSERT_VALID(pDC);

 int nSavedDC = pDC->SaveDC();

 CString strItem;

 if (lpDrawItemStruct->itemID != –1) {

  GetText(lpDrawItemStruct->itemID, strItem);

 }

 COLORREF TextColor;

 COLORREF BackColor;

 UINT nItemState = lpDrawItemStruct->itemState;

 if (nItemState & ODS_SELECTED) {

  TextColor = RGB(255, 255, 255); // Белый

  BackColor = RGB(255, 0, 0); // Красный

 } else {

  TextColor = RGB(255, 0, 0); // Красный

  BackColor = RGB(255, 255, 255); // Белый

 }

 CRect ItemRect(lpDrawItemStruct->rcItem);

 // Нарисовать фон

 pDC->FillSolidRect(ItemRect, BackColor);

 // Нарисовать текст

 pDC->SetTextColor(TextColor);

 pDC->SetBkMode(TRANSPARENT);

 pDC->SelectObject(&m_Font);

 ItemRect.left += m_nEdgeSpace;

 pDC->DrawText(strItem, ItemRect, DT_LEFT | DT_SINGLELINE | DT_VCENTER);

 ItemRect.left –= m_nEdgeSpace;

 // Нарисовать по необходимости рамку фокуса

 if (nItemState & ODS_FOCUS) {

  pDC->DrawFocusRect(ItemRect);

 }

 pDC->RestoreDC(nSavedDC);

}


void CODListBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) {

 lpMeasureItemStruct->itemHeight = m_nFontHeight + (m_nEdgeSpace * 2);

}

CODListBox::GetIdealItemRect перекрывает такой же метод в классе CTitleTipListBox. Как вы видите, его реализация похожа на реализацию метода в базовом классе, за исключением того, что новый метод использует для шрифта переменную m_Font. Конечно, я мог бы добиться результата и без переопределения метода базового класса, если бы воспользовался CWnd::SetFont для установки шрифта для списка. Однако я хотел показать, как нужно перекрывать этот метод в других случаях. Например, вам придется переопределить CTitleTipListBox::GetIdealItemRect, если вы захотите показывать в списке картинки.

CODListBox::DrawItem рисует строку по информации из структуры DrawItemStruct. Этот код аналогичен коду в функции CTitleTip::OnPaint, за исключением того, что вместо цветов по умолчанию используются красный и белый цвета. Помните, что этот метод может вызываться из класса CTitleTip для рисования внутри его окна.

CODListBox::MeasureItem вычисляет высоту строки на основе шрифта и заданного пустого пространства вокруг текста. Этот метод вызывается Windows только один раз, потому что у этого элемента "список" установлен стиль LBS_OWNERDRAWFIXED. В случае со стилем LBS_OWNERDRAWVARIABLE метод будет вызываться для каждой строки.

В диалоге CTTDemoDlg присутствуют оба рассмотренных элемента "список", и большая часть кода была сгенерирована AppWizard'ом (см. рис.14). Я добавил в класс переменные m_RegListBox и m_ODListBox для обычного списка и списка с пользовательской отрисовкой, соответственно. Еще я добавил код в функцию CTTDemoDlg::OnInitDialog, где производится сабклассинг обоих элементов "список" вызовом CWnd::SubclassWindow. Я загружаю оба списка из статического массива pszItemArray.

Рис.14. CTTDemoDlg

// TTDemoDlg.h : header file /////////////////////////////////////////////////////////////////////////////

// CTTDemoDlg dialog


#include "TitleTipListBox.h"

#include "ODListBox.h"

class CTTDemoDlg : public CDialog { // Construction public:

 CTTDemoDlg(CWnd* pParent = NULL); // standard constructor

// Dialog Data

 //{{AFX_DATA(CTTDemoDlg)

 enum { IDD = IDD_TTDEMO_DIALOG };

 // NOTE: the ClassWizard will add data members here

 //}}AFX_DATA

 // ClassWizard generated virtual function overrides

 //{{AFX_VIRTUAL(CTTDemoDlg)

protected:

 virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support

 //}}AFX_VIRTUAL

 // Implementation

protected:

 HICON m_hIcon;

 CTitleTipListBox m_RegListBox; // Обычный список

 CODListBox m_ODListBox; // Список с пользовательской отрисовкой

 // Generated message map functions

 //{{AFX_MSG(CTTDemoDlg)

 virtual BOOL OnInitDialog();

 afx_msg void OnPaint();

 afx_msg HCURSOR OnQueryDragIcon();

 //}}AFX_MSG

 DECLARE_MESSAGE_MAP()

};


// TTDemoDlg.cpp : implementation file

#include "stdafx.h"

#include "TTDemo.h"

#include "TTDemoDlg.h"


#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif


/////////////////////////////////////////////////////////////////////////////

// CTTDemoDlg dialog

CTTDemoDlg::CTTDemoDlg(CWnd* pParent /*=NULL*/) : CDialog(CTTDemoDlg::IDD, pParent) {

 //{{AFX_DATA_INIT(CTTDemoDlg)

 // NOTE: the ClassWizard will add member initialization here

 //}}AFX_DATA_INIT

 // Note that LoadIcon does not require a subsequent DestroyIcon in Win32

 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

}


void CTTDemoDlg::DoDataExchange(CDataExchange* pDX) {

 CDialog::DoDataExchange(pDX);

 //{{AFX_DATA_MAP(CTTDemoDlg)

 // NOTE: the ClassWizard will add DDX and DDV calls here

 //}}AFX_DATA_MAP

}


BEGIN_MESSAGE_MAP(CTTDemoDlg, CDialog)

 //{{AFX_MSG_MAP(CTTDemoDlg)

 ON_WM_PAINT()

 ON_WM_QUERYDRAGICON()

 //}}AFX_MSG_MAP

END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////

// CTTDemoDlg message handlers

BOOL CTTDemoDlg::OnInitDialog() {

 CDialog::OnInitDialog();

 // Set the icon for this dialog. The framework does this automatically

 // when the application's main window is not a dialog

 SetIcon(m_hIcon, TRUE); // Set big icon

 SetIcon(m_hIcon, FALSE); // Set small icon

 // Сабклассинг обычного элемента "список"

 HWND hwndRegListBox = ::GetDlgItem(GetSafeHwnd(), IDC_REGLISTBOX);

 ASSERT(hwndRegListBox);

 VERIFY(m_RegListBox.SubclassWindow(hwndRegListBox));

 // Сабклассинг списка с пользовательской отрисовкой

 HWND hwndODListBox = ::GetDlgItem(GetSafeHwnd(), IDC_ODLISTBOX);

 ASSERT(hwndODListBox);

 VERIFY(m_ODListBox.SubclassWindow(hwndODListBox));

 // Заполнение обоих списков строками

 static char* pszItemArray[] = {

  "The C++ Programming Language",

  "C++ Primer",

  "OLE Controls Inside Out",

  "Inside OLE 2nd Edition",

  "Inside ODBC",

  "Code Complete",

  "Rapid Software Development",

  "The Design Of Everyday Things",

  "Object-Oriented Analysis And Design",

  "MFC Internals",

  "Animation Techniques In Win32",

  "Inside Visual C++",

  "Writing Solid Code",

  "Learn Java Now"

 };

 static int nItemArrayCount = sizeof(pszItemArray) / sizeof(pszItemArray[0]);

 for (int n = 0; n < nItemArrayCount; n++) {

  VERIFY(m_RegListBox.AddString(pszItemArray[n]) != LB_ERR);

  VERIFY(m_ODListBox.AddString(pszItemArray[n]) != LB_ERR);

 }

 return TRUE; // return TRUE unless you set the focus to a control

}


// If you add a minimize button to your dialog, you will need the code below

// to draw the icon. For MFC applications using the document/view model,

// this is automatically done for you by the framework.

void CTTDemoDlg::OnPaint() {

 if (IsIconic()) {

  CPaintDC dc(this); // device context for painting

  SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

  // Center icon in client rectangle

  int cxIcon = GetSystemMetrics(SM_CXICON);

  int cyIcon = GetSystemMetrics(SM_CYICON);

  CRect rect;

  GetClientRect(&rect);

  int x = (rect.Width() – cxIcon + 1) / 2;

  int y = (rect.Height() – cyIcon + 1) / 2;

  // Draw the icon

  dc.DrawIcon(x, y, m_hIcon);

 } else {

  CDialog::OnPaint();

 }

}


// The system calls this to obtain the cursor to display while the user drags

// the minimized window.

HCURSOR CTTDemoDlg::OnQueryDragIcon() {

 return (HCURSOR) m_hIcon;

}

Заключение

Итак, я дал вам пять советов по использованию подсказок. Надеюсь, они вдохновят вас на более широкое применение подсказок ToolTips, TitleTips и DataTips в ваших программах и Web-страницах. А может быть, вы даже придумаете новый вид подсказок, которым поделитесь со всеми нами!

Автор выражает благодарность Биллу Кинсли и другим из компании AM Communications, Inc.

Добавление задержек к подсказкам

Элемент TitleTip, созданный мной, не реализует возможностей добавления задержки перед показом подсказки, предоставляемых стандартным элементом ToolTip с помощью сообщения TTM_SETDELAYTIME. Я не стал добавлять задержек по примеру Microsoft, которая также не реализовала задержки в своих TitleTip'ах. Однако, в большинстве других видов подсказок эта задержка присутствует, поэтому если вы желаете добавить задержку перед показом ваших самописных подсказок, я объясню, как это сделать.

В общем случае, задержки реализуются через Windows-таймеры. В классе CWnd реализованы две функции, которые относятся к таймерам: CWnd::SetTimer и CWnd::KillTimer. CWnd::SetTimer устанавливает таймер, и принимает в качестве параметров ID таймера, временной интервал в миллисекундах и указатель на функцию, вызываемую по истечению указанного интервала. Если указатель на функцию равен NULL, то таймер использует сообщение WM_TIMER для уведомления окна о наступившем событии. CWnd::KillTimer останавливает таймер, принимая в качестве параметра ID таймера.

Заручившись такой поддержкой, давайте посмотрим, как можно добавить задержки к написанным вами подсказкам. Я покажу, как реализовать эквивалент TTDT_AUTOPOP сообщения TTM_SETDELAYTIME. Сообщение с этим параметром устанавливает время задержки перед скрытием подсказки, если курсор мыши неподвижен.

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*