"Joseph M. Newcomer" <newcomer@flounder.com> wrote in message
I see many things wrong here.
For one thing, this is an MFC group and this is not MFC code.
More, below.
On Wed, 11 Mar 2009 18:34:55 -0700 (PDT), anurag
<yourstrulyanurag@gmail.com> wrote:
I want to display a tooltip that changes as the mouse moves to
different positions in the client area showing the pixel co-ordinates
in the tooltip. So, the tool here is the whole client area. Following
is the code i picked up from MSDN and used "as is" , everything
(messages, mouse tracking) works fine but the problem is that no
tooltips are displayed.
Any help will be greatly appreciated.
Following is the code i'm using:
// code begins
#define _WIN32_WINNT 0x0501
#define WINVER 0x0501
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
int count;
TCHAR str[1000];
****
Global variables make no sense
****
HWND g_hwndTrackingTT;
TOOLINFO g_toolItem;
HINSTANCE g_hInst;
BOOL g_TrackingMouse;
****
None of these should be global
****
LRESULT CALLBACK WindowFunc(HWND,UINT,WPARAM,LPARAM);
HWND CreateTrackingToolTip(int toolID, HWND hDlg, char *pText);
TCHAR szWinName[] = TEXT("MyWin");
int WINAPI WinMain(HINSTANCE hThisInst,HINSTANCE hPrevInst,LPSTR
lpszArgs,int nWinMode)
{
HWND hwnd;
MSG msg;
WNDCLASSEX wcl;
INITCOMMONCONTROLSEX ic;
BOOL ret;
g_hInst = hThisInst;
ic.dwSize = sizeof(INITCOMMONCONTROLSEX);
ic.dwICC = ICC_STANDARD_CLASSES|ICC_BAR_CLASSES;
ret = InitCommonControlsEx(&ic);
wcl.cbSize = sizeof(WNDCLASSEX);
wcl.hInstance = hThisInst;
wcl.lpszClassName = szWinName;
wcl.lpfnWndProc = WindowFunc;
wcl.style = CS_HREDRAW|CS_VREDRAW;
wcl.hIcon = LoadIcon(NULL,IDI_APPLICATION);
wcl.hIconSm = NULL;
wcl.hCursor = LoadCursor(NULL,IDC_ARROW);
wcl.lpszMenuName = NULL;
wcl.cbClsExtra = 0;
wcl.cbWndExtra = 0;
wcl.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
if(!RegisterClassEx(&wcl)) return 0;
hwnd = CreateWindowEx(
WS_EX_WINDOWEDGE,
szWinName,
TEXT("Window Title"),
****
You are using the TEXT macro here (Unicode-compliant) but you are using
the obsolete char
type elsewhere. Why the inconsistency?
****
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
HWND_DESKTOP,
NULL,
hThisInst,
NULL
);
ShowWindow(hwnd,nWinMode);
UpdateWindow(hwnd);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WindowFunc(HWND hwnd,UINT message,WPARAM
wParam,LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
static int cxClient = 0, cyClient = 0, oldX, oldY;
****
THe appearance of a static variable inside a window function is so
horrendously wrong that
it is hard to imagine why anyone would want to use it. This is absolutely
horrible-beyond-belief code.
Why do you think this could possibly make sense? If you have more than
one instance of
the window, you are totally screwed. It is so far beyond
worst-possible-practice that
even looking at it is giving me a headache.
NEVER do this!
****
int newX, newY;
char coords[12];
POINT pt;
****
None of these variables make sense here. Also, you should at least use
the macros in
windowsx.h to create something that looks like it was written by someone
who understands
code structure. This is a horrible example of The Switch Statement From
Hell.
****
switch(message){
case WM_CREATE:
g_hwndTrackingTT = CreateTrackingToolTip(456, hwnd, "");
****
This should not be a global variable. It should be a "local" variable of
the main window
class, stored in a structure accessed via the GWLP_USERDATA field.
I'm not sure where the magical value 456 came from. But it is a random
number, and 0 or 1
would work as well.
****
return 0;
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
****
These cannot be saved or retained across calls; to do so is erroneous
design. If you ever
need the client rectangle, you should call GetClientRect at the point
where you need it,
not do something as silly as a static local variable!
****
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
return 0;
case WM_MOUSELEAVE:
// The mouse pointer has left our window.
// Deactivate the ToolTip.
SendMessage(g_hwndTrackingTT, TTM_TRACKACTIVATE, (WPARAM)
FALSE, (LPARAM)&g_toolItem);
g_TrackingMouse = FALSE;
****
Given the correction below, you will need to hide the tooltip at this
point
ShowWindow(g_hwndTrackingTT, SW_HIDE);
****
return FALSE;
case WM_MOUSEMOVE:
if (!g_TrackingMouse)
// The mouse has just entered the window.
{
// Request notification when the mouse leaves.
TRACKMOUSEEVENT tme = { sizeof(TRACKMOUSEEVENT) };
tme.hwndTrack = hwnd;
tme.dwFlags = TME_LEAVE;
TrackMouseEvent(&tme);
// Activate the ToolTip.
SendMessage(g_hwndTrackingTT, TTM_TRACKACTIVATE,
(WPARAM)TRUE, (LPARAM)&g_toolItem);
****
You have "activated" tracking but you have not actually made the tooltip
visible. I would
suggest at this point that you call
ShowWindow(g_hwndTrackingTT, SW_SHOW);
****
g_TrackingMouse = TRUE;
}
newX = LOWORD(lParam);
newY = HIWORD(lParam);
****
Note also that the use of LOWORD and HIWORD is erroneous. The correct
values are
GET_X_LPARAM and GET_Y_LPARAM. This code will fail if the screen
coordinates go negative,
which they can in a multimonitor system.
****
// Make sure the mouse has actually moved. The presence of the
ToolTip
// causes Windows to send the message continuously.
if ((newX != oldX) || (newY != oldY))
{
oldX = newX;
oldY = newY;
****
These would be variables stored in a structure whose pointer is stored in
the
GWLP_USERDATA field of the tooltip, not static variables of the handler or
global
variables. Of course, if you used MFC, all of this would be trivial.
// Update the text.
sprintf(coords, "%d, %d", newX, newY);
****
The use of the obsolete data type char, the use of a fixed-size stack
structure of tiny
size, the use of the unsafe sprintf function, all represent poor
programming methodology
for modern programming
*****
g_toolItem.lpszText = coords;
SendMessage(g_hwndTrackingTT, TTM_SETTOOLINFO, 0, (LPARAM)
&g_toolItem);
// Position the ToolTip.
// The coordinates are adjusted so that the ToolTip does
not
// overlap the mouse pointer.
pt.x = newX;
pt.y = newY;
ClientToScreen(hwnd, &pt);
SendMessage(g_hwndTrackingTT, TTM_TRACKPOSITION,
0, (LPARAM)MAKELONG(pt.x + 10, pt.y - 20));
}
return FALSE;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
HWND CreateTrackingToolTip(int toolID, HWND hDlg, char *pText)
{
// Create a ToolTip.
HWND hwndTT = CreateWindowEx(WS_EX_TOPMOST,
TOOLTIPS_CLASS, NULL,
WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
hDlg, NULL, g_hInst,NULL);
if (!hwndTT)
{
return NULL;
}
// Set up tool information.
// In this case, the "tool" is the entire parent window.
g_toolItem.cbSize = sizeof(TOOLINFO);
g_toolItem.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;
g_toolItem.hwnd = hDlg;
g_toolItem.hinst = g_hInst;
g_toolItem.lpszText = pText;
g_toolItem.uId = (UINT_PTR)hDlg;
GetClientRect (hDlg, &g_toolItem.rect);
// Associate the ToolTip with the tool window.
SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO)
****
Why is there an LPTOOLINFO cast here? This is unnecessary, since
&g_toolItem is
implicitly an LPTOOLINFO object.
****
&g_toolItem);
return hwndTT;
}
// code ends
Thanks,
--Anurag.
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm