Using handler OnBegindrag with CTreeCtrl - c++

I have class MyCTreeCtrl and I want to add message handler like:
void MyCTreeCtrl::OnBegindrag(NMHDR *pNMHDR, LRESULT *pResult)
{
}
What should I write between:
BEGIN_MESSAGE_MAP(MyCTreeCtrl, CTreeCtrl)
END_MESSAGE_MAP()
for creating BEGINDRAG handler.
Can't you advice me some literature about message handling in MFC? Thanks.

You should not deal with message map trying to create handlers yourself. For most messages, wizard is going to add the code for you.
For tree control in the dialog for example, you can select tree control in the resource editor and choose Add Event Handler (There are also other ways of inserting message handler using class view and properties). It is unfortunate that MS named it an event handler while in reality it is notification message handler for control specific notification code; in your case it is TVN_BEGINDRAG.
Wizard inserts appropriate entries into a message map:
ON_NOTIFY(TVN_BEGINDRAG, IDC_TREE_DRAG, &CYourDlg::OnTvnBegindragTreeDrag)
Adds declaration in .h file:
afx_msg void OnTvnBegindragTreeDrag(NMHDR *pNMHDR, LRESULT *pResult);
and implementation (definition) on .cpp file:
void CYourDlg::OnTvnBegindragTreeDrag(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
// TODO: Add your control notification handler code here
*pResult = 0;
}
In the nutshell:
Message map is the way MFC was design for the flexibility of inserting message handlers. As for any Win32 application, message handler is called from windows procedure; in MFC it is MFC window procedure that all controls are subclassed with.
The message map is the static array of AFX_MSGMAP_ENTRY structures:
struct AFX_MSGMAP_ENTRY
{
UINT nMessage; // windows message
UINT nCode; // control code or WM_NOTIFY code
UINT nID; // control ID (or 0 for windows messages)
UINT nLastID; // used for entries specifying a range of control id's
UINT_PTR nSig; // signature type (action) or pointer to message #
AFX_PMSG pfn; // routine to call (or special value)
};
MFC window procedure gets this map, search for an entry for specific signature (nSig) and if signature of the entry matches, calls appropriate function (pfn).
Each message entry in the map uses specific macro that expands to this structure.
In your case it is ON_NOTIFY, since message is MW_NOTIFY. You will also notice the notification code TVN_BEGINDRAG.
In case you want to create message entry for a message that is not in the wizard database, or for custom message, you have couple of choices, ON_MESSAGE you can use in following manner:
Macro goes into a message map and declaration and definition that go into header and cpp files.
ON_MESSAGE(WM_CUSTOM_MESSAGE, OnCustomMessage)
LRESULT CTreeCtrlDragSampleDlg::OnCustomMessage(WPARAM wParam, LPARAM lParam)
{
return 0;
}
afx_msg LRESULT OnCustomMessage(WPARAM wParam, LPARAM lParam);
Other choices: ON_COMMAND, ON_CONTROL that map WM_COMMAND messages from window or windows common control.
More info:
http://msdn.microsoft.com/en-us/library/6d1asasd(v=vs.100).aspx for VS 2010

Related

Is there a solution for this case?

This is a Windows Desktop Application project created by Visual Studio.
I have a Dialog resource created from the Resource View that has a Static Text.
I'm using this dialog in order to show errors to the user:
DialogBox(hInst, MAKEINTRESOURCE(IDD_MY_MESSAGE_BOX), hWnd, MyMessageBoxProc);
The reason I'm using a DialogBox is that I need it to stop the code execution, because the next line of code will close the application I mean the user should be aware of the error message before application exits. I know a way to change the Static Text:
HWND myMessageBox = CreateDialog(hInst, MAKEINTRESOURCE(IDD_MY_MESSAGE_BOX), nullptr, MyMessageBoxProc);
HWND staticText = GetDlgItem(myMessageBox, IDC_STATIC);
SetWindowText(staticText, L"Text changed.");
But that approach doesn't stop code execution.
Since it's a Windows Desktop Application project I cannot create MFC classes and try the following approach:
// Find the Static Text.
// If called from within MyMessageBox class.
CWnd *staticText = GetDlgItem(IDC_STATIC);
staticText->SetWindowText("Text changed.");
// If called from elsewhere.
MyMessageBox myMessageBox;
CWnd *staticText = myMessageBox.GetDlgItem(IDC_STATIC);
staticText->SetWindowText("Text changed.");
So what would be a workaround in order to change the Static Text using a DialogBox without the need of MFC classes or even another approach that allows me to change the Static Text and still stop code execution like a DialogBox.
Just change the text in your window procedure (MyMessageBoxProc) by handling WM_INITDIALOG message. If you wish to supply the text to the dialog, then create it using DialogBoxParam instead, which is then accessible via the lParam parameter.
e.g.
INT_PTR MyMessageBoxProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_INITDIALOG) {
HWND hCtrl = GetDlgItem(hWnd, IDC_STATIC);
SetWindowText(hCtrl, reinterpret_cast<LPCTSTR>(lParam));
}
return FALSE;
}
The creation would be something like:
LPCTSTR text = _T("Text changed.");
DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_MY_MESSAGE_BOX), hWnd, MyMessageBoxProc,
reinterpret_cast<LPARAM>(text));
Note that there is a standard message box that ships with windows, which you may want to use instead of writing your own. That's available via the function MessageBox

GUI with c++. lagged when i use button

am new in C++ GUI, am modifying a code sent with a machine to me, i want to make a while loop when i click button, i tried the thread and it is still stuck.
void CDlgWriteEPC::loop()
{
// Do something
}
void CDlgWriteEPC::OnBnClickedOk()
{
std::thread loadingThread(&CDlgWriteEPC::loop, this);
loadingThread.join();
}
join blocks the current thread until the other thread is done, so that's no help.
You should start the worker thread, return immediately and the worker thread
should send some kind of message when it's done.
The function names in your example code seem to look like it's from a MSVC++ MFC
application so we'll work with that.
Simply put, windows GUI applications are event driven, each time a event happens a
WM_MESSAGE is sent. The framework receives these messages and calls the appropriate
functions to handle it. We can define our own messages and message handlers.
This way the worker thread can send such messages to the framework and it will call
our handler function.
WM_APP is defined as a starting point for private user messages, so there won't be
any conflict with already existing system messages.
(https://msdn.microsoft.com/en-us/library/windows/desktop/ms644930%28v=vs.85%29.aspx)
So, imagine we are building a MFC dialog application that searches something in a file.
If the file is big it can take a long time and to prevent blocking the main thread and
getting a 'window is not responding' message we need to do this in a worker thread. We might
also want a progress bar for example.
First, we define our own messages inside our existing dialog class starting from WM_APP + 1
and we add our handler functions, these must be of the following type:
afx_msg LRESULT (CWnd::*)(WPARAM, LPARAM)
WPARAM and LPARAM are parameters passed when posting the message, you can use them to send
custom data. In our example we can use them to send the % progress for our progress bar.
(https://msdn.microsoft.com/en-us/library/k35k2bfs.aspx)
class CMyAppDlg : public CDialogEx
{
public:
//Public so the worker thread class can use these same sames when posting a message.
enum Messages
{
MSG_ThreadProgress = WM_APP + 1,
MSG_ThreadDone
};
private:
afx_msg LRESULT OnThreadProgress(WPARAM wParam, LPARAM lParam)
{
ProgressBar->SetPos(wParam); //Worker thread posts progress as wParam
};
afx_msg LRESULT OnThreadDone(WPARAM wParam, LPARAM lParam)
{
//Get result from worker thread class and use it...
};
};
Then we need to add our messages and handlers to the message map, you should add them to the already
existing message map in the .cpp file for the dialog/document.
BEGIN_MESSAGE_MAP(CMyAppDlg, CDialogEx)
ON_MESSAGE(MSG_ThreadProgress, &CMyAppDlg::OnThreadProgress)
ON_MESSAGE(MSG_ThreadDone, &CMyAppDlg::OnThreadDone)
END_MESSAGE_MAP()
Now we can simply post these messages in our worker thread and the framework main thread will handle
the messages and update the progress bar or use the result:
class ThreadClass
{
public:
//Constructor takes a reference to our dialog class because we need the window handle
//to post a message
ThreadClass(CMyAppDlg& MyAppDlg) : mMyAppDlg(MyAppDlg) {};
void operator()() //Thread worker code...
{
while (what_we_look_for_not_found)
{
int Progress = 0;
//Search for a while and update progress variable...
//Post message to dialog asking it to update the progressbar
PostMessage(mMyAppDlg.m_hWnd, CMyAppDlg::MSG_ThreadProgress, Progress, 0);
}
//Finished searching...
StoreResult();
//Post message to dialog informing it thread is done and result can be retrieved.
PostMessage(mMyAppDlg.m_hWnd, CMyAppDlg::MSG_ThreadDone, 0, 0);
}
private:
CMyAppDlg& mMyAppDlg;
};
QT uses a similar system with SIGNAL and SLOT and other frameworks surely have their own equivalent system.
You should be able to find more information in the manuals if you are using something else then MSVC++ MFC.

Retrieve WTL object from handle

I had to rewrite a custom file dialog (derived from MFC's CFileDialog) to WTL's CFileDialog. I have a bit of a problem to retrieve data when I don't have access to the dialog object itself. Imagine the following.
I have a member in the class
static WNDPROC m_wndProc;
I initialize it in the following static member fnct.
void CMyFileDialog::OnInitDone(LPOFNOTIFY lpon)
{
m_wndProc = (WNDPROC)::SetWindowLong(thisHWND, GWL_WNDPROC, reinterpret_cast<long>
(&CMyFileDialog::WndProcSelect));
}
The handle comes into the callback method with no problem and I can "connect" to it with CWindow
LRESULT CALLBACK CMyFileDialog::WndProcSelect(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// ...
CWindow callerWnd(hwnd);
}
And here, I don't know the real methodology to convert the CWindow to my CMyFileDialog. As I think, this CWindow class is just connected somehow to the handle itself, but does not the same object as it was created before. So for example, if I have a CString or other members in my CMyFileDialog, it won't access its state, because it was created in another object.
I think you are doing something wrong here. You have access to the message map without having to modify the WndProc (that is something that the CFileDialogImpl will have already done).
See for example http://www.codeproject.com/Articles/12999/WTL-for-MFC-Programmers-Part-IX-GDI-Classes-Common#usingcfiledialog, where they simply
BEGIN_MSG_MAP(CMyFileDialog)
CHAIN_MSG_MAP(CFileDialogImpl<CMyFileDialog>)
END_MSG_MAP()
You could always use SetWindowLongPtr with your "this" pointer, then it would be fairly easy to extract the pointer to your CMyFileDialog.

How do I use Dialog resources in Win32?

Without resources I can create my UI with a complex array of CreateWindow() and CreateWindowEx(), and WndProc() to process my events.
I noticed if I right-click in the resource view and click "add resource", I can draw a dialog box with all the controls. This would save me a huge amount of time if I could draw the interface like I normally do with C#.
After I've drawn the interface with the resource editor, how do I then create the window from code? Can someone provide a very simple example with a button, and show how to handle a WM_COMMAND event on that button please?
Also, is this generally how people create the GUI? Is there any loss in flexible to do this way? Even in C# I often have to supplement designer-generated UI with my own code-generated UI, but the majority of the time I'm quite happy to use designer.
After creating the dialog in the resource editor, call CreateDialog(modeless dialog;you need to dispatch the messages manually just like when you use CreateWindow) or DialogBox(modal dialog; the function does not return until you close the dialog. it does the dispatching for you) to make the dialog show up. Just like you pass in the window proc to RegisterClass, you pass the dialog proc to those functions for the dialog call back. An example of DialogProc looks likes this:
BOOL DialogProc( HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam ){
switch( iMessage ){
case WM_COMMAND:
switch( LOWORD( wParam ) ){
case BTOK:
MessageBox( hDlg, "Hello, World!", NULL, NULL );
return TRUE;
break;
}
break;
}
return FALSE;
}
This is a basic way of creating a dialog. More sophisticated method would normally involve OOP, usually wrapping each resource( button, window, etc) as a C++ object or using MFC.
If you have placed your button or any control on some dialog, that control is already in created state. For handling the messages of these child controls on this dialog , you have to override OnCommand Method in the class which is implementing your dialog.
For Example:
//CDialog_ControlDlg is my Dialog class derived from CDialog
//IDC_BUTTON_SAMPLE is the ID of the button which was palced on the dialog in the resource Editor..
BOOL CDialog_ControlDlg::OnCommand(WPARAM wParam,LPARAM lparam){
int iNotiFicationMsg=HIWORD(wParam);//This is thenotification Msg from the child control
int iCommandId=LOWORD(wParam);//And Control ID of the Child control which caused that Msg
BOOL result=FALSE;
switch(iCommandId){
case IDC_BUTTON_SAMPLE:
if(iNotiFicationMsg==BN_CLICKED)
{
//Your Code for handling this type of Msg for this control..
}
break;
default:
{
//Specific Code;
}
return result;
}
}

Message map macros

When do you use ON_COMMAND and when do we use ON_MESSAGE. What are the differences between them.
ON_COMMAND is specifically used to handle a command message (i.e. WM_COMMAND) like the click of a button/menu item/toolbar button.
ON_MESSAGE is more generic and can be used for any windows message. It is usually used for less frequently handled messages for which specific message map macros have not been provided. You can use ON_MESSAGE to handle ON_COMMAND messages as well but you will have to extract message information (i.e. command ID) yourself.
Example:
See here:
http://msdn.microsoft.com/en-us/library/k35k2bfs(VS.80).aspx
http://msdn.microsoft.com/en-us/library/ms647591(VS.85).aspx
In the message map:
ON_MESSAGE( WM_COMMAND, OnMyCommand )
The handler:
LRESULT CMyWnd::OnMyCommand( WPARAM wParam, LPARAM lParam )
{
// ... Handle message here
int commandId = LOWORD(wParam);
switch(commandId){
case ID_HELLOCOMMAND:
MessageBox(0, "Hello there!", "ID_HELLO_COMMAND", MB_OK);
break;
// ... other commands here
}
return 0L;
}
Disclaimer: Owing to MFC's message pump mechanism, you may have to do a bit more than what's shown above. The best man to ask: Jeff Prosise