简体   繁体   中英

Copying a selected line from Clistview Pane (MFC)

So using the MFC wizard, there is a context menu in the output pane tabs that it creates for "Copy" and "Clear" & Hide. I have the clear sorted out, but what I can not seem to get my head around is how to use the code provided outside of Visual Studio from MS on how to copy data to the clipboard.

https://docs.microsoft.com/en-us/cpp/mfc/clipboard-using-the-windows-clipboard?view=msvc-160

There are two tabs in the output pane: Status/Debug. The code provided by MS is only has 1 issue and I can't sort out the problem, keeps saying unknown identifier (which I know what it means, but not sure it's saying that since it is an object in the OutputWnd.h file), but the same variable is used elsewhere in the same.cpp file.

My goal here: If I click on a single line in the "status" or "debug" tab, right click, the popup menu shows copy/clear.....I want to copy the selected line to the clipboard. The example code uses:

//strcpy_s((char*)hGlob, 64, "Current selection\r\n");

And if I uncomment that, and run the program, it will paste "Current selection" to a notepad document.....as well as fire my messagebox at the end to confirm I'm running through the entire function for validation.

So when I change it to:

strcpy_s((char*)hGlob, 64, m_wndOutputBuild); // <<< Keeps coming up as unknown identifier????

I keep getting "Unknown Identifier" even though it is used in COutputWnd class. I "think" it has to do with the data being in the COutputlist class but moving the object from Protected to Public doesn't work.

If I comment out the entire void COutputList::OnEditCopyD1() my project fully compiles and works 100% using m_wndOutputBuild to drive the output panes of status/debug....it's this copy thing...I just can't figure out what I am doing wrong.

These files were built my the Visual Studio 2017 MFC wizard, so in that regard, they should be solid...they only provided the messagebox aspect and I'm trying to make it work... simply copying any selected single line of either tab and copying the text from the in focus tab in the pane.

Any thoughts on what I'm missing?

Thank you.

Here are the two files.

OutputWnd.cpp

#include "StdAfx.h"
#include "pch.h"
#include "framework.h"

#include "OutputWnd.h"
#include "Resource.h"
#include "MainFrame.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// COutputBar

COutputWnd::COutputWnd() noexcept
{
}

COutputWnd::~COutputWnd()
{
}

BEGIN_MESSAGE_MAP(COutputWnd, CDockablePane)
    ON_WM_CREATE()
    ON_WM_SIZE()
END_MESSAGE_MAP()

int COutputWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CDockablePane::OnCreate(lpCreateStruct) == -1)
        return -1;

    CRect rectDummy;
    rectDummy.SetRectEmpty();

    // Create tabs window:
    if (!m_wndTabs.Create(CMFCTabCtrl::STYLE_FLAT, rectDummy, this, 1))
    {
        TRACE0("Failed to create output tab window\n");
        return -1;      // fail to create
    }

    // Create output panes:
    const DWORD dwStyle = LBS_NOINTEGRALHEIGHT | WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL;

    if (!m_wndOutputBuild.Create(dwStyle, rectDummy, &m_wndTabs, 2) ||
        !m_wndOutputDebug.Create(dwStyle, rectDummy, &m_wndTabs, 3))
    {
        TRACE0("Failed to create output windows\n");
        return -1;      // fail to create
    }   

    UpdateFonts();

    CString strTabName;
    BOOL bNameValid;

    // Attach list windows to tab:
    bNameValid = strTabName.LoadString(IDS_STATUS_TAB);
    ASSERT(bNameValid);
    m_wndTabs.AddTab(&m_wndOutputBuild, strTabName, (UINT)0);
    bNameValid = strTabName.LoadString(IDS_DEBUG_TAB);
    ASSERT(bNameValid);
    m_wndTabs.AddTab(&m_wndOutputDebug, strTabName, (UINT)1);

    return 0;
}

void COutputWnd::OnSize(UINT nType, int cx, int cy)
{
    CDockablePane::OnSize(nType, cx, cy);

    // Tab control should cover the whole client area:
    m_wndTabs.SetWindowPos (nullptr, -1, -1, cx, cy, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
}

void COutputWnd::AdjustHorzScroll(CListBox& wndListBox)
{
    CMainFrame* pMainFrame = (CMainFrame*)AfxGetMainWnd();
    pMainFrame->m_wndOutput.AddStringDebugTab(_T("Debug: OutputWnd--OutputWnd::AdjustHorzScroll(CListBox& wndListBox)"));
    
    CClientDC dc(this);
    CFont* pOldFont = dc.SelectObject(&afxGlobalData.fontRegular);

    int cxExtentMax = 0;

    for (int i = 0; i < wndListBox.GetCount(); i ++)
    {
        CString strItem;
        wndListBox.GetText(i, strItem);

        cxExtentMax = max(cxExtentMax, (int)dc.GetTextExtent(strItem).cx);
    }

    wndListBox.SetHorizontalExtent(cxExtentMax);
    dc.SelectObject(pOldFont);
}

void  COutputWnd::AddStringStatusTab(CString  message)
{
    m_wndOutputBuild.AddString(message);
    m_wndOutputBuild.SetCurSel(m_wndOutputBuild.GetCount() - 1);
}

void  COutputWnd::AddStringDebugTab(CString  message)
{
    m_wndOutputDebug.AddString(message);
    m_wndOutputDebug.SetCurSel(m_wndOutputDebug.GetCount() - 1);
}

void COutputWnd::UpdateFonts()
{   
    m_wndOutputBuild.SetFont(&afxGlobalData.fontRegular);
    m_wndOutputDebug.SetFont(&afxGlobalData.fontRegular);   
}

/////////////////////////////////////////////////////////////////////////////
// COutputList1

COutputList::COutputList() noexcept
{
}

COutputList::~COutputList()
{
}

BEGIN_MESSAGE_MAP(COutputList, CListBox)
    ON_WM_CONTEXTMENU()
    ON_COMMAND(ID_EDIT_COPY_D1, OnEditCopyD1)
    ON_COMMAND(ID_EDIT_CLEAR, OnEditClear)
    ON_COMMAND(ID_VIEW_OUTPUTWND, OnViewOutput)
    ON_WM_WINDOWPOSCHANGING()
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// COutputList message handlers

void COutputList::OnContextMenu(CWnd* /*pWnd*/, CPoint point)
{
    CMenu menu;
    menu.LoadMenu(IDR_OUTPUT_POPUP);

    CMenu* pSumMenu = menu.GetSubMenu(0);

    if (AfxGetMainWnd()->IsKindOf(RUNTIME_CLASS(CMDIFrameWndEx)))
    {
        CMFCPopupMenu* pPopupMenu = new CMFCPopupMenu;

        if (!pPopupMenu->Create(this, point.x, point.y, (HMENU)pSumMenu->m_hMenu, FALSE, TRUE))
            return;

        ((CMDIFrameWndEx*)AfxGetMainWnd())->OnShowPopupMenu(pPopupMenu);
        UpdateDialogControls(this, FALSE);
    }

    SetFocus();
}

void COutputList::OnEditCopyD1()
{
    //CString source;
    //HGLOBAL clipbuffer;
    //char * buffer;
    //EmptyClipboard();
    //clipbuffer = GlobalAlloc(GMEM_DDESHARE, source.GetLength() + 1);
    //buffer = (char*)GlobalLock(clipbuffer);
    //strcpy(buffer, LPCSTR(source));
    //GlobalUnlock(clipbuffer);
    //SetClipboardData(CF_TEXT, clipbuffer);
    //CloseClipboard();
    


    if (!OpenClipboard())
    {
        AfxMessageBox(_T("Cannot open the Clipboard"));
        return;
    }
    // Remove the current Clipboard contents
    if (!EmptyClipboard())
    {
        AfxMessageBox(_T("Cannot empty the Clipboard"));
        return;
    }
    // Get the currently selected data
    HGLOBAL hGlob = GlobalAlloc(GMEM_FIXED, 64);
    //strcpy_s((char*)hGlob, 64, "Current selection\r\n"); //m_strCurrentEntry
    strcpy_s((char*)hGlob, 64, m_wndOutputBuild); // <<< Keeps coming up as unknown identifier????
    // For the appropriate data formats...
    if (::SetClipboardData(CF_TEXT, hGlob) == NULL)
    {
        CString msg;
        msg.Format(_T("Unable to set Clipboard data, error: %d"), GetLastError());
        AfxMessageBox(msg);
        CloseClipboard();
        GlobalFree(hGlob);
        return;
    }
    CloseClipboard();

    MessageBox(_T("TODO: Copy output")); //<< This fires normally so I know it is working!

    //CMainFrame* pMainFrame = (CMainFrame*)AfxGetMainWnd();
    //m_wndOutput.AddStringStatusTab(_T("Item Copied"));
}

void COutputList::OnEditClear()
{
    CListBox::ResetContent();
    //MessageBox(_T("Clear output"));
}

void COutputList::OnViewOutput()
{
    CDockablePane* pParentBar = DYNAMIC_DOWNCAST(CDockablePane, GetOwner());
    CMDIFrameWndEx* pMainFrame = DYNAMIC_DOWNCAST(CMDIFrameWndEx, GetTopLevelFrame());

    if (pMainFrame != nullptr && pParentBar != nullptr)
    {
        pMainFrame->SetFocus();
        pMainFrame->ShowPane(pParentBar, FALSE, FALSE, FALSE);
        pMainFrame->RecalcLayout();

    }
}

OutputWnd.h

#pragma once

/////////////////////////////////////////////////////////////////////////////
// COutputList window

class COutputList : public CListBox
{
// Construction
public:
    COutputList() noexcept;

// Implementation
public:
    virtual ~COutputList();

protected:
    afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
    afx_msg void OnEditCopyD1();
    afx_msg void OnEditClear();
    afx_msg void OnViewOutput();

    DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////
// COutputWnd window

class COutputWnd : public CDockablePane
{
// Construction
public:
    COutputWnd() noexcept;

    void UpdateFonts();
    void AddStringStatusTab(CString message);
    void AddStringDebugTab(CString message);

// Attributes
protected:
    CMFCTabCtrl m_wndTabs;

    COutputList m_wndOutputBuild;
    COutputList m_wndOutputDebug;
    COutputList m_wndOutputFind;

protected:

    void AdjustHorzScroll(CListBox& wndListBox);

// Implementation
public:
    virtual ~COutputWnd();

protected:
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    afx_msg void OnSize(UINT nType, int cx, int cy);

    DECLARE_MESSAGE_MAP()
};

Here is some code from a project using those output windows. Yes, I did have to implement the "Copy Selection" operation.

void COutputList::OnEditCopy()
{
    while (TRUE)
    {
        if (OpenClipboard())
        {
            if (EmptyClipboard())
            {
                CString s, si;
                for (int i = 0, n = GetCount(); i < n; i++)
                    if (GetSel(i)>0)
                    {
                        GetText(i, si);
                        s += si + _T("\r\n");
                    }
                if (!s.IsEmpty())
                {
                    HGLOBAL hMem = GlobalAlloc(GHND, (s.GetLength() + 1)*sizeof(TCHAR));
                    if (hMem)
                    {
                        LPTSTR p = (LPTSTR)GlobalLock(hMem);
                        if (p)
                        {
                            lstrcpy(p, s);
                            GlobalUnlock(hMem);
                            if (!SetClipboardData(sizeof(TCHAR) == sizeof(WCHAR) ? CF_UNICODETEXT : CF_TEXT, hMem))
                            {
                                GlobalFree(hMem);
                                AfxMessageBox(_T("Could not copy the Selection to the Clipboard!"));
                            }
                        }
                        else
                        {
                            GlobalFree(hMem);
                            AfxMessageBox(_T("Memory Allocation Error!"));
                        }
                    }
                    else AfxMessageBox(_T("Memory Allocation Error!"));
                }
            }
            else AfxMessageBox(_T("The Clipboard could not be emptied!"));
            CloseClipboard();
            break;
        }
        else
            if (AfxMessageBox(_T("The Selection cannot be copied because the Clipboard is currently unavailable"),
                MB_RETRYCANCEL | MB_ICONQUESTION) != IDRETRY)
                break;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM