TrackPopupMenu会阻塞调用的线程
c++吧
全部回复
仅看楼主
level 10
不眠梦乡 楼主
比如我的程序有一个托盘,在托盘图标右键时,程序就阻塞了,但是我的程序需要更新,
有什么解决方法,
2014年12月19日 17点12分 1
level 10
不眠梦乡 楼主
因为程序是按帧数更新的,像游戏画面一样
while()
{
if ( PeekMessage )
//
else
//
}
但是阻塞了画面就不更新,怎么解决
2014年12月19日 17点12分 2
level 10
不眠梦乡 楼主
。。。。
2014年12月20日 11点12分 3
level 10
不眠梦乡 楼主
我尝试在托盘右键消息中新开一个线程处理弹出菜单,结果菜单没出来,不知道是什么原因。。
2014年12月20日 11点12分 4
你应该在子线程中写游戏逻辑,主线程做窗口,游戏菜单用贴图,不要用Win菜单。
2014年12月20日 15点12分
level 13
你是做游戏吧?
我就是游戏专业毕业的,这个没办法,Windows本来的菜单也会的,就是你拖窗口也会卡住线程。
我曾经问过老师,他也没办法。不过后来我自己多线程后,才明白使用PeekMessage做游戏是多么落后的技术。
经过我的研究,最好的方式是主线程用正常的消息循环处理窗口消息,甚至直接DialogBoxIndirect都行。然后开一个子线程在子线程里写游戏循环,不要管消息也不要处理消息。
游戏线程推荐用timeSetEvent创建定时器线程(用TIME_ONESHOT模式),因为它比如CreateThread创建的普通线程实时性更高。比如在我电脑上普通线程Sleep(1)会实际暂停10ms,而定时器线程Sleep(1)实际暂停timeSetEvent的第二个参数指定值。
2014年12月20日 15点12分 5
level 10
不眠梦乡 楼主
是按游戏的框架做的,因为程序15帧的,但是又不是单纯的游戏,这么说吧,是一个抽奖软件,画面在滚动号码,同时还有一些简单的动画。
然后,有一些活动,投影仪的画面是副屏,这样播ppt的同时也可以操作电脑而不会被观众看到
所以,我写的这个软件是拖到第二屏幕并且置顶的,然后在主屏幕的托盘可以有简单的控制,但是,弹出快捷菜单就阻塞了
2014年12月20日 15点12分 6
[汗]抽奖程序滚动动画用SetTimer不就行了,弹出式菜单内部有消息循环,所以内部还是照样会响应WM_TIMER的。
2014年12月20日 15点12分
回复 yjryym :菜单内部响应?不明白,菜单是用trackpopunmenu显示的,会阻塞在这里
2014年12月20日 15点12分
回复 不眠梦乡 :我是说
TrackPopunMenu
内部有消息循环,所以使用TIMER来做就会继续响应。
2014年12月20日 15点12分
回复 yjryym :这样啊,我明天试下
2014年12月20日 16点12分
level 10
不眠梦乡 楼主
UI就不更新了,号码就不滚动,本来我想都用快捷键控制的,但是考虑到使用的人,就是学校社团里面的人,未必很熟悉,也不够明白直观
2014年12月20日 15点12分 7
@ yjryym 不知道怎么说得明白点
2014年12月20日 15点12分
level 10
不眠梦乡 楼主
按照你在5楼的方法,托盘图标右键阻塞掉主线程,然后子线程继续定时更新,是这样吗
2014年12月20日 15点12分 8
游戏的话就这样做,普通应用没必要,SetTimer即可搞定。
2014年12月20日 15点12分
回复 yjryym :嗯嗯,虽说一个程序不需要,但我想做一个大体的框架出来,下次直接用
2014年12月20日 15点12分
回复 yjryym :10楼,谢谢你啦[哈哈] 我明天试试,
2014年12月20日 15点12分
level 12

2014年12月20日 15点12分 9
level 10
不眠梦乡 楼主
timesetevent如果用回调函数
我对回调函数的实现机制不了解,它是另开一个线程执行的吗,
2014年12月20日 15点12分 10
timeSetEvent和SetTimer的区别是:SetTimer是在当然线程开定时器,并定时产生WM_TIMER消息;timeSetEvent是单独开一个线程的定时器,支持一次模式和周期模式,周期模式就是定时调用一次回调函数,一次模式就和CreateThread一样回调函数返回即关闭线程(但实时性高于CreateThread)。
2014年12月20日 16点12分
回复 yjryym :嗯,你对这方面好了解啊,谢谢啦,明天要早起,晚安。。
2014年12月20日 16点12分
回复 不眠梦乡 :打错字了,是
SetTimer是在当前线程开定时器[哈哈]
2014年12月20日 16点12分
level 9
[冷]阻塞大法好,模态大法好,彩笔路过
2014年12月20日 17点12分 11
level 13
// 这是我研究的游戏循环框架的多线程版,注释过得代码是用来测试的。
#include <Windows.h>
#include <tchar.h>
#include <imm.h>
#pragma comment(lib, "WinMM")
#pragma comment(lib, "Imm32")
// 窗口句柄
HWND hWnd;
// 游戏运行状态
auto isRunning = true;
// 游戏线程精度
const auto PROID = 1U;
// 游戏帧率
const auto FPS = 60;
// 游戏分辨率
const auto WIDTH = 800, HEIGTH = 600;
// 窗口输入法句柄(以便需要时启用输入法)
HIMC hImc;
// 定义游戏窗口
const struct DLGTEMPLATEEX
{
::DLGTEMPLATE Dlg;
::WCHAR Menu;
::WCHAR Class;
::WCHAR Title;
} DT = {
WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU | DS_CENTER
, WS_EX_APPWINDOW, 0, 0, 0, WIDTH >> 1, HEIGTH >> 1};
// 游戏窗口回调
INT_PTR CALLBACK MainProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
// 游戏线程(处理游戏逻辑)
TIMECALLBACK MainGame;
// 主线程(处理窗口消息)
INT APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, INT nShowCmd)
{
return DialogBoxIndirect(hInstance, &DT.Dlg, HWND_DESKTOP, MainProc);
}
INT_PTR CALLBACK MainProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
// 防止游戏窗口受显示参数影响
DefWindowProc(::hWnd = hWnd, WM_SYSCOMMAND, SC_RESTORE, NULL);
// 禁用输入法
hImc = ImmAssociateContext(hWnd, nullptr);
// 创建游戏线程
timeSetEvent(PROID, PROID, MainGame, GetCurrentThreadId(), TIME_ONESHOT);
break;
case WM_CLOSE:
// 结束对话框
EndDialog(hWnd, EXIT_SUCCESS);
// 判断游戏循环是否已经退出
if (isRunning)
{
// 通知游戏线程退出
isRunning = false;
// 等待游戏线程退出
SuspendThread(GetCurrentThread());
}
break;
case WM_SYSCOMMAND:
switch (LOWORD(wParam))
{
// 拦截Alt菜单
case SC_KEYMENU:
// 拦截屏保
case SC_SCREENSAVE:
// 拦截黑屏
case SC_MONITORPOWER:
break;
default:
return FALSE;
}
break;
// 屏蔽窗口客户群刷新
case WM_ERASEBKGND:
break;
default:
return FALSE;
}
return TRUE;
}
bool InitGame();
bool UpdataGame();
void ExitGame();
void CALLBACK MainGame(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
{
LARGE_INTEGER cur, old, fre;
LONGLONG frame = 1LL;
// 提高游戏线程优先级
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
// 游戏初始化
InitGame();
QueryPerformanceFrequency(&fre);
QueryPerformanceCounter(&old);
// 游戏循环
while (isRunning)
{
QueryPerformanceCounter(&cur);
if ((cur.QuadPart - old.QuadPart) * FPS >= fre.QuadPart * frame)
{
++frame;
// 更新游戏
if (UpdataGame())
{
PostMessage(hWnd, WM_CLOSE, NULL, NULL);
break;
}
// 让出CPU给其它线程
SwitchToThread();
continue;
}
// 延时并降低等待更新的CPU占用
Sleep(PROID);
}
// 结束游戏
ExitGame();
HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, dwUser);
isRunning = false;
ResumeThread(hThread);
CloseHandle(hThread);
}
HDC hDC, hBufDC;
//DWORD dwTime;
bool InitGame()
{
// 创建缓冲区
hDC = GetDC(hWnd);
hBufDC = CreateCompatibleDC(nullptr);
HBITMAP hBmp = CreateCompatibleBitmap(hDC, WIDTH, HEIGTH);
SelectObject(hBufDC, hBmp);
DeleteObject(hBmp);
PatBlt(hDC, 0, 0, WIDTH, HEIGTH, BLACKNESS);
//dwTime = timeGetTime();
return{};
}
bool UpdataGame()
{
//TCHAR str[100];
//static int i = {};
//DWORD dt = timeGetTime();
//int len = _stprintf(str, TEXT("time: %lf, frame: %d, fps: %lf"), ++i / double(FPS), i, i * 1000 / double(dt - dwTime) + .005);
//TextOut(hBufDC, 100, 100, str, len);
// 刷新缓冲区到窗口
BitBlt(hDC, 0, 0, WIDTH, HEIGTH, hBufDC, 0, 0, SRCCOPY);
// 按Esc退出
return GetAsyncKeyState(VK_ESCAPE) < 0;
}
void ExitGame()
{
DeleteDC(hBufDC);
ReleaseDC(hWnd, hDC);
}
2014年12月20日 17点12分 12
[冷]改变优先级大丈夫?
2014年12月20日 18点12分
回复 白晓生锄禾 :嗯,是啊。
2014年12月21日 05点12分
level 10
不眠梦乡 楼主
@yjryym 嗯嗯,感谢你的代码
我还没有试过,但想问两个问题
// 按Esc退出
return GetAsyncKeyState(VK_ESCAPE) < 0;
之前我也是这样的,但是这样焦点在其他窗口的时候也会检测到,会造成退出的
还有一个,DC需要每次画图的时候重新获得吗,看你的不用的,改变窗口大小对DC没影响是吗,如果是SetWindowsLong后,对DC有影响吗
2014年12月21日 03点12分 14
这个esc写来测试用的,真正的游戏esc要干很多事,DC一次性获取就可以了。
2014年12月21日 05点12分
回复 yjryym :不会有问题的吗,DC都不会变的是吗
2014年12月21日 05点12分
回复 不眠梦乡 :GetDC后不去ReleaseDC当然不会变,GDI又不是DX。
2014年12月21日 05点12分
1