Windows API animated window controls - windows

Lets say I have a window with 2 dialogs, each having its own set of controls/information.
One is displayed on the window and the other is hidden, and I have a button switching between them.
How would I animate the transition between the 2 dialogs, like having it slide back and forth?
Note: I'm trying to use only the windows api for this.

Hans is correct, you can use the Windows API AnimateWindow.
AnimateWindow Function
here an example:
int CALLBACK EventDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
AnimateWindow(hwndDlg, 100, AW_SLIDE | AW_HOR_POSITIVE);
return 1;
}
case WM_PAINT:
{
return 1;
}
}
return 0;
}

Related

How to detect mouse hovering in a non-client section of a window?

I have a program that paints to the client area about 60hz using Direct3D 9, and the mouse is interfering, so I want to get rid of it only when it moves across the client area.
I thought that calling ShowCursor(false) in WM_MOUSEMOVE and calling ShowCursor(true) when WM_NCMOUSEMOVE is called by the system would work, but it results in a poor behavior.
So I found that TrackMouseEvent() would make the job, but I'm calling it in the following way:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static bool g_fMouseTracking = false;
switch (message)
{
case WM_MOUSEMOVE:
if (!g_fMouseTracking)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.dwFlags = TME_NONCLIENT;
tme.dwHoverTime = HOVER_DEFAULT;
tme.hwndTrack = hWnd;
g_fMouseTracking = TrackMouseEvent(&tme);
}
break;
case WM_NCMOUSEHOVER:
ShowCursor(true);
break;
...
and WM_NCMOUSEHOVER is never called. I don't know why.
Anyway, this is only one piece of code, to do what I want I know I need more code, but if it's not calling WM_NCMOUSEMOVE I can't start doing more advanced mouse hovering tricks.
When you want to track WM_NCMOUSEHOVER you must use TrackMouseEvent in WM_NCMOUSEMOVE.

HideCaret() has no effect on Windows XP (x64)

I'm trying to hide caret on my read-only EDIT control. On Windows 10 (x64) caret is hiding and everything works OK. But on Windows XP (x64) caret is still visible. What I did wrong?
BOOL OnCommand(HWND hWnd, INT ID, HWND hWndCtl, UINT codeNotify) {
switch (ID) {
case IDC_EDIT1:
switch (codeNotify) {
case EN_SETFOCUS:
HideCaret(hWndCtl);
break;
}
break;
}
return FALSE;
}
BOOL CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_COMMAND:
return OnCommand(hWnd, (INT)LOWORD(wParam), (HWND)lParam, (UINT)HIWORD(wParam));
}
return FALSE;
}
Much easier.
Don't give the edit control the focus. You may remove the WS_TABSTOP style.
Don't use an Edit control at all and use a static control. This also has never a Caret.
Why do you use a Edit control and want to hide the caret.
Seams to be an X-Y question.

How to cancel item label editing in Tree-View control upon ESC keydown in WinAPI

I have a dialog box with a Tree-View control where the user can edit the item labels. I want the user to be able to cancel the label edit by pressing ESC key.
The problem is that pressing ESC closes the dialog window immediately.
I have tried getting the handle to the EditBox control by a TreeView_GetEditControl() call upon TVN_BEGINLABELEDIT message and subclassing it to trap the ESC key, but when I do that, typing in edit box becomes impossible.
What is the problem?
Here is the relevant code:
INT_PTR CALLBACK DlgProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam) {
switch(message) {
//...
case WM_NOTIFY:
{
LPNMHDR pNmHdr = (LPNMHDR)lParam;
switch(pNmHdr->code) {
case TVN_BEGINLABELEDIT:
{
HWND hwndTV = (HWND)GetWindowLongPtr(hWnd, GWLP_USERDATA); // stored handle to Tree-View ctl
HWND hWndEditBox = TreeView_GetEditControl(hwndTV);
// subclass edit box
TreeViewGlobals::g_wpOrigEditBoxProc =
(WNDPROC)SetWindowLongPtr(hWndEditBox,
GWLP_WNDPROC, (LONG_PTR)EditBoxCtl_SubclassProc);
break;
}
case TVN_ENDLABELEDIT:
{
SetWindowLongPtr(hWnd, DWLP_MSGRESULT, (LONG)TRUE); // accept edit
return TRUE;
}
default:
break;
}
}
default:
break;
}
return FALSE;
}
INT_PTR CALLBACK EditBoxCtl_SubclassProc(HWND hWndEditBox, UINT message,
WPARAM wParam, LPARAM lParam) {
switch(message) {
HANDLE_MSG(hWndEditBox, WM_GETDLGCODE, EditBoxCtl_OnGetDlgCode);
HANDLE_MSG(hWndEditBox, WM_KEYDOWN, EditBoxCtl_OnKey); // does not receive WM_KEYDOWN for ESC unless I handle WM_GETDLGCODE above
default:
break;
}
return CallWindowProc(TreeViewGlobals::g_wpOrigEditBoxProc,
hWndEditBox, message, wParam, lParam);
}
UINT EditBoxCtl_OnGetDlgCode(HWND hWndEditBox, LPMSG lpmsg) {
if(lpmsg) {
if(lpmsg->message == WM_KEYDOWN && lpmsg->wParam == VK_ESCAPE) {
return DLGC_WANTMESSAGE;
}
}
return 0;
}
void EditBoxCtl_OnKey(HWND hWndEditBox, UINT vk, BOOL fDown,
int cRepeat, UINT flags) {
switch(vk) {
case VK_ESCAPE:
Beep(4000, 150); // never beeps
break;
default:
break;
}
}
P.S. I noticed that when I remove WM_GETDLGCODE handler in EditBoxCtl_SubclassProc(), it becomes possible to type in the edit box again, but then I can't trap WM_KEYDOWN for ESC key from that procedure.
Below is the solution that I found. The trick seems to be calling the original control proc with WM_GETDLGCODE intercepted in subclass proc, storing the return value and then returning it with DLGC_WANTALLKEYS or DLGC_WANTMESSAGE flag set to prevent system from further processing the keystroke.
The upside to this approach is that pressing ESC cancels editing and reverts the item label to its original text, and pressing ENTER while editing no longer just closes the dialog(which was another problem) without any additional code to handle those cases.
Here is the code that works:
INT_PTR CALLBACK EditBoxCtl_SubclassProc(HWND hWndEditBox, UINT message,
WPARAM wParam, LPARAM lParam) {
switch(message) {
//HANDLE_MSG(hWndEditBox, WM_GETDLGCODE, EditBoxCtl_OnGetDlgCode); // can't use this: need wParam and lParam for CallWindowProc()
case WM_GETDLGCODE: {
INT_PTR ret = CallWindowProc(TreeViewGlobals::g_wpOrigEditBoxProc,
hWndEditBox, message, wParam, lParam);
MSG* lpmsg = (MSG*)lParam;
if(lpmsg) {
if(lpmsg->message == WM_KEYDOWN &&
(lpmsg->wParam == VK_ESCAPE || lpmsg->wParam == VK_RETURN) )
{
return ret | DLGC_WANTALLKEYS;
}
}
return ret;
}
default:
break;
}
return CallWindowProc(TreeViewGlobals::g_wpOrigEditBoxProc,
hWndEditBox, message, wParam, lParam);
}
The problem is that the modal dialog has its own message loop and its own translation with IsDialogMessage. Using the MFC I would say, just use PreTranslateMessage but this isn't available in plain WinApi. You don't have access to the internal message loop and the keyboard interface.
So the Escape key is handled inside the message loop. And causes a WM_COMMAND message with IDCANCEL to be sent. (See the MSDN specs about dialogs)
Maybe the easiest way is to interrcept the WM_COMMAND message sent to the dialog, check if who has the focus and if the inplace edit control has the focus you just set the focus back to the tree control and eat forget the IDCANCEL and don't close the dialog.
you need remember the tree-view hwnd when you receive TVN_BEGINLABELEDIT (in class member, associated with dialog) and zero it when you receive TVN_ENDLABELEDIT. when user press esc or enter in modal dialog box - you receive WM_COMMAND with IDCANCEL (on esc) or IDOK( on enter). you need check saved tree-view hwnd and if it not 0 - call TreeView_EndEditLabelNow
switch (uMsg)
{
case WM_INITDIALOG:
m_hwndTV = 0;
break;
case WM_NOTIFY:
switch (reinterpret_cast<NMHDR*>(lParam)->code)
{
case TVN_BEGINLABELEDIT:
m_hwndTV = reinterpret_cast<NMHDR*>(lParam)->hwndFrom;
return TRUE;
case TVN_ENDLABELEDIT:
m_hwndTV = 0;
//set the item's label to the edited text
SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, TRUE);
return TRUE;
}
break;
case WM_CLOSE:
EndDialog(hwndDlg, 0);
break;
case WM_COMMAND:
switch (wParam)
{
case IDCANCEL:
if (m_hwndTV)
{
TreeView_EndEditLabelNow(m_hwndTV, TRUE);
}
else
{
EndDialog(hwndDlg, IDCANCEL);
}
break;
case IDOK:
if (m_hwndTV)
{
TreeView_EndEditLabelNow(m_hwndTV, FALSE);
}
else
{
EndDialog(hwndDlg, IDOK);
}
break;
}
break;
}

Hot tracking list item selection in a combo box

I have a combo box and I need to intercept the changement of the selection while the user changes the selection by just hovering with the mouse without clicking. This is for displaying complementary information about the item the user is hovering over.
CBN_SELCHANGE won't do the job, because this message gets fired only when the user has actually changed the selection by clicking on one of the combo box items or when the up/down keys are pressed.
Apparently no message is fired while the user is just hovering over the the combobox.
Illustration
E.g: I need to know when the user moves the mouse from the entry 2 to the entry 33.
This is c++ subclass based on c# article which you mentioned:
LRESULT CALLBACK ComboProc(HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam, UINT_PTR uIdSubClass, DWORD_PTR)
{
if (msg == WM_CTLCOLORLISTBOX)
{
COMBOBOXINFO ci = { sizeof(COMBOBOXINFO) };
GetComboBoxInfo(hwnd, &ci);
if (HWND(lParam) == ci.hwndList)
{
int pos = SendMessage(ci.hwndList, LB_GETCURSEL, 0, 0);
OutputDebugStringA(std::to_string(pos).c_str());
OutputDebugStringA("\n");
}
}
if (msg == WM_NCDESTROY)
{
RemoveWindowSubclass(hwnd, ComboProc, uIdSubClass);
}
return DefSubclassProc(hwnd, msg, wParam, lParam);
}
...
SetWindowSubclass(hComboBox, ComboProc, 0, 0);
This was tested on Windows 10.
This can only report the hover selection in drop down list, it can't change the selection.

How to set the text on the "save" button in Windows' file dialog?

I'm trying to set the text on the "save" button of the Windows "Save file as..." dialog.
I've set up the hook, received the message, found the button (nb. If I call "GetWindowText()" I see "&Save" so I know it's the right button).
Next I changed the text using "SetWindowText()" (and called "GetWindowText()" to check it - the text is correct).
But ... the button still says "Save".
I can change the "Cancel" button using the exact same code - no problem. What's so special about the "Save" button? How can I change it.
Code (for what it's worth):
static UINT_PTR CALLBACK myHook(HWND hwnd, UINT msg, WPARAM, LPARAM)
{
if (msg == WM_INITDIALOG) {
wchar_t temp[100];
HWND h = GetDlgItem(GetParent(hwnd),IDOK);
GetWindowTextW(h,temp,100); // temp=="&Save"
SetWindowTextW(h,L"Testing");
GetWindowTextW(h,temp,100); // temp=="Testing"
}
}
I finally made it work....
I'm pretty sure there's something funny going on with the "Save" button but this code will wrestle it into submission:
// I replace the dialog's WindowProc with this
static WNDPROC oldProc = NULL;
static BOOL CALLBACK buttonSetter(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// Set the button text on every window redraw....
if (msg == WM_ERASEBKGND) {
SetDlgItemTextW(hwnd,IDOK,L"OK");
}
return oldProc(hwnd, msg, wParam, lParam);
};
// This is the callback for the GetWriteName hook
static UINT_PTR CALLBACK GWNcallback(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HWND dlg = GetParent(hwnd);
if (msg == WM_INITDIALOG) {
oldProc = (WNDPROC)GetWindowLongPtr(dlg, GWL_WNDPROC);
if (oldProc !=0) {
SetWindowLongPtr(dlg, GWL_WNDPROC, (LONG)buttonSetter);
}
}
// We need extra redraws to make our text appear...
InvalidateRect(dlg,0,1);
}
You probably need to redraw the window after setting the text.
Try calling UpdateWindow() after setting the text.
Use CDM_SETCONTROLTEXT message to set the text rather than mess with SetWindowText directly, i.e.
SendMessage(hwnd, CDM_SETCONTROLTEXT, IDOK, L"Testing");
http://msdn.microsoft.com/en-us/library/ms646960(VS.85).aspx has more on customizing open/save dialogs

Resources