从 Clistview 窗格 (MFC) 复制选定的行
Copying a selected line from Clistview Pane (MFC)
因此使用 MFC 向导,在输出窗格选项卡中有一个上下文菜单,它为“复制”和“清除”和“隐藏”创建。我已经清楚地整理好了,但我似乎无法理解的是如何使用 MS Visual Studio 之外提供的代码将数据复制到剪贴板。
https://docs.microsoft.com/en-us/cpp/mfc/clipboard-using-the-windows-clipboard?view=msvc-160
输出窗格中有两个选项卡:Status/Debug。 MS 提供的代码只有 1 个问题,我无法解决问题,一直说未知标识符(我知道这是什么意思,但不确定它是在说什么,因为它是 OutputWnd.h 中的一个对象文件),但在同一个 .cpp 文件的其他地方使用了相同的变量。
我的目标是:如果我在“状态”或“调试”选项卡中单击一行,右键单击,弹出菜单显示copy/clear.....我想复制选定的线到剪贴板。示例代码使用:
//strcpy_s((char*)hGlob, 64, "Current selection\r\n");
如果我取消注释,运行 程序,它会将“当前选择”粘贴到记事本文档中......并在最后触发我的消息框以确认我是运行通过整个函数进行验证。
所以当我把它改成:
strcpy_s((char*)hGlob, 64, m_wndOutputBuild); // <<< Keeps coming up as unknown identifier????
即使在 COutputWnd class 中使用它,我仍然收到“未知标识符”。我“认为”它与 COutputlist class 中的数据有关,但是将对象从 Protected 移动到 Public 不起作用。
如果我注释掉整个 void COutputList::OnEditCopyD1() 我的项目使用 m_wndOutputBuild 驱动 status/debug 的输出面板完全编译并 100% 工作......就是这个复制东西...我只是不知道我做错了什么。
这些文件是我 Visual Studio 2017 MFC 向导构建的,所以在这方面,它们应该是可靠的...它们只提供了消息框方面,我正在努力使其工作...只需复制任一选项卡的任何选定的单行并从窗格中的焦点选项卡复制文本。
对我遗漏的东西有什么想法吗?
谢谢。
这是两个文件。
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()
};
这是使用这些输出的项目中的一些代码 windows。是的,我确实必须执行“复制选择”操作。
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;
}
}
因此使用 MFC 向导,在输出窗格选项卡中有一个上下文菜单,它为“复制”和“清除”和“隐藏”创建。我已经清楚地整理好了,但我似乎无法理解的是如何使用 MS Visual Studio 之外提供的代码将数据复制到剪贴板。
https://docs.microsoft.com/en-us/cpp/mfc/clipboard-using-the-windows-clipboard?view=msvc-160
输出窗格中有两个选项卡:Status/Debug。 MS 提供的代码只有 1 个问题,我无法解决问题,一直说未知标识符(我知道这是什么意思,但不确定它是在说什么,因为它是 OutputWnd.h 中的一个对象文件),但在同一个 .cpp 文件的其他地方使用了相同的变量。
我的目标是:如果我在“状态”或“调试”选项卡中单击一行,右键单击,弹出菜单显示copy/clear.....我想复制选定的线到剪贴板。示例代码使用:
//strcpy_s((char*)hGlob, 64, "Current selection\r\n");
如果我取消注释,运行 程序,它会将“当前选择”粘贴到记事本文档中......并在最后触发我的消息框以确认我是运行通过整个函数进行验证。
所以当我把它改成:
strcpy_s((char*)hGlob, 64, m_wndOutputBuild); // <<< Keeps coming up as unknown identifier????
即使在 COutputWnd class 中使用它,我仍然收到“未知标识符”。我“认为”它与 COutputlist class 中的数据有关,但是将对象从 Protected 移动到 Public 不起作用。
如果我注释掉整个 void COutputList::OnEditCopyD1() 我的项目使用 m_wndOutputBuild 驱动 status/debug 的输出面板完全编译并 100% 工作......就是这个复制东西...我只是不知道我做错了什么。
这些文件是我 Visual Studio 2017 MFC 向导构建的,所以在这方面,它们应该是可靠的...它们只提供了消息框方面,我正在努力使其工作...只需复制任一选项卡的任何选定的单行并从窗格中的焦点选项卡复制文本。
对我遗漏的东西有什么想法吗?
谢谢。
这是两个文件。
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()
};
这是使用这些输出的项目中的一些代码 windows。是的,我确实必须执行“复制选择”操作。
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;
}
}