UCanCode
Software focuses on general application software development. We provide complete solution for developers. No matter you want to develop a simple database
workflow application, or an large flow/diagram based system, our product will provide a complete solution for you. Our product had been used by hundreds of top companies around the world!
"100% source code provided! Free you from not daring to use components because of unable to master the key technology of components!"
|
MFC
Example:
Docking CSizingControlBar Windows inside ActiveX
Control with CFrameWnd and SetTimer
|
|
Introduction
A client
recently
ucancode.neted me for
a component
that could
be used in a
Win32
application,
as well as
embedded in
a web page.
My solution
was to
write
an
ActiveX
control
that
I could
embed in a
CDialog
for the
Win32 app
and use the
<OBJECT>
tag in IE to
embed the
control in a
web
page. When
they ucancode.neted
me if I
could do
docking
windows like
in Visual
Studio.
There was
one problem,
though - the
docking
code relied
on having a
CFrameWnd
to dock to.
I made the
assumption
that
CFrameWnd
could only
be a
top-level
window with
a title bar,
but that
turns out
not to be
true.
CFrameWnd
can be
created with
the
WS_CHILD
style,
rather than
WS_OVERLAPPEDWINDOW
(the
default) and
you can make
it a child
of any other
window,
including an
ActiveX
control!
The result
is a control
that allows
you to have
docking
windows,
even inside
Internet
Explorer.
I've
included and
HTML file
called
index.htm
to
illustrate
this, which
you can open
in IE after
building the
control.
Additionally,
I have also
figured out
how to embed
ActiveX
controls
in the
docking
windows
themselves,
so you can
now have
ActiveX
controls
inside
ActiveX
controls,
etc. My
example code
uses the
ActiveMovie
control.
Here�s what
you need to
do:
-
derive
your own
class
from
CFrameWnd
(ie.
CEmbeddedFrame )
-
derive a
class
from the
docking
window
code (I
used
Cristi
Posea�s
CMyBar
as a
basis).
I called
it
CDockingWnd .
-
create a
member
variable
in the
control
of your
frame
class
Collapse
Copy
Code
CEmbeddedFrame m_Frame;
-
call
Create()
on the
frame in
the
OnCreate()
override
of your
control.
Collapse
Copy
Code
int CDockCtrlCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (COleControl::OnCreate(lpCreateStruct) == -1)
return -1;
CRect r( 0, 0, 100, 100 );
if( !m_Frame.Create( NULL, _T("Embedded Frame"),
WS_CHILD | WS_VISIBLE |
WS_CLIPCHILDREN, r,
this,
NULL,
NULL,
NULL ) )
{
TRACE( "**** Creation of embedded frame failed\n" );
return -1;
}
return 0;
}
-
Add
member
variables
to the
frame
for the
client
area
object
and the
docking
window
Collapse
Copy
Code
CEdit m_wndClient;
CDockingWnd m_wndDockingWnd;
-
In
OnCreate()
of the
frame
control,
create
the
docking
window
and any
other
client-area
controls
you
need,
then
dock the
docking
windows
as you
see fit.
Collapse
Copy
Code
int CEmbeddedFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
SetTimer(0, 100, NULL);
m_wndClient.Create( WS_VISIBLE|WS_CHILD,
CRect(0,0,0,0),
this,
AFX_IDW_PANE_FIRST );
m_wndClient.ModifyStyleEx(0, WS_EX_CLIENTEDGE);
if (!m_font.CreateStockObject(DEFAULT_GUI_FONT))
if (!m_font.CreatePointFont(80, "MS Sans Serif"))
return -1;
m_wndClient.SetFont(&m_font);
m_wndClient.SetWindowText(
_T( "This window is a child of the frame." ) );
if (!m_wndDockingWnd.Create(_T("Docking Window"), this,
IDC_DOCKING_WND))
{
TRACE0( "Failed to create Docking Windown" );
return -1; }
m_wndDockingWnd.SetBarStyle(m_wndDockingWnd.GetBarStyle() |
CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);
EnableDocking(CBRS_ALIGN_ANY);
#ifdef _SCB_REPLACE_MINIFRAME
m_pFloatingFrameClass = RUNTIME_CLASS(CSCBMiniDockFrameWnd);
#endif
m_wndDockingWnd.EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndDockingWnd, AFX_IDW_DOCKBAR_LEFT);
return 0;
}
-
In the
OnCreate()
handler
of your
docking
window,
create
the
control(s)
you want
to be
children
of the
docking
window.
My
sample
code
shows
how to
create a
simple
edit
control
or how
to embed
ActiveX
controls
in your
docking
window.
Collapse
Copy
Code
int CDockingWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (baseCDockingWnd::OnCreate(lpCreateStruct) == -1)
return -1;
SetSCBStyle(GetSCBStyle() | SCBS_SHOWEDGES | SCBS_SIZECHILD);
#ifdef _USE_EDIT_CTRL_
if (!m_wndChild.Create( WS_CHILD|WS_VISIBLE|
ES_MULTILINE|ES_WANTRETURN|ES_AUTOVSCROLL,
CRect(0,0,0,0),
this,
IDC_FRAME_EDIT) )
return -1;
m_wndChild.ModifyStyleEx(0, WS_EX_CLIENTEDGE);
if (!m_font.CreateStockObject(DEFAULT_GUI_FONT))
if (!m_font.CreatePointFont(80, "MS Sans Serif"))
return -1;
m_wndChild.SetFont(&m_font);
m_wndChild.SetWindowText(
_T( "This docking window is embedded in the control" ) );
#else
AfxEnableControlContainer();
if( !m_AMControl.CreateControl( _T("AMOVIE.ActiveMovie Control.2"),
_T("Active Movie Ctrl"),
WS_CHILD | WS_VISIBLE,
CRect(0,0, 50, 50),
this,
IDC_ACTIVE_MOVIE_CTRL ) )
{
TRACE( "Unable to create Active Movie control. "
"GetLastError() == %dn", GetLastError() );
return -1;
}
IUnknownPtr pUnk = m_AMControl.GetControlUnknown();
if( pUnk )
{
pUnk->QueryInterface( IID_IMediaPlayer,
(void**)&m_pMediaPlayer );
if( m_pMediaPlayer )
{
}
}
#endif
return 0;
}
-
In your
control�s
OnSize()
handler,
make
CEmbeddedFrame
as big
as the
window
(of
course,
you
don�t
have to,
but I
will
make
this
assumption
here).
-
You also
have to
simulate
the
WM_IDLEUPDATECMDUI
behavior
that the
MFC
doc-view
architecture
gives
you.
This is
the
mechanism
in
doc-view
that
updates
the
state of
toolbar
buttons
and
deletes
temporary
objects
from
memory
when the
app
isn't
busy.
The
docking
window
code
uses a
lot of
calls to
DelayRecalcLayout() ,
where
the
RecalcLayout()
call for
the
CMiniFrameWnd
of the
docking
window
is
deferred
until
idle
processing.
If you
don't do
this,
the
frame
and the
control
will not
get
updated
properly.
In the
ActiveX
control,
we fake
it with
the
timer we
set in
CEmbeddedFrame::OnCreate() .
Again, I
wish to
thank
Cristi
for his
help on
this
behavior.
Collapse
Copy
Code
void CEmbeddedFrame::OnTimer(UINT nIDEvent)
{
CFrameWnd::OnTimer(nIDEvent);
if (nIDEvent != 0)
return;
if (m_hWnd != NULL)
{
if (m_nShowDelay == SW_HIDE)
ShowWindow(m_nShowDelay);
if (IsWindowVisible() || m_nShowDelay >= 0)
{
AfxCallWndProc(this, m_hWnd,
WM_IDLEUPDATECMDUI, (WPARAM)TRUE, 0);
SendMessageToDescendants( WM_IDLEUPDATECMDUI,
(WPARAM)TRUE,
0,
TRUE,
TRUE);
}
if (m_nShowDelay > SW_HIDE)
ShowWindow(m_nShowDelay);
m_nShowDelay = -1;
POSITION pos = m_listControlBars.GetHeadPosition();
while (pos != NULL)
{
CControlBar* pBar =
(CControlBar*) m_listControlBars.GetNext(pos);
ASSERT(pBar != NULL);
if (pBar->m_hWnd == NULL ||
pBar->GetDlgCtrlID() != AFX_IDW_DOCKBAR_FLOAT)
continue;
CFrameWnd* pFrameWnd = pBar->GetParentFrame();
if (pFrameWnd->m_hWnd != NULL && pFrameWnd != this)
{
if (pFrameWnd->m_nShowDelay == SW_HIDE)
pFrameWnd->ShowWindow(pFrameWnd->m_nShowDelay);
if (pFrameWnd->IsWindowVisible()
|| pFrameWnd->m_nShowDelay >= 0)
{
AfxCallWndProc(pFrameWnd, pFrameWnd->m_hWnd,
WM_IDLEUPDATECMDUI, (WPARAM)TRUE, 0);
pFrameWnd->SendMessageToDescendants(
WM_IDLEUPDATECMDUI,
(WPARAM)TRUE, 0,
TRUE, TRUE);
}
if (pFrameWnd->m_nShowDelay > SW_HIDE)
pFrameWnd->ShowWindow(pFrameWnd->m_nShowDelay);
pFrameWnd->m_nShowDelay = -1;
}
}
bool bActive = (GetTopLevelParent() == GetForegroundWindow());
if (bActive != m_bActive)
{
NotifyFloatingWindows(bActive ? FS_ACTIVATE : FS_DEACTIVATE);
m_bActive = bActive;
}
}
}
If you have
any
questions on
embedding
docking
windows
inside
ActiveX
controls.
|
|
|
|
|
|