北京时间16点43分 2018年12月28号
前面的文章完成了双击播放列表播放文件以及播放时的时间轴显示,这次将实现全屏显示以及按钮函数的实现。
对于全屏显示,想法是处理PICTURE控件的双击显示消息函数,但是发现在添加处理函数后,双击后程序并不响应消息函数。
后来发现是libvlc自己就拦截处理了播放时控件双击函数,所以我们写的程序才没有响应。
所以,想要实现双击全屏有两种方法:
这里面讲到的是添加一个定时器和回调。
1)在MFC对话框程序中,首先添加一个控件,这里我添加了一个Picture Contron:IDC_PLAYWND;
2)获得IDC_PLAYWND控件句柄;
1 | gPlayHwnd = GetDlgItem(IDC_PLAYWND)->GetSafeHwnd(); |
3)让libVLC播放对象设置gPlayHwnd 为播放窗口句柄,这样libVLC播放窗口就成为IDC_PLAYWND控件的子窗口;
1 | libvlc_media_player_set_hwnd (mp, gPlayHwnd ); |
4)开始播放后创建一个定时器;
C++
1 | ::SetTimer(NULL, 1, 1000, TimeProc); |
5)定时器回调函数以及处理过程如下:
C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | //定时器回调 void CALLBACK TimeProc( HWND hwnd, UINT message, UINT idTimer, DWORD dwTime) { EnumChildWindows(gPlayHwnd, EnumerateVLC, NULL); } BOOL CALLBACK EnumerateVLC(HWND hWndvlc, LPARAM lParam) { TCHAR szWndTitle[1024]; int nLen = GetWindowText(hWndvlc, szWndTitle, 1024); if (0 != nLen) { //禁用鼠标消息 EnableWindow(hWndvlc, FALSE); KillTimer(NULL, 1); }
return TRUE; } |
在上述代码中,我们通过之前得到的IDC_PLAYWND控件句柄枚举得到子窗口VLC播放窗口句柄,接着通过EnableWindow函数禁止VLC播放窗口接受鼠标键盘输入。这时我们的程序就可以响应鼠标点击libVLC播放窗口的消息了;
6)设置全屏,主要是设置IDC_PLAYWND控件全屏时占满整个屏幕,然后隐藏其他控件以及标题栏,这样VLC子窗口就可以全屏播放了。不需要使用libvlc_set_fullscreen这个内置api,使用这个api无法达到效果。
2、第二种方法就是在vlclib处理拦截双击信息之前,我们添加处理函数PreTranslateMessage,拦截信息。
添加相应的函数,流程大概就是接受到双击的消息后,判断是不是在播放的PICTURE控件上,如果是,则执行全屏的函数OnDblclkPlay();如果不在PICTURE控件上,则不做处理。
BOOL CVlcPlayerCsdnDlg::PreTranslateMessage(MSG* pMsg)
{
//双击放大整个屏幕
if (pMsg->message == WM_LBUTTONDBLCLK) //只要接收到双击就放大屏幕
{
CRect rect;
GetDlgItem(IDC_PLAY)->GetWindowRect(rect);
//ScreenToClient(rect);
if (rect.PtInRect(pMsg->pt))
OnDblclkPlay();
}
//屏蔽ESC按键的退出机制,因为一般的对话框程序一按到ESC就退出了
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE)
{
if (bFullScreen)//如果是全屏状态下,不退出。而是退出全屏
{
OnDblclkPlay();
return TRUE;
}
else
return TRUE;
}
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN)
return TRUE;
return CDialogEx::PreTranslateMessage(pMsg);
}
OnDblclkPlay是全屏显示的函数,全屏的函数首先是放大整个对话框,隐藏其他的控件和标题栏后,放大PICTURE控件,它的定义为:
void CVlcPlayerCsdnDlg::OnDblclkPlay()
{
if (!bFullScreen)
{
//播放列表在全屏时出错处理
if (m_listPlay.IsWindowVisible()) isshowlist = TRUE;
else isshowlist = FALSE;
bFullScreen = true;
//获取系统屏幕宽高
int g_iCurScreenWidth = GetSystemMetrics(SM_CXSCREEN);
int g_iCurScreenHeight = GetSystemMetrics(SM_CYSCREEN);
//用m_struOldWndpl得到当前窗口的显示状态和窗体位置,以供退出全屏后使用
GetWindowPlacement(&m_struOldWndpl);
GetDlgItem(IDC_PLAY)->GetWindowPlacement(&m_struOldWndpPic);
//计算出窗口全屏显示客户端所应该设置的窗口大小,主要为了将不需要显示的窗体边框等部分排除在屏幕外
CRect rectWholeDlg;
CRect rectClient;
GetWindowRect(&rectWholeDlg);//得到当前窗体的总的相对于屏幕的坐标
RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposQuery, &rectClient);//得到客户区窗口坐标
ClientToScreen(&rectClient);//将客户区相对窗体的坐标转为相对屏幕坐标
//GetDlgItem(IDC_STATIC_PICSHOW)->GetWindowRect(rectClient);//得到PICTURE控件坐标
rectFullScreen.left = rectWholeDlg.left - rectClient.left;
rectFullScreen.top = rectWholeDlg.top - rectClient.top;
rectFullScreen.right = rectWholeDlg.right + g_iCurScreenWidth - rectClient.right;
rectFullScreen.bottom = rectWholeDlg.bottom + g_iCurScreenHeight - rectClient.bottom;
//设置窗口对象参数,为全屏做好准备并进入全屏状态
WINDOWPLACEMENT struWndpl;
struWndpl.length = sizeof(WINDOWPLACEMENT);
struWndpl.flags = 0;
struWndpl.showCmd = SW_SHOWNORMAL;
struWndpl.rcNormalPosition = rectFullScreen;
SetWindowPlacement(&struWndpl);//该函数设置指定窗口的显示状态和显示大小位置等,是我们该程序最为重要的函数
GetDlgItem(IDC_BUTTON_UP)->ShowWindow(FALSE);
GetDlgItem(IDC_BUTTON_PLAY)->ShowWindow(FALSE);
GetDlgItem(IDC_BUTTON_DOWN)->ShowWindow(FALSE);
GetDlgItem(IDC_BUTTON_FORWARD)->ShowWindow(FALSE);
GetDlgItem(IDC_BUTTON_BACKWARD)->ShowWindow(FALSE);
GetDlgItem(IDC_BUTTON_SHOWLIST)->ShowWindow(FALSE);
GetDlgItem(IDC_LIST_PLAY)->ShowWindow(FALSE);
GetDlgItem(IDC_SLIDER1)->ShowWindow(FALSE);
GetDlgItem(IDC_STATIC)->ShowWindow(FALSE);
GetDlgItem(IDC_LIST_MUSINFO)->ShowWindow(FALSE);
//将PICTURE控件的坐标设为全屏大小
GetDlgItem(IDC_PLAY)->MoveWindow(CRect(0, 0, g_iCurScreenWidth, g_iCurScreenHeight));
}
else
{
GetDlgItem(IDC_PLAY)->SetWindowPlacement(&m_struOldWndpPic);
SetWindowPlacement(&m_struOldWndpl);
bFullScreen = false;
GetDlgItem(IDC_BUTTON_UP)->ShowWindow(TRUE);
GetDlgItem(IDC_BUTTON_PLAY)->ShowWindow(TRUE);
GetDlgItem(IDC_BUTTON_DOWN)->ShowWindow(TRUE);
GetDlgItem(IDC_BUTTON_FORWARD)->ShowWindow(TRUE);
GetDlgItem(IDC_BUTTON_BACKWARD)->ShowWindow(TRUE);
GetDlgItem(IDC_BUTTON_SHOWLIST)->ShowWindow(TRUE);
GetDlgItem(IDC_SLIDER1)->ShowWindow(TRUE);
GetDlgItem(IDC_STATIC)->ShowWindow(TRUE);
if (isshowlist == TRUE)
{
GetDlgItem(IDC_LIST_PLAY)->ShowWindow(TRUE);
GetDlgItem(IDC_LIST_MUSINFO)->ShowWindow(TRUE);
}
else
{
GetDlgItem(IDC_LIST_MUSINFO)->ShowWindow(FALSE);
GetDlgItem(IDC_LIST_PLAY)->ShowWindow(FALSE);
}
}
}
这两个函数用到的变量定义有:
BOOL bFullScreen;
CRect rectFullScreen;
WINDOWPLACEMENT m_struOldWndpl;//结构中包含了有关窗口在屏幕上位置的信息
WINDOWPLACEMENT m_struOldWndpPic;//PICTURE控件在屏幕上位置的信息
BOOL isshowlist;//列表是否显示了
运行,效果如下(图一正常情况,图二为放大后):
好啦,全屏显示的代码就这样啦,接下来就是按钮的实现了。直接为那六个按钮添加消息处理函数,然后代码如下:
void CVlcPlayerCsdnDlg::OnBnClickedButtonPlay() //播放按钮
{
if (!m_cAVPlayer.IsOpen())
{
return;
}
if (m_cAVPlayer.IsPlaying())
{
m_cAVPlayer.Pause();
}
else
{
m_cAVPlayer.Play();
}
}
void CVlcPlayerCsdnDlg::OnBnClickedButtonUp() //上一集按钮
{
int nIndex = m_listPlay.GetCurSel();
if (LB_ERR == nIndex)
{
return;
}
if (nIndex - 1 < 0)
{
nIndex = m_listPlay.GetCount();
}
m_listPlay.SetCurSel(nIndex - 1);
OnDblclkListPlay();
}
void CVlcPlayerCsdnDlg::OnBnClickedButtonDown() //下一集按钮
{
int nIndex = m_listPlay.GetCurSel();
if (LB_ERR == nIndex)
{
return;
}
if (nIndex + 1 >= m_listPlay.GetCount())
{
nIndex = -1;
}
m_listPlay.SetCurSel(nIndex + 1);
OnDblclkListPlay();
}
void CVlcPlayerCsdnDlg::OnBnClickedButtonForward() //快进
{
m_cAVPlayer.SeekBackward();
}
void CVlcPlayerCsdnDlg::OnBnClickedButtonBackward() //快退
{
m_cAVPlayer.SeekForward();
}
void CVlcPlayerCsdnDlg::OnBnClickedButtonShowlist() //显示播放列表按钮
{
ShowPlaylist(!m_listPlay.IsWindowVisible());
}
好啦,现在基本的完成啦,这里有源码下载地址。大家如果觉得在播放音频文件时PICTURE控件为空,可以再播放一个gif动画,在这里我就只上传源码(下载地址——mp3显示gif动画、系统有菜单栏)。
注意:1、本人是萌新,大佬们可以直接跳过阅读我的文章,写这个目的就是为了赚点分数以后可以用,当然也是想和其他萌新一起学习。
2、我会尽力快点更新,如果有什么问题大家可以在底下评论,我看到便会回复的,我的个人邮箱
3、每一期我都会尽量放上源代码,希望能帮到大家的学习。