- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在尝试将 OpenGL 控件添加到 MFC 对话框中。该对话框是从一个也运行 OpenGL 的窗口启动的……这使它变得复杂。由于一次只有一个 OpenGL 上下文可以在一个线程上运行,我要么必须拥有整个对话框,要么只拥有它自己的线程上的控件。我选择尝试后者,因为它会让我们项目中的其他对话框也更容易使用。
我对 MFC 的大部分了解都是参差不齐的,因为我一直在学习,所以如果我错过了重要的东西,我深表歉意。我真的可以使用一些 MFC 帮助来确定最佳的消息传递方式,或者从对话框中为控件设置属性。幸运的是,我似乎有一些工作。
我只是将 OnSize 用作示例。我在控件包装器类中创建了这个函数,以尝试将消息从对话框推送到控件。
void AddOpenGLControl::PostMessageToControl(UINT Msg, WPARAM wParam, LPARAM lParam)
{
if (dialogHandle != NULL)
PostMessage(dialogHandle, Msg, wParam, lParam);
}
但这让我不得不尝试在对话框中模拟假的 Windows 消息,这些消息可能已经存在,以发送到控件。
WPARAM wp = nType;
LPARAM lp = MAKELPARAM(ctrlRect.Width(), ctrlRect.Height());
openGlControlOnThread.PostMessageToControl(WM_SIZE, wp, lp);
我知道我会想要像普通控件一样访问触发更多消息,而这种方法会很快变得麻烦。
有没有办法简单地传递消息?很难要求我不知道的东西,但我在考虑继承,或者包装类中的消息映射,或者预翻译消息,或者从隐藏的普通控件中窃取消息以发送或者......好吧,我' d 采取任何可以跨线程工作的东西。
这是所有代码,以填补空白。我尽可能地将代码配对,但我确实必须使用我们的消息循环(抱歉!)。这是我从窗口的标准启动:
//Main thread (with existing openGL window)
class TCADTLSandbox2
{
public:
virtual bool DoCmd(); // Main Entry Point
};
bool TCADTLSandbox2::DoCmd()
{
TCADTLSandbox2Dialog dialog;
dialog.Create(TCADTLSandbox2Dialog::IDD);
dialog.ShowWindow(SW_SHOW);
// We have to use the main window's accessors to get any messages from the window
WPARAM dialogMessage;
while (!GetUITools()->WaitForCommandMessage("", dialogMessage) || (dialogMessage != TIMsgIDCancel))
{
if (dialogMessage == TIMsgIDOK)
{
break;
}
}
dialog.ShowWindow(SW_HIDE);
dialog.DestroyWindow();
return true;
}
这是对话框类。类成员 openGlControlOnThread 和 OnSize() 是两个有趣的东西。
//Dialog
class TCADTLSandbox2Dialog : public CDialog
{
DECLARE_DYNAMIC(TCADTLSandbox2Dialog)
public:
TCADTLSandbox2Dialog(CWnd* pParent = NULL);
virtual ~TCADTLSandbox2Dialog();
enum { IDD = IDD_SANDBOX2 };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
DECLARE_MESSAGE_MAP()
private:
AddOpenGLControl openGlControlOnThread;
virtual BOOL OnInitDialog();
afx_msg void OnBnClickedOk();
afx_msg void OnBnClickedCancel();
afx_msg void OnSize(UINT nType, int cx, int cy);
};
IMPLEMENT_DYNAMIC(TCADTLSandbox2Dialog, CDialog)
TCADTLSandbox2Dialog::TCADTLSandbox2Dialog(CWnd* pParent /*=NULL*/): CDialog(TCADTLSandbox2Dialog::IDD, pParent){}
TCADTLSandbox2Dialog::~TCADTLSandbox2Dialog(){}
void TCADTLSandbox2Dialog::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(TCADTLSandbox2Dialog, CDialog)
ON_BN_CLICKED(IDOK, &TCADTLSandbox2Dialog::OnBnClickedOk)
ON_BN_CLICKED(IDCANCEL, &TCADTLSandbox2Dialog::OnBnClickedCancel)
ON_WM_SIZE()
END_MESSAGE_MAP()
BOOL TCADTLSandbox2Dialog::OnInitDialog()
{
CDialog::OnInitDialog();
CRect rect;
GetDlgItem(IDC_CADTL_SANDBOX_OPENGLTEST)->GetWindowRect(rect);
ScreenToClient(rect);
openGlControlOnThread.Create(rect, this);
initialized = true;
return TRUE;
}
void TCADTLSandbox2Dialog::OnSize(UINT nType, int cx, int cy)
{
CDialog::OnSize(nType, cx, cy);
if (initialized)
{
CRect ctrlRect(0, 0, 0, 0);
GetDlgItem(IDC_CADTL_SANDBOX_OPENGLTEST)->GetWindowRect(ctrlRect);
ScreenToClient(ctrlRect);
//int buttonWidth = ctrlRect.Width();
ctrlRect.left = 20;
ctrlRect.right = cx - 20;
ctrlRect.bottom = cy - 50;
WPARAM wp = nType;
LPARAM lp = MAKELPARAM(ctrlRect.Width(), ctrlRect.Height());
openGlControlOnThread.PostMessageToControl(WM_SIZE, wp, lp);
}
}
void TCADTLSandbox2Dialog::OnBnClickedOk()
{
PostQuitMessage(0);
}
void TCADTLSandbox2Dialog::OnBnClickedCancel()
{
PostQuitMessage(0);
CDialog::OnCancel();
}
这就是它变得有趣的地方。这就是我将 OpenGL 控件包装到新线程上所做的。 PostMessageToControl 是我希望用更简单的东西替换的东西。
// Class to kickoff the control thread
class AddOpenGLControl
{
public:
AddOpenGLControl();
~AddOpenGLControl();
void Create(CRect rect, CWnd *parent);
// You can send something along the lines of (WM_DESTROY, NULL, NULL)
void PostMessageToControl(UINT Msg, WPARAM wParam, LPARAM lParam);
private:
void StartThread(CRect rect, CWnd *parent);
std::thread controlThread;
};
// *** The thread class ***
AddOpenGLControl::AddOpenGLControl(){}
AddOpenGLControl::~AddOpenGLControl()
{
WaitForSingleObject(controlThread.native_handle(), INFINITE); // Okay?
controlThread.join(); // Also okay?
}
void AddOpenGLControl::PostMessageToControl(UINT Msg, WPARAM wParam, LPARAM lParam)
{
if (dialogHandle != NULL)
PostMessage(dialogHandle, Msg, wParam, lParam);
}
void AddOpenGLControl::Create(CRect rect, CWnd *parent)
{
std::thread initThread(&AddOpenGLControl::StartThread, this, rect, std::ref(parent));
controlThread = std::move(initThread);
}
void AddOpenGLControl::StartThread(CRect rect, CWnd *parent)
{
COpenGLControl *openGLControl = new COpenGLControl;
openGLControl->Create(rect, parent);
openGLControl->m_unpTimer = openGLControl->SetTimer(1, 1000, 0);
HWND threadHandle = (HWND)openGLControl->GetSafeHwnd();
// This is where I start getting lost. Taken from MSDN
MSG msg;
BOOL bRet;
while ((bRet = GetMessage(&msg, threadHandle, 0, 0)) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
这里是控件本身:
// OpenGL Dialog Control thread (now it can have it's own openGL context)
class COpenGLControl : public CWnd
{
public:
UINT_PTR m_unpTimer;
COpenGLControl();
virtual ~COpenGLControl();
void Create(CRect rect, CWnd *parent);
void UpdateOpenGLDispay();
afx_msg void OnSize(UINT nType, int cx, int cy);
void ParentDialogResize(UINT nType, int cx, int cy);
private:
CWnd *hWnd;
HDC hDC;
HGLRC openGLRC;
CString className;
void Initialize();
void DrawCRD(double centerX, double centerY, double centerZ, double crdScale);
afx_msg void OnPaint();
afx_msg void OnDraw(CDC *pDC);
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnTimer(UINT_PTR nIDEvent);
DECLARE_MESSAGE_MAP()
};
// *** The actual control ***
COpenGLControl::COpenGLControl()
{
initialized = false;
display = new Display2d;
}
COpenGLControl::~COpenGLControl()
{
CleanUp();
}
BEGIN_MESSAGE_MAP(COpenGLControl, CWnd)
ON_WM_PAINT()
ON_WM_CREATE()
ON_WM_TIMER()
ON_WM_SIZE()
ON_WM_DESTROY()
END_MESSAGE_MAP()
int COpenGLControl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
Initialize();
return 0;
}
void COpenGLControl::Initialize()
{
// Initial Setup:
//
//Set up the pixal descriptor for using openGL on the graphics card
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), // Size of this structure
1, // Version of this structure
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA,
24, // Want 24bit color
0, 0, 0, 0, 0, 0, // Not used to select mode
0, 0, // Not used to select mode
0, 0, 0, 0, 0, // Not used to select mode
32, // Size of depth buffer
0, // Not used to select mode
0, // Not used to select mode
PFD_MAIN_PLANE, // Draw in main plane
0, // Not used to select mode
0, 0, 0 }; // Not used to select mode
// Store the device context
if (!(hDC = GetDC()->m_hDC)) // From the dialog?
{
AfxMessageBox("Can't Create A GL Device Context.");
//May not be able to unregister class?? May not need to?
return;
}
// Choose a pixel format that best matches that described in pfd
int nPixelFormat; // Pixel format index
nPixelFormat = ChoosePixelFormat(hDC, &pfd);
// Set the pixel format for the device context
if (!SetPixelFormat(hDC, nPixelFormat, &pfd))
AfxMessageBox("Setting pixel format failed");
// Create the rendering context and make it current
if (!(openGLRC = wglCreateContext(hDC)))
{
AfxMessageBox("Can't Create A GL Rendering Context.");
//May not be able to unregister class?? May not need to?
return;
}
if (!wglMakeCurrent(hDC, openGLRC))
AfxMessageBox("WGLFailed");
// Set color to use when clearing the background.
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClearDepth(1.0f);
// Turn on backface culling
glFrontFace(GL_CCW);
glCullFace(GL_BACK);
// Turn on depth testing
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
// Enable alpha blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
UpdateOpenGLDispay();
initialized = true;
}
void COpenGLControl::Create(CRect rect, CWnd *parent)
{
className = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW | CS_OWNDC, NULL, (HBRUSH)GetStockObject(BLACK_BRUSH), NULL);
CreateEx(0, className, "OpenGL", WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, rect, parent, 0);
hWnd = parent;
}
void COpenGLControl::OnPaint()
{
// Attempt to help with flickering
UpdateOpenGLDispay();
CPaintDC dc(this);
ValidateRect(NULL);
}
void COpenGLControl::OnDraw(CDC *pDC)
{
UpdateOpenGLDispay();
}
void COpenGLControl::UpdateOpenGLDispay()
{
DrawCRD(); // ... just draw something
SwapBuffers(hDC);
}
void COpenGLControl::DrawCRD(double centerX, double centerY, double centerZ, double crdScale)
{
// X CRD
glColor4f(1.0f, 0.0f, 0.0f, 1);//R
glBegin(GL_LINES);
glVertex3f(centerX, centerY, centerZ);
glVertex3f(centerX + 1 * crdScale, centerY, centerZ);
glEnd();
// Y CRD
glColor4f(0.0f, 0.0f, 1.0f, 1);//B
glBegin(GL_LINES);
glVertex3f(centerX, centerY, centerZ);
glVertex3f(centerX, centerY + 1 * crdScale, centerZ);
glEnd();
// Z CRD
glColor4f(0.0f, 1.0f, 0.0f, 1);//G
glBegin(GL_LINES);
glVertex3f(centerX, centerY, centerZ);
glVertex3f(centerX, centerY, centerZ + 1 * crdScale);
glEnd();
}
void COpenGLControl::OnTimer(UINT_PTR nIDEvent)
{
switch (nIDEvent)
{
case 1:
UpdateOpenGLDispay();
break;
}
CWnd::OnTimer(nIDEvent);
}
void COpenGLControl::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy);
if (0 >= cx || 0 >= cy || nType == SIZE_MINIMIZED) return;
if (nType == SIZE_RESTORED)
ParentDialogResize(nType, cx, cy);
}
void COpenGLControl::ParentDialogResize(UINT nType, int cx, int cy)
{
if (initialized)
{
if (0 >= cx || 0 >= cy || nType == SIZE_MINIMIZED) return;
this->SetWindowPos(NULL, 20, 20, cx, cy, SWP_SHOWWINDOW); // fixed for this example
}
}
void COpenGLControl::OnDestroy()
{
CWnd::OnDestroy();
PostQuitMessage(0);
}
void COpenGLControl::CleanUp()
{
if (!wglDeleteContext(openGLRC))
AfxMessageBox("Deleting OpenGL Rendering Context failed");
if (!wglMakeCurrent(hDC, NULL))
AfxMessageBox("Removing current DC Failed");
//ReleaseDC(hDC); // The internets say the device context should automatically be deleted since it's CS_OWNDC
}
// Sorry for the heap of code. Or is it stack?
谢谢!
最佳答案
似乎我错过了 MFC 的几个重要方面。如果有人遵循类似的路径,最好在尝试创建 opengl 控件之前先完成常规控件的子类化过程。
有几种方法可以做到这一点。如果我使用 OnWndMsg或类似的 WindowProc我可以在消息仍处于 wParam/lParam 状态时获取消息,并将其传递。
BOOL TCADTLSandbox2Dialog::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
//This is one way to just pass the message along. For some cases, we may need to check the mouse position as well.
if (message == WM_MOUSEWHEEL)
{
openGlControlOnThread.PostMessageToControl(message, wParam, lParam);
return true;
}
if (wParam == WM_LBUTTONDOWN)
{
openGlControlOnThread.PostMessageToControl(message, wParam, lParam);
return true;
}
return CDialog::OnWndMsg(message, wParam, lParam, pResult);
}
此外,事实证明 PreTranslateMessage是我可以使用的一个选项,尽管当时我没有看到如何使用。
BOOL TCADTLSandbox2Dialog::PreTranslateMessage(MSG* pMsg)
{
// Send the message to the control (the dialog gets it by default)
if (pMsg->message == WM_MOUSEWHEEL)
{
openGlControlOnThread.PostMessageToControl(pMsg->message, pMsg->wParam, pMsg->lParam);
return true;
}
return MCDialog::PreTranslateMessage(pMsg);
}
希望这对其他人有帮助!
关于c++ - 在 MFC 对话框和它自己的线程上的 OpenGL 控件之间传递消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35659457/
我有一个 MFC 项目,它链接到第三方 dll。在程序退出时,IDE 会报告“检测到内存泄漏!”并倾倒泄漏物。 这些泄漏来自第三方 dll。我很确定这些是错误的报道。 (Google 的快速检查表明
首先我想要的是:能够显示具有多列的网格,每个单元格都有一个自定义渲染回调。因此,您可以使用这样的控件在游戏中显示您的库存,或者类似于 Google Chrome 中的行为,它会显示您访问的热门页面的网
在新的 MFC 功能(功能包)中,菜单出现在三个地方: 在菜单栏中 (CMFCMenuBar) 在弹出菜单中 (CMFCPopupMenu) 在 CMFCButton 的“下拉菜单”版本中 我想在所有
在我的 MFC 项目中,我想动态生成标签。例如:我必须为它们生成 4 个编辑控件和相应的标签——比如“Label1”“Label2”...... CStatic *label[MAX_THREAD];
我有第一个对话框,上面有一个简单的按钮,单击该按钮时,使用 CDialog::Create(IDD,this) 创建了第二个对话框。我希望在销毁第二个对话框但不向第二个对话框添加任何代码时通知父级,即
我们的代码库中的添加到剪贴板代码非常低级 - 分配全局内存等等。对于简单的情况,我只想将一些纯文本放在剪贴板上,是否有任何例程可以包装所有这些内容? 一个例子是 CRichEditCtrl 具有 Co
我对 mfc 中事件和消息之间的区别有点困惑。 他们是一样的吗? 最佳答案 由于您专门询问 MFC,我假设您指的是可以在 MFC 类的属性窗口中定义的事件处理程序和消息处理程序。 在“事件”下,您可以
如何以编程方式检测我的 MFC 应用程序当前是否正在显示模式对话框或属性表?目前我正在使用以下内容,但我觉得该代码也会触发无模式对话框。 bool HasModalDialog(const CWnd*
我有两个按钮: 单选按钮:“十六进制” 按钮:“A” 我想在用户选中“十六进制”按钮时启用“A”(“A”在创建时的状态为“禁用”),我该怎么做?谢谢大家。 最佳答案 您需要使用 CButton 's
通常情况下,窗口的厚度为 4 个像素,可以通过 GetSystemMetrics 方法获取。我可以更改它的值,例如 2 个像素吗? 非常感谢! 最佳答案 简单的回答:不。不适用于特定窗口。 复杂的答案
我需要打开一个从同一个类实例化的对话框两次。当我尝试这个时 CdelmeDlg dlg; dlg.DoModal(); dlg.DoModal(); 第二个调用只打开对话框一瞬间,然后关闭。我敢打赌消
如何通过代码在 mfc 中减少标题栏的窗口? 最佳答案 用: ModifyStyle (WS_CAPTION, 0); // to hide ModifyStyle (0, WS_CAPTION);
我使用 AfxMessageBox 关键字显示消息框。基本的东西。 但是,由于路径的长度,它显示如下: 有什么方法可以阻止它以这种方式自动换行吗? 抱歉,如果这是一个愚蠢的问题。但如果我只有一个句子,
所以,我有一个 MFC 程序的插件。我正在使用鼠标事件 Hook (来自 SetWindowsHookEx)来捕获点击。主机应用程序可以打开任意数量的(可能重叠的)子窗口,但我只想拦截特定子窗口中的点
我正在尝试将图像添加到现有按钮..我在一定程度上做到了这一点,问题是我可以添加一个所有者绘制的图像,但无法添加我想要的确切图像..示例见下文代码 CButton* pBtn= (CButton*)Ge
我想在对话框的标题栏上放置一些控件。一种可能的解决方案是,我只是从对话框中删除标题栏并绘制自己的标题栏。 但是如果我自己画标题栏,标题栏的外观不会根据窗口的主题而改变。而且我也不得不忍受接近、最小化和
我已经使用 MinGW 开发了 WinAPI 应用程序,没有问题。现在,我可以用 MFC 做同样的事情吗? 最佳答案 你不能。 MFC 代表 Microsoft Foundation Classes,
(我正在使用VS ++ 2005) 我在对话框上放置了编辑框控件(ID为ID_edit_box),并为其关联了两个变量(使用处理程序向导):控件(c_editbox)和值(v_editbox)变量。我
我有一个自定义 MFC 对话框 CMyDialog,使用资源编辑器添加了一个类型为 CMyControl 的自定义控件 - 该对话框有一个控件的成员变量并且有 DDX设置。 该控件正在接收绘制消息,并
直到现在,我从未真正需要我正在开发的大型 MFC(如果重要,则为单文档界面)应用程序的 Winapp ExitInstance()。但现在我这样做了,主要是为了清理内存分配、卸载一些 DLL 等。好吧
我是一名优秀的程序员,十分优秀!