---- [http://www.tfh-berlin.de/~s716193/pics/TkinMFC.jpg] [[ author: [Sascha Leuthold] ]] ---- Comments are welcome considering implementation-details and discussions on the subject itselfs (widget embedding). ---- ---- '''TkinMFC.tcl''' set buttonTkcon [button .panel.buttonTkcon \ -text "tkcon" -height 3 -width 20 \ -command {source C:/home/TkinMfC/tcl/tkcon.tcl}] pack $buttonTkcon -padx 5 -pady 5 -side left -anchor n set frameAdd [frame .panel.frameAdd -relief sunken -bd 2] pack $frameAdd -padx 5 -pady 5 -side left -expand true -fill both Derive '''CWinApp''' to host the application/thread/event-loop '''TkinMFC.h''' #ifndef TKINMFC_H #define TKINMFC_H #include "resource.h" #include "stdafx.h" class CTkinMfCApp : public CWinApp { public: tktinfo *tinfo_panel; private: Tcl_Interp *interp; char **argv; int argc; private: bool Tk_Initialize(); void ParseCmdLine(int* argc, char*** argv); public: CTkinMfCApp(); //{{AFX_VIRTUAL(CTkinMfCApp) public: virtual int ExitInstance( ); virtual BOOL OnIdle(LONG lCount); virtual BOOL InitInstance(); //}}AFX_VIRTUAL public: //{{AFX_MSG(CTkinMfCApp) //}}AFX_MSG DECLARE_MESSAGE_MAP() }; #endif // TKINMFC_H '''TkinMFC.cpp''' #include "stdafx.h" #include "TkinMfC.h" #include "MainFrm.h" BEGIN_MESSAGE_MAP(CTkinMfCApp, CWinApp) //{{AFX_MSG_MAP(CTkinMfCApp) //}}AFX_MSG_MAP END_MESSAGE_MAP() CTkinMfCApp::CTkinMfCApp() { tinfo_panel = new tktinfo; tinfo_panel->tk_path = ""; } CTkinMfCApp theApp; bool CTkinMfCApp::Tk_Initialize() { ParseCmdLine(&argc,&argv); Tcl_FindExecutable(argv[0]); interp = Tcl_CreateInterp(); /* * argc, argv0 and argv */ char *args; Tcl_DString argString; char buf[TCL_INTEGER_SPACE]; args = Tcl_Merge(argc, (CONST char **)argv); Tcl_ExternalToUtfDString(NULL, args, -1, &argString); Tcl_SetVar(interp, "argv", Tcl_DStringValue(&argString), TCL_GLOBAL_ONLY); Tcl_DStringFree(&argString); ckfree(args); sprintf(buf, "%d", argc); Tcl_ExternalToUtfDString(NULL, argv[0], -1, &argString); Tcl_SetVar(interp, "argc", buf, TCL_GLOBAL_ONLY); Tcl_SetVar(interp, "argv0", Tcl_DStringValue(&argString), TCL_GLOBAL_ONLY); /* * Initialize packages */ if (Tcl_Init(interp) == TCL_ERROR) { return TCL_ERROR; } if (Tk_Init(interp) == TCL_ERROR) { return TCL_ERROR; } if (Tcl_Eval(interp, "wm withdraw .") != TCL_OK) { return false; } CWnd* cwndPtr = AfxGetMainWnd( ); CMainFrame* cmainPtr = static_cast(cwndPtr); HWND DlgBar_hWnd = cmainPtr->m_wndDlgBar; char tkwin_panel[] = ".panel"; tinfo_panel->tk_path = tkwin_panel; tinfo_panel->interp = interp; SetProp(DlgBar_hWnd, "tktinfo", static_cast(tinfo_panel)); char buffer[1000]; _snprintf(buffer, sizeof(buffer), "toplevel %s -use 0x%x", tkwin_panel, DlgBar_hWnd); if (Tcl_Eval(interp, buffer) != TCL_OK) { return false; } Tk_Window tkmain_panel = Tk_MainWindow(interp); tinfo_panel->tktkwin = Tk_NameToWindow(interp, static_cast(tkwin_panel), tkmain_panel); RECT topsz_panel; GetClientRect(DlgBar_hWnd, &topsz_panel); Tk_MoveResizeWindow(tinfo_panel->tktkwin, 0, 0, topsz_panel.right, topsz_panel.bottom); int i; _snprintf(buffer, sizeof(buffer), "winfo id %s", tinfo_panel->tk_path); Tcl_Eval(interp, buffer); Tcl_GetInt(interp, interp->result, &i); tinfo_panel->tkhwnd = reinterpret_cast(i); Tcl_Eval(interp, "source [file join C:/ home TkinMfC tcl TkinMfC.tcl]"); Tcl_PkgProvide(interp, "tkinmfc", "1.1"); return true; } BOOL CTkinMfCApp::InitInstance() { SetRegistryKey(_T("Local AppWizard-Generated Applications")); CMainFrame* pFrame = new CMainFrame; m_pMainWnd = pFrame; pFrame->LoadFrame(IDR_MAINFRAME); pFrame->ShowWindow(SW_SHOW); pFrame->UpdateWindow(); if (!Tk_Initialize()) return FALSE; return TRUE; } int CTkinMfCApp::ExitInstance( ) { delete tinfo_panel; CWinApp::ExitInstance(); return 0; } BOOL CTkinMfCApp::OnIdle(LONG lCount) { while(Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT)) { } return 0; } void CTkinMfCApp::ParseCmdLine(int* argcPtr, char*** argvPtr) { /* * tclAppInit.c -- * * Provides a default version of the main program and Tcl_AppInit * procedure for Tcl applications (without Tk). Note that this * program must be built in Win32 console mode to work properly. * * Copyright (c) 1996-1997 by Sun Microsystems, Inc. * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * RCS: @(#) $Id: 15861,v 1.1 2006-05-05 06:00:31 jcw Exp $ static void setargv(argcPtr, argvPtr) int *argcPtr; Filled with number of argument strings. char ***argvPtr; Filled with argument strings (malloc'd). ) Code from tcl-distribution */ char *cmdLine, *p, *arg, *argSpace; char **argv; int argc, size, inquote, copy, slashes; /* * Set argv[0] to *.exe */ char buffer[MAX_PATH+1]; GetModuleFileName(m_hInstance, buffer, sizeof(buffer)); for (p = buffer; *p != '\0'; p++) { if (*p == '\\') { *p = '/'; } } for (p = buffer; ; p++) { if (*p == '\0') { *p = ' '; /* * Append the command line options */ for (int i = 0; ; i++) { if ( m_lpCmdLine[i] == '\0') break; p++; *p = m_lpCmdLine[i]; } p++; *p = '\0'; break; } } cmdLine = buffer; /* * Precompute an overly pessimistic guess at the number of arguments * in the command line by counting non-space spans. */ size = 2; for (p = cmdLine; *p != '\0'; p++) { if ((*p == ' ') || (*p == '\t')) { /* INTL: ISO space. */ size++; while ((*p == ' ') || (*p == '\t')) { /* INTL: ISO space. */ p++; } if (*p == '\0') { break; } } } argSpace = (char *) Tcl_Alloc( (unsigned) (size * sizeof(char *) + strlen(cmdLine) + 1)); argv = (char **) argSpace; argSpace += size * sizeof(char *); size--; p = cmdLine; for (argc = 0; argc < size; argc++) { argv[argc] = arg = argSpace; while ((*p == ' ') || (*p == '\t')) { /* INTL: ISO space. */ p++; } if (*p == '\0') { break; } inquote = 0; slashes = 0; while (1) { copy = 1; while (*p == '\\') { slashes++; p++; } if (*p == '"') { if ((slashes & 1) == 0) { copy = 0; if ((inquote) && (p[1] == '"')) { p++; copy = 1; } else { inquote = !inquote; } } slashes >>= 1; } while (slashes) { *arg = '\\'; arg++; slashes--; } if ((*p == '\0') || (!inquote && ((*p == ' ') || (*p == '\t')))) { /* INTL: ISO space. */ break; } if (copy != 0) { *arg = *p; arg++; } p++; } *arg = '\0'; argSpace = arg + 1; } argv[argc] = NULL; *argcPtr = argc; *argvPtr = argv; } Derive '''CFrameWnd''' '''MainFrame.h''' #ifndef MAINFRM_H #define MAINFRM_H class CMainFrame : public CFrameWnd { public: CMainFrame(); protected: DECLARE_DYNAMIC(CMainFrame) public: virtual ~CMainFrame(); CDialogBar m_wndDlgBar; protected: //{{AFX_MSG(CMainFrame) afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnPaint(); afx_msg void OnSize(UINT nType, int cx, int cy); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; #endif // MAINFRM_H '''MainFrame.cpp''' #include "stdafx.h" #include "TkinMfC.h" #include "MainFrm.h" IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd) BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //{{AFX_MSG_MAP(CMainFrame) ON_WM_CREATE() ON_WM_PAINT() ON_WM_SIZE() //}}AFX_MSG_MAP END_MESSAGE_MAP() CMainFrame::CMainFrame() { } CMainFrame::~CMainFrame() { } int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; if (!m_wndDlgBar.Create(this, IDD_DIALOG1, CBRS_BOTTOM|CBRS_TOOLTIPS|CBRS_FLYBY, IDD_DIALOG1)) return -1; return 0; } void CMainFrame::OnSize(UINT nType, int cx, int cy) { CFrameWnd::OnSize(nType, cx, cy); CRect rect; m_wndDlgBar.GetClientRect(&rect); rect.right = cx; rect.top = cy - rect.bottom; rect.bottom = cy; m_wndDlgBar.MoveWindow(rect); CTkinMfCApp* appPtr = static_cast(AfxGetApp()); if(appPtr->tinfo_panel->tk_path != "") Tk_MoveResizeWindow(appPtr->tinfo_panel->tktkwin, 0, 0, cx, rect.bottom - rect.top); } void CMainFrame::OnPaint() { CPaintDC dc(this); CRect rect,rectTk; GetClientRect(&rect); m_wndDlgBar.GetClientRect(&rectTk); rect.bottom = rect.bottom - rectTk.bottom; dc.TextOut(rect.right/2-50,rect.bottom/2,"MFC Control"); rect.left = 10; rect.top = 10; rect.bottom = rect.bottom-10; rect.right = rect.right-10; CBrush brush; brush.CreateSolidBrush(RGB(0,0,255)); dc.FrameRect(&rect,&brush); } '''stdafx.h''' #ifndef STDAFX_H #define STDAFX_H #define VC_EXTRALEAN #include #include #define NO_CONST #include struct tktinfo { char *tk_path; HWND tkhwnd; Tk_Window tktkwin; Tcl_Interp *interp; }; #endif // STDAFX_H ---- ''What do you think?'' Is it possible to achieve the same easier? ---- [[ [Category GUI] | [Category Windows] | [Category Example] ]]