|
I am using CTabCtrl to switch between doc / view views. Works as expected, no problems.
But I need to change the views when the are "switched" to make OpenCV driver to be happy. The following code does do that before the tabs are switched. ( so far there is only one view in each child frame).
So far I have only two views to deal with, but will have more.
Being naturally lazy, I just do not like the CRuntimeClass and follwing if's.
Is there easier / less typing /error prone way to accomplish this?
How about using the document template to get the view pointer?
TRACE("\nvoid CMDITabs::OnSelchanging(NMHDR* pNMHDR, LRESULT* pResult) ");
// select current view - before tab changes
int i = GetCurSel();
if (i >= 0)
{
TCITEM item;
item.mask = TCIF_PARAM;
GetItem(i, &item);
HWND hWnd = HWND(item.lParam);
CWnd *pWnd = FromHandle(hWnd); // child frame
//CWnd *pChild = pWnd->GetWindow(GW_CHILD); // first child
CView *pChild_View = (CView*) pWnd->GetWindow(GW_CHILD); // first child - view
CRuntimeClass * pRuntime = pChild_View->GetRuntimeClass();
if(pRuntime->m_lpszClassName == "CTCC_MDIView_AVI_Process")
{
CTCC_MDIView_AVI_Process *pProcess = (CTCC_MDIView_AVI_Process *) pWnd->GetWindow(GW_CHILD);
if(!pProcess->m_C_OpenCV_Image->C_DisconnectDriver())
{
AfxMessageBox("failed to disconnect driver", MB_ICONSTOP);
TRACE("\nFailed to disconnect driver");
}
else
{
TRACE("\n\nCTCC_MDIView_AVI_Process driver disconnected ");
AfxMessageBox("\nCTCC_MDIView_AVI_Process driver disconnected ");
}
}
if(pRuntime->m_lpszClassName == "CTCC_MDIView_AVI_Preview")
{
CTCC_MDIView_AVI_Preview *pProcess = (CTCC_MDIView_AVI_Preview *) pWnd->GetWindow(GW_CHILD);
if(!pProcess->m_C_OpenCV_Image->C_DisconnectDriver())
{
AfxMessageBox("failed to disconnect driver", MB_ICONSTOP);
TRACE("\nFailed to disconnect driver");
}
else
{
TRACE("\nCTCC_MDIView_AVI_Preview driver disconnected ");
AfxMessageBox("\nCTCC_MDIView_AVI_Preview driver disconnected ");
}
}
|
|
|
|
|
Even without getting rid of the ifs you could cut down on the amount of reporting code by factoring the whole TRACE/AfxMessageBox malarkey into another function.
And as you've got more arrows than Custer's hat in some of those conditionals it might be worth moving some of them into their own functions. And the casts [1]. And the location of the runtime class object. There's at least one line in there you don't need for getting the runtime class as well. If you do that lot the code might not look so ugly, be easier to read AND modify.
As for runtime class... every time you use something like that you're showing up the fact you've got a missing virtual function. Create a common base class to your views, define a pure virtual function in there to do your disconnection schtick, implement the function in your views, call it where you've got the class name checks now and snip, snip Bob's yer aunty - no more runtime class required and an if statement disposed of.
Anyway the point here is simplify your code, look for places where you branch on type and replace them with virtual function calls.
Cheers,
Ash
[1] Generally loads of arrows in one statement and casting means you're missing member functions of some sort. Objects (with some exceptions) shouldn't expose their data to the world.
|
|
|
|
|
I did ask for a different way to do this and you have provided it, thanks.
I'll try your suggestion and use virtual function, since I have newer used it! Sound like a right solution.
I did not particularly ask for simplifying the existing code, it is the way it is , with all the traces and messages, just to help me to make it work. ( It still needs some tweaking outside tab control).
Putting that stuff in functions would not necessary make it function better, just make it readable, as you pointed out. But that is not the reason I asked for opinions.
|
|
|
|
|
Ok, being a grenhorn in MFC inheritance I am stumpped.
How do I get the real class pointer?
The first child pWnd_View points to the base class only, if casted to it ( CView derivative) or same if the returned pointer is just CWnd.
"Standard " GetWindow returns window pointer.
And I do have class derived from base derived from CView.
GetItem(i, &item);
HWND hWnd = HWND(item.lParam);
CWnd *pWnd = FromHandle(hWnd); // child frame
CWnd *pWnd_View = pWnd->GetWindow(GW_CHILD); // first child - view
|
|
|
|
|
At the moment you do your switching on type as:
CView *pChild_View = (CView*) pWnd->GetWindow(GW_CHILD);
CRuntimeClass * pRuntime = pChild_View->GetRuntimeClass();
When you do the GetWindow the pointer you get back is (before you cast it, ugh) a pointer to an ordinary CWnd . You can call any CWnd virtual functions implemented in your class (and CView ) without doing any casting.
Now... What you've got presumably is some sort of inheritance going:
CWnd->CView->YourClasses What I'm suggesting is that you interpose another class between CView and YourClass:-
CWnd->CView->YourBaseClass->YourClasses with a pure virtual function in it called something like:-
virtual void Disconnect()=0; Then you'd implement it in your derived classes. Hack out the bits in the if(runtime class name) blocks and stick them in there.
Now... The next problem is, when you've only got a CWnd pointer (from GetWindow() ). The first option is a C-style cast. Don't do that, it's very 1990s and unsafe in so many ways. Instead use one of two C++ casts. Use static_cast if you're sure that the result from GetWindow is one of your view classes. If it's not it can go horribly wrong and the program will crash messily. However it's really fast - it generally doesn't generate any code for single inheritance. The second choice is dynamic_cast. Use this if the result from GetWindow isn't always an object of one of your view classes. It's slower but writing UI code you won't notice it. In this case I'd say you'd be safe using static_cast as you're creating the views and ought to know what classes they are.
Anyway, having bored you with that lot, how do you replace your if() code with the virtual function calls? It'd go something like:
CWnd *viewWindow = pWnd->GetWindow( GW_CHILD );
YourBaseClass *myBaseView = static_cast<YourBaseClass *>( viewWindow );
myBaseView->Disconnect(); Your'e getting a window pointer, casting it to the base class of your views then calling the virtual function through that pointer.
I'd be tempted to pile that lot in a function - it's three lines of hairy pointer manipulation you probably don't want to leave future coders. However you could always write it in a one liner:
static_cast<YourBaseClass *>( pWnd->GetWindow( GW_CHILD ) )->Disconnect(); but it's a bit of a mouthful. Actually it's not too bad looking at it so maybe use the one liner.
Hope that helps,
Ash
|
|
|
|
|
I understand your point, but if your code had been written:
CRuntimeClass *rtClass = GetChildViewsRuntimeClass( this );
if( rtClass->className == "first view class" )
{
DisconnectFirstViewClassControlThingy( this );
}
else if ( rtClass->className == "second view class" )
{
DisconnectSecondViewClassControlThingy( this );
} Then most C++ programmers would have looked at that and said - "Ah ha, switching on a type field, there's a missing virtual function..." As it was I had to mentally extract the salient points to suggest the change I did.
Basically always write code to be read by other people - they don't know the problem you're trying to solve so making things as easy to read as possible helps them help you.
Cheers,
Ash
PS: And if you ever see any code I write on code project that you think could be clearer, please tell me! I can either explain it better preferably by rewriting it or explaining it better for neophytes that don't know the language or its idioms yet. I'm always trying to learn and only occasionally does the criticism hurt .
|
|
|
|
|
Ash,
many thanks for all your suggestions, I really appreciate it.
It is very helpfull because I am still in the basic of the application and eventually it will be less klugy if I use inheritance.
As far as my silly coding, I always strive to make it work first
and sometime use both TRACE and AfxMessageBox to keep myself fron going crazy finding the "problems".
Many thanks for all your time.
Vaclav
|
|
|
|
|
I found my pure virtual function problem - the base abstract class cannot be instantiated, so IMPLEMENT_DYNCREATE and DECLARE_DYNCREATE pair ( MFC "standard" )need to be deleted.
Working with MFC is fun!
Next problem...
Hello Ash, sorry to bug you , but I told you I am a greenie in using inheritance.
My learning process is not starting well.
I am not sure if it is me or VC 6.0 wizard, but I cannot get the pure virtual function defined using wizard or manually.
Maybe I am missing some setting in compiler commands?
I a have never used virtual options in the wizards.
Here is the compiler error:
Z:\0\0 MDI\V1\TCC_MDIView_Base.cpp(17) : error C2259: 'CTCC_MDIView_Base' : cannot instantiate abstract class due to following members:
z:\0\0 mdi\v1\tcc_mdiview_base.h(13) : see declaration of 'CTCC_MDIView_Base'
Z:\0\0 MDI\V1\TCC_MDIView_Base.cpp(17) : warning C4259: 'void __thiscall CTCC_MDIView_Base::Test(void)' : pure virtual function was not defined
z:\0\0 mdi\v1\tcc_mdiview_base.h(24) : see declaration of 'Test'
Z:\0\0 MDI\V1\TCC_MDIView_Base.cpp(17) : error C2259: 'CTCC_MDIView_Base' : cannot instantiate abstract class due to following members:
z:\0\0 mdi\v1\tcc_mdiview_base.h(13) : see declaration of 'CTCC_MDIView_Base'
Z:\0\0 MDI\V1\TCC_MDIView_Base.cpp(17) : warning C4259: 'void __thiscall CTCC_MDIView_Base::Test(void)' : pure virtual function was not defined
z:\0\0 mdi\v1\tcc_mdiview_base.h(24) : see declaration of 'Test'
Here is the base calls declartion:
virtual void Test() = 0;
The VC++ 6.0 wizard does not generate the definition. I undestand pure virtual does not need it, but the compiler complains about it, twice! I understand I could define it in base class, but even than I get same warnings / errors.
Here is the definition in the derived class and there are no errors from compiler.
void CTCC_MDIView_Base_Preview::Test()
{
}
I also do not get why there are warnings and errors.
Both "problems" should be errors. But that is my opinion.
Again, thanks for your help and time.
Vaclav
-- modified 24-May-12 23:14pm.
|
|
|
|
|
Hi!
Is it possible to deallocate a memory that was allocated by new using free function? Otherwise what will happen if we deallocate using free function while the memory is allocated using new in C++?
|
|
|
|
|
See here[^].
Veni, vidi, vici.
|
|
|
|
|
Thank you Sir .
|
|
|
|
|
You are welcome.
Veni, vidi, vici.
|
|
|
|
|
|
I have a Delphi application which Creates a shared memory uses CreateFileMapping, OpenFileMapping, MapViewOfFile functions.
Now I wanted to share the same memory for my MFC application. I used the OpenFileMapping, MapViewOfFile functions.
I created a structure exactly same in size as the Delphi application and mapped the structure object.
sample code:
HANDLE hMapObject2;
hMapObject2 = OpenFileMapping( FILE_MAP_ALL_ACCESS, FALSE, "PP101U3_SHARED");
if( !hMapObject2 )
{
AfxMessageBox("Failed to open Simpack DataBase");
return( 0 );
}
Simpack = ( struct SIMPACKDB *) MapViewOfFile( hMapObject2, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
if( !Simpack )
{
AfxMessageBox("Failed to create Simpack File Map View");
return(0);
}
Esim->SPV1 = Simpack->SP_Z;
I am able to read the values exactly correct for all the member variables in the structure.
But when I try to write value in the shared memory, its not changing. It shows the previous value immediately.
The value of Simpack->SP_Z[15] is 0.5010 as read
from the shared memory which is set by the Delphi application.
When I set or write the value of the same variable to the shared memory using the code:
Simpack->SP_Z[15] = 0.6123;it still shows the previous value 0.5010. When I change the same variables value in the Delphi application it changes and the changed value can be read here in the MFC application.
Please help me how to write the values in the shared memory. Is there anything wrong in the code?
|
|
|
|
|
manoharbalu wrote: When I set or write the value of the same variable to the shared memory using the code:
Simpack->SP_Z[15] = 0.6123;it still shows the previous value 0.5010.
What does 'it still shows' mean? You checking it in debugger or printing the values.
I suggest you to check whether that process has write permission for that shared memory.
|
|
|
|
|
The previous value 0.5010 is the orginal value of the same variable in the Delphi application. Also it is the value in the MFC application that is got after mapping it to the shared memory using OpenFileMapping and MapFileView functions.
This value is seen in the watch window of the Debugger in the MFC application
|
|
|
|
|
|
Richard MacCutchan wrote: Why have you reposted this question[^]?
Probably because he wasn't able to get an urgentz answer from the first posting.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
Hi all,
I am having a problem. I am having two threads, one thread i doing some work inside a for loop and inside that for loop its making a call for second thread.
My problem is that my first thread should not resume its working untill thread2 finishes it work, and after thread2 has finished its work it should start its working after thread2 was called.
Can i use CEvent for this???
I am not getting how to do it.
Thanks in advance
|
|
|
|
|
Have a look at this[^] for basic usage of event object. You can use the same logic to use CEvent on you own.
You may find this[^] code project article useful too.
|
|
|
|
|
Sounds like a good time to use WaitForSingleObject() in the first thread, waiting for an event or some other object to get notified/released/set in the second thread.
==============================
Nothing to say.
|
|
|
|
|
VCProgrammer wrote: my first thread should not resume its working untill thread2 finishes it work
So why are you using threads? This is serial processing not parallel, so using threads does not provide any advantage.
Programming is work, it isn't finger painting. Luc Pattyn
|
|
|
|
|
VCProgrammer wrote: Can i use CEvent for this???
yes you can! however am agree with richard!
"Opinions are neither right nor wrong. I cannot change your opinion. I can, however, change what influences your opinion." - David Crow Never mind - my own stupidity is the source of every "problem" - Mixture
cheers,
Alok Gupta
VC Forum Q&A :- I/ IV
Support CRY- Child Relief and You
|
|
|
|
|
I have a Delphi application which Creates a shared memory uses CreateFileMapping, OpenFileMapping, MapViewOfFile functions.
Now I wanted to share the same memory for my MFC application. I used the OpenFileMapping, MapViewOfFile functions.
I created a structure exactly same in size as the Delphi application and mapped the structure object.
sample code:
HANDLE hMapObject2;
hMapObject2 = OpenFileMapping( FILE_MAP_ALL_ACCESS, FALSE, "PP101U3_SHARED");
if( !hMapObject2 )
{
AfxMessageBox("Failed to open Simpack DataBase");
return( 0 );
}
Simpack = ( struct SIMPACKDB *) MapViewOfFile( hMapObject2, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
if( !Simpack )
{
AfxMessageBox("Failed to create Simpack File Map View");
return(0);
}
Esim->SPV1 = Simpack->SP_Z;
I am able to read the values exactly correct for all the member variables in the structure.
But when I try to write value in the shared memory, its not changing. It shows the previous value immediately.
The value of Simpack->SP_Z[15] is 0.5010 as read
from the shared memory which is set by the Delphi application.
When I set or write the value of the same variable to the shared memory using the code:
Simpack->SP_Z[15] = 0.6123;it still shows the previous value 0.5010. When I change the same variables value in the Delphi application it changes and the changed value can be read here in the MFC application.
Please help me how to write the values in the shared memory. Is there anything wrong in the code?
|
|
|
|
|
Please put your code between <pre> tags to make it easy to read.
What data type is the Simpack->SP_Z array?
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|