www.gusucode.com > 多线程抽签VC++源码实现-源码程序 > 多线程抽签VC++源码实现-源码程序\code\ShakeDlg.cpp
//Download by http://www.NewXing.com // ShakeDlg.cpp : implementation file // #include "stdafx.h" #include "Shake Your Name.h" #include "ShakeDlg.h" #include <mmsystem.h> #pragma comment(lib,"winmm.lib") #include "StatLink.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CAboutDlg dialog used for App About class CAboutDlg : public CDialog { public: CAboutDlg(); protected: CStaticLink m_wndLink1; CStaticLink m_wndLink2; CStaticLink m_wndLink3; CStaticLink m_wndLink4; // Dialog Data //{{AFX_DATA(CAboutDlg) enum { IDD = IDD_ABOUTBOX }; //}}AFX_DATA // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CAboutDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: //{{AFX_MSG(CAboutDlg) virtual BOOL OnInitDialog(); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { //{{AFX_DATA_INIT(CAboutDlg) //}}AFX_DATA_INIT } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CAboutDlg) //}}AFX_DATA_MAP } BOOL CAboutDlg::OnInitDialog() { CDialog::OnInitDialog(); // TODO: Add extra initialization here m_wndLink1.m_link = _T("tencent://message/?uin=137571735"); m_wndLink2.m_link = _T("mailto:lusta@live.cn"); m_wndLink3.m_link = _T("http://hi.baidu.com/lustaone/"); m_wndLink4.m_link = _T("http://hi.baidu.com/lustaone/"); m_wndLink1.SubclassDlgItem(IDC_STATIC_QQ, this); m_wndLink2.SubclassDlgItem(IDC_STATIC_EMAIL, this); m_wndLink3.SubclassDlgItem(IDC_STATIC_SPACE, this); m_wndLink4.SubclassDlgItem(IDC_STATIC_PHOTO, this); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) //{{AFX_MSG_MAP(CAboutDlg) // No message handlers //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CShakeDlg dialog CShakeDlg::CShakeDlg(CWnd* pParent /*=NULL*/) : CDialog(CShakeDlg::IDD, pParent) { //{{AFX_DATA_INIT(CShakeDlg) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); m_bShaking = FALSE; m_bDataIsRead = FALSE; m_hShake = NULL; m_hRoll = NULL; m_hCursor = NULL; } void CShakeDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CShakeDlg) // NOTE: the ClassWizard will add DDX and DDV calls here //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CShakeDlg, CDialog) //{{AFX_MSG_MAP(CShakeDlg) ON_WM_SYSCOMMAND() ON_WM_DESTROY() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(ID_BTN_READLIST, OnBtnReadList) ON_BN_CLICKED(ID_BTN_SHAKE, OnBtnStart) ON_WM_LBUTTONDOWN() ON_BN_CLICKED(IDC_BUTTON_SHOWBOX, OnBtnShowBox) ON_WM_SETCURSOR() ON_BN_CLICKED(ID_HELP, OnHelp) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CShakeDlg message handlers BOOL CShakeDlg::OnInitDialog() { CDialog::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here CStdioFile csf; CString strPath; CString strTemp; if (csf.Open("list.txt",CFile::modeRead,NULL)) { strPath = csf.GetFilePath(); goto read; } else if(csf.Open("List.txt",CFile::modeRead,NULL)) { strPath = csf.GetFilePath(); goto read; } else if (csf.Open("list",CFile::modeRead,NULL)) { strPath = csf.GetFilePath(); goto read; } else { MessageBox("软件目录下不存在列表文件list.txt. 请手动载入或放置到软件目录下", "提示",MB_ICONASTERISK); GetDlgItem(IDC_BUTTON_SHOWBOX)->SetWindowText("列表: 空(点击载入)"); m_bDataIsRead = FALSE; return FALSE; } read: while(csf.ReadString(strTemp)) m_sList.AddTail((LPCTSTR)strTemp); m_bDataIsRead = TRUE; GetDlgItem(IDC_BUTTON_SHOWBOX)->SetWindowText("列表: 已经载入(点击查看)"); ShowLoadedData(csf.GetFilePath()); return TRUE; // return TRUE unless you set the focus to a control } void CShakeDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } } void CShakeDlg::OnDestroy() { WinHelp(0L, HELP_QUIT); if (m_hShake) ::TerminateThread(m_hShake,0); if(m_hRoll) ::TerminateThread(m_hRoll,0); CAboutDlg dlg; dlg.DoModal(); CDialog::OnDestroy(); } // If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void CShakeDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } HCURSOR CShakeDlg::OnQueryDragIcon() { return (HCURSOR) m_hIcon; } void CShakeDlg::OnBtnReadList() { // TODO: Add your control notification handler code here CFileDialog dlg(TRUE); dlg.m_ofn.lpstrTitle="读取列表文件"; dlg.m_ofn.lpstrFilter="文本文档(*.txt)\0*.txt\0所有类型(*.*)\0*.*\0\0"; if(IDOK==dlg.DoModal()) { m_sList.RemoveAll(); CString strTemp; CStdioFile csf; if (csf.Open(dlg.GetPathName(),CFile::modeRead,NULL)) { while(csf.ReadString(strTemp)) m_sList.AddTail((LPCTSTR)strTemp); m_bDataIsRead = TRUE; GetDlgItem(IDC_BUTTON_SHOWBOX)->SetWindowText("列表: 已经载入(点击查看)"); ShowLoadedData(csf.GetFilePath()); } } } void CShakeDlg::OnBtnStart() { // TODO: Add your control notification handler code here if (m_bShaking) return; if (!m_bDataIsRead) { MessageBox("列表尚未读取,请先手动载入","提示",MB_OK); return; } m_hShake = ::CreateThread(NULL,0,ShakeThreadProc,NULL,0,NULL); m_hRoll = ::CreateThread(NULL,0,RollThreadProc,NULL,0,NULL); if (m_hShake && m_hRoll) m_bShaking = TRUE; GetDlgItem(ID_BTN_READLIST)->EnableWindow(FALSE); GetDlgItem(IDCANCEL)->EnableWindow(FALSE); } void CShakeDlg::ShowLoadedData(CString dataResause) { if (!m_bDataIsRead) return; CString readResult; readResult.Empty(); readResult += "列表数据来源及详细信息如下:\n"; readResult += dataResause; readResult +="\n\n"; POSITION position; position = m_sList.GetHeadPosition(); while(position) { // AfxMessageBox(m_sList.GetNext(position)); readResult += m_sList.GetNext(position); readResult += "\n"; } MessageBox(readResult,"列表读取结果",MB_ICONASTERISK); } DWORD WINAPI CShakeDlg::ShakeThreadProc(LPVOID lpParameter) {//在这个程序中,抖动线程的结束时间有不确定性,所以不保证抖动结束的窗口位置是原始位置 // PlaySound(MAKEINTRESOURCE(IDR_WAVE_SHAKE),AfxGetResourceHandle(),SND_ASYNC|SND_RESOURCE); CShakeApp* pApp = (CShakeApp*)AfxGetApp(); CShakeDlg *pShakeDlg = (CShakeDlg *)pApp->GetMainWnd(); if(!(pShakeDlg->m_bDataIsRead)) return 0; CPoint CurrentPos; CRect rect; pShakeDlg->GetClientRect(&rect); pShakeDlg->ClientToScreen(&rect); CurrentPos.x = rect.left; CurrentPos.y = rect.top; int FrameWidth; int FrameHight; int CaptionHight; //我当前系统设置上这三个值分别为3,3,22 FrameWidth = GetSystemMetrics(SM_CXFIXEDFRAME); FrameHight = GetSystemMetrics(SM_CYFIXEDFRAME); CaptionHight = GetSystemMetrics(SM_CYCAPTION); //这里需要将CurrentPos坐标offset()到主窗口左上角坐标 CurrentPos.Offset(-FrameWidth, -CaptionHight-FrameHight); //实现抖动: 半个小圈 + 三个大圈 + 半个小圈 pShakeDlg->SetWindowPos(&wndTopMost,CurrentPos.x-1,CurrentPos.y-2,0,0, SWP_NOSIZE); Sleep(10);//上面的SWP_NOSIZE参数忽略cx,cy,故可置0 pShakeDlg->SetWindowPos(&wndTopMost,CurrentPos.x-4,CurrentPos.y-4,0,0, SWP_NOSIZE); Sleep(10); pShakeDlg->SetWindowPos(&wndTopMost,CurrentPos.x-7,CurrentPos.y-2,0,0, SWP_NOSIZE); Sleep(10); pShakeDlg->SetWindowPos(&wndTopMost,CurrentPos.x-8,CurrentPos.y,0,0, SWP_NOSIZE); Sleep(10); int i = 0;// Circling number you want for (;;i++) // Not setting it means shaking forever. { pShakeDlg->SetWindowPos(&wndTopMost,CurrentPos.x-6,CurrentPos.y+6,0,0, SWP_NOSIZE); Sleep(10); pShakeDlg->SetWindowPos(&wndTopMost,CurrentPos.x,CurrentPos.y+8,0,0, SWP_NOSIZE); Sleep(10); pShakeDlg->SetWindowPos(&wndTopMost,CurrentPos.x+6,CurrentPos.y+6,0,0, SWP_NOSIZE); Sleep(10); pShakeDlg->SetWindowPos(&wndTopMost,CurrentPos.x+8,CurrentPos.y,0,0, SWP_NOSIZE); Sleep(10); pShakeDlg->SetWindowPos(&wndTopMost,CurrentPos.x+6,CurrentPos.y-6,0,0, SWP_NOSIZE); Sleep(10); pShakeDlg->SetWindowPos(&wndTopMost,CurrentPos.x,CurrentPos.y-8,0,0, SWP_NOSIZE); Sleep(10); pShakeDlg->SetWindowPos(&wndTopMost,CurrentPos.x-6,CurrentPos.y-6,0,0, SWP_NOSIZE); Sleep(10); pShakeDlg->SetWindowPos(&wndTopMost,CurrentPos.x-8,CurrentPos.y,0,0, SWP_NOSIZE); Sleep(10); } pShakeDlg->SetWindowPos(&wndTopMost,CurrentPos.x-7,CurrentPos.y+2,0,0, SWP_NOSIZE); Sleep(10); pShakeDlg->SetWindowPos(&wndTopMost,CurrentPos.x-4,CurrentPos.y+4,0,0, SWP_NOSIZE); Sleep(10); pShakeDlg->SetWindowPos(&wndTopMost,CurrentPos.x-1,CurrentPos.y+2,0,0, SWP_NOSIZE); Sleep(10); pShakeDlg->SetWindowPos(&wndTopMost,CurrentPos.x,CurrentPos.y,0,0, SWP_NOSIZE); return 0; } DWORD WINAPI CShakeDlg::RollThreadProc(LPVOID lpParameter) { CShakeApp* pApp = (CShakeApp*)AfxGetApp(); CShakeDlg *pShakeDlg = (CShakeDlg *)pApp->GetMainWnd(); if(!(pShakeDlg->m_bDataIsRead)) return 0; POSITION position; CString strShow; position = pShakeDlg->m_sList.GetHeadPosition(); while(TRUE) { position = pShakeDlg->m_sList.GetHeadPosition(); while(position) { strShow = pShakeDlg->m_sList.GetNext(position); pShakeDlg->SetDlgItemText(IDC_BUTTON_SHOWBOX,strShow); ::Sleep(100); } } return 0; } void CShakeDlg::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default if (m_hShake) { ::TerminateThread(m_hShake,0); m_hShake = NULL; } if(m_hRoll) { ::TerminateThread(m_hRoll,0); m_hRoll = NULL; } if (!m_hRoll && !m_hShake) { GetDlgItem(ID_BTN_READLIST)->EnableWindow(TRUE); GetDlgItem(IDCANCEL)->EnableWindow(TRUE); m_bShaking = FALSE; } CDialog::OnLButtonDown(nFlags, point); } void CShakeDlg::OnBtnShowBox() { // TODO: Add your control notification handler code here if (m_bDataIsRead) { ShowLoadedData(""); } else { OnBtnReadList(); } } BOOL CShakeDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) { // TODO: Add your message handler code here and/or call default if (m_bDataIsRead && m_bShaking) { CString windir; GetWindowsDirectory(windir.GetBuffer(MAX_PATH), MAX_PATH); windir.ReleaseBuffer(); windir += _T("\\winhlp32.exe"); HMODULE hModule = LoadLibrary(windir); if (hModule) { m_hCursor = CopyCursor(::LoadCursor(hModule, MAKEINTRESOURCE(106))); } FreeLibrary(hModule); if (m_hCursor) ::SetCursor(m_hCursor); return TRUE; } return CDialog::OnSetCursor(pWnd, nHitTest, message); } void CShakeDlg::OnHelp() { // TODO: Add your control notification handler code here CString str; // str = "CHM格式说明文档正在制作中...完成后将与软件一同发布 "; str = "1. list.txt文件用来存放抽签的列表名字, 该文本必须每行放置一个备选项。\n"; str += " 程序每读取1行则视为一个名字, 所以不建议存在空行。\n\n"; str += "2. 可在启动前将准备好的列表文件放置在该软件同一目录, 或启动后再载入。\n\n"; str += "3. 点击“开始”按钮滚动列表, 鼠标指针变为手型, 此时点击程序主窗口可停止滚动。\n\n"; str += "4. 停止后再次点击“开始”,可重复滚动。"; MessageBox(str,"使用说明",MB_ICONASTERISK); }