📄 progressdialog.cpp
字号:
/* * * progressdialog.cpp * Copyright (C) 2006 Michael H. Overlin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Contact at poster_printer@yahoo.com * */#include "progressdialog.h"#include "progressdialog_rc.h"#include "dialogwindow.h"#include "gdiutils.h"#include "mathutils.h"#include <mmsystem.h>#include <strsafe.h>#include <process.h>#define TIMER_ID 100#define STATUSUPDATE_TIMER_MS 175#define PROGRESS_RADIOBUTTON_NUMBER 6#define PROGRESS_RADIOBUTTON_FIRST IDC_RADIO_PROGRESS_1#define MAX_STATUS_CCH 128#define WAIT_TIMESLICE_MS 50BOOL ProgressDialogWindow::Status::operator ==(const ProgressDialogWindow::Status& st) const { return memcmp(this, &st, sizeof(*this)) == 0; }BOOL ProgressDialogWindow::Status::operator !=(const ProgressDialogWindow::Status& st) const { return ! (*this == st); }ProgressDialogWindow::ProgressDialogWindow( IN HINSTANCE hinst, IN const tstring& tstrTitle, IN const tstring& tstrJobDescription, IN BOOL bHideCancelButton) : DialogWindow(hinst, IDD_DIALOG_PRINTPROGRESS){ m_bHideCancelButton = bHideCancelButton; m_status.bErrors = FALSE; m_status.bUserCanceled = FALSE; m_status.bAllDone = FALSE; m_statusOld = m_status; m_tstrTitle = tstrTitle; m_tstrJobDescription = tstrJobDescription; m_hNewThread = NULL; this->SetAutoDelete(FALSE);}ProgressDialogWindow::~ProgressDialogWindow() { if (m_hNewThread != NULL) { while( ::WaitForSingleObject(m_hNewThread, WAIT_TIMESLICE_MS) == WAIT_TIMEOUT ) { // IN ORDER FOR MODAL DIALOG TO TERMINATE, IT MAY HAVE TO ENABLE WINDOWS IN THE CURRENT THREAD // W/O THIS LOOP DEADLOCK RESULTS MSG msg; if (PeekMessage(&msg, (HWND) NULL, 0, 0, PM_REMOVE)) { if ( ! ::DialogWindow::TheirIsDialogMessage(msg) ) { TranslateMessage(&msg); DispatchMessage(&msg); } } } }}ProgressDialogWindow::Status ProgressDialogWindow::GetStatus(void) { ProgressDialogWindow::Status retValue; Lock(); __try { retValue = m_status; } __finally { UnLock(); } return retValue;}void ProgressDialogWindow::SetStatus(const ProgressDialogWindow::Status& status) { ProgressDialogWindow::Status statusBuff; Lock(); __try { statusBuff = m_status; } __finally { UnLock(); } if (statusBuff != status) { Lock(); __try { m_status = status; } __finally { UnLock(); } if (status.bAllDone) { this->CenterWindowAboveParent(); this->ShowWindow(SW_NORMAL); //::Beep(500, 100); ::PlaySound(TEXT("SystemAsterisk"), NULL, SND_ASYNC); // MAKE USER HIT OK BUTTON ANYWAY //if (status.bUserCanceled) { // this->EndDialog(0); //} } }}tstring ProgressDialogWindow::GetStatusString(void) { tstring retValue; Lock(); try { retValue = m_tstrStatus; } catch(...) { UnLock(); throw; } UnLock(); return retValue;}void ProgressDialogWindow::SetStatusString(const tstring& tstrStatus) { Lock(); __try { m_tstrStatus = tstrStatus; } __finally { UnLock(); }}BOOL ProgressDialogWindow::DoNewThreadModalDialog(HWND hwndParent) { ASSERT(m_hNewThread == NULL); m_hwndDialogParent = hwndParent; m_hNewThread = (HANDLE) ::_beginthread( ProgressDialogWindow::TheirThreadProc, 0, this); BOOL bRetValue = (m_hNewThread != NULL); return bRetValue;}//INT_PTR ProgressDialogWindow::GetDialogResultCode(void) {// INT_PTR resultCode;// Lock();// __try {// resultCode = m_DialogResultCode;// } __finally {// UnLock();// }// return resultCode;//}// ****// **** private: class ProgressDialogWindow// ****void ProgressDialogWindow::AnimateProgressRadioButtons(void) { Lock(); __try { BOOL bFound = FALSE; for(uint ui = 0; ui < PROGRESS_RADIOBUTTON_NUMBER; ++ui) { if (this->IsDlgButtonChecked(ui + PROGRESS_RADIOBUTTON_FIRST)) { uint uiCheck = (ui + 1) % PROGRESS_RADIOBUTTON_NUMBER; this->CheckDlgButton(ui + PROGRESS_RADIOBUTTON_FIRST, FALSE); this->CheckDlgButton(uiCheck + PROGRESS_RADIOBUTTON_FIRST, TRUE); bFound = TRUE; break; } } if (!bFound) { this->CheckDlgButton(PROGRESS_RADIOBUTTON_FIRST, TRUE); } } __finally { UnLock(); }}void ProgressDialogWindow::CheckAllProgressRadioButtons(void) { Lock(); __try { for(uint ui = 0; ui < PROGRESS_RADIOBUTTON_NUMBER; ++ui) { if (!this->IsDlgButtonChecked(ui + PROGRESS_RADIOBUTTON_FIRST)) { this->CheckDlgButton(ui + PROGRESS_RADIOBUTTON_FIRST, TRUE); } } } __finally { UnLock(); }}HWND ProgressDialogWindow::GetDialogParent(void) { HWND hwndParent; Lock(); __try { hwndParent = m_hwndDialogParent; } __finally { UnLock(); } return hwndParent;}void ProgressDialogWindow::DoStatusTick(void) { tstring tstrStatus, tstrOldStatus; Status status, statusOld; Lock(); try { tstrOldStatus = m_tstrOldStatus; tstrStatus = m_tstrOldStatus = m_tstrStatus; statusOld = m_statusOld; status = m_statusOld = m_status; } catch(...) { UnLock(); throw; } UnLock(); if (tstrOldStatus != tstrStatus || statusOld != status) { tstring tstrTemp; tstrTemp = tstrStatus; if (status.bAllDone) { tstrTemp += TEXT("\nDONE."); } this->SetDlgItemText(IDC_STATIC_PRINT_PROGRESS, tstrTemp.c_str()); } if (! status.bAllDone) { // DEBUG / FIX: KILL TIMER WHEN ALL DONE? this->AnimateProgressRadioButtons(); } else { this->CheckAllProgressRadioButtons(); HWND hwndDismiss = this->GetDlgItem(IDC_BUTTON_DISMISS); // 7/12 ::CenterWindowHorizontallyInDialog(hwndDismiss, this->hdlg()); ::SetWindowText(hwndDismiss, TEXT("OK")); //RECT rDlg; //::GetClientRect(this->hdlg(), &rDlg); //RECT rButton; //::GetWindowRect(hwndDismiss, &rButton); //::ScreenToClient(rButton, this->hdlg()); //RECT rTemp = rButton; //::CenterInRect(rTemp, rDlg); //::MoveWindow(hwndDismiss, rTemp.left, rButton.top, RW(rButton), RH(rButton), TRUE); ::ShowWindow(hwndDismiss, SW_SHOW); this->SetHasSystemMenu(TRUE); } //Lock(); //try { // if (m_tstrOldStatus != m_tstrStatus || m_statusOld != m_status) { // m_tstrOldStatus = m_tstrStatus; // m_statusOld = m_status; // tstring tstrTemp; // tstrTemp = m_tstrStatus; // if (m_status.bAllDone) { // tstrTemp += TEXT("\n\nDONE."); // } // this->SetDlgItemText(IDC_STATIC_PRINT_PROGRESS, tstrTemp.c_str()); // } // if (! m_status.bAllDone) { // DEBUG / FIX: KILL TIMER WHEN ALL DONE? // this->AnimateProgressRadioButtons(); // } else { // this->CheckAllProgressRadioButtons(); // this->SetDlgItemTextW(IDC_BUTTON_DISMISS, TEXT("OK")); // } //} catch(...) { // UnLock(); // throw; //} //UnLock();}void ProgressDialogWindow::SetDialogResultCode(INT_PTR resultCode) { Lock(); __try { m_DialogResultCode = resultCode; } __finally { UnLock(); }}BOOL ProgressDialogWindow::InitMsg(WPARAM wParam, LPARAM lParam) { DialogWindow::InitMsg(wParam, lParam); BOOL bHideCancelButton; tstring tstrTitle, tstrJobDescription, tstrStatus; Lock(); try { bHideCancelButton = m_bHideCancelButton; tstrTitle = m_tstrTitle; tstrJobDescription = m_tstrJobDescription; tstrStatus = m_tstrStatus; } catch(...) { UnLock(); throw; } UnLock(); this->CenterWindowAboveParent(); this->SetWindowText(tstrTitle.c_str()); this->SetDlgItemText(IDC_STATIC_PRINT_JOB_DESCRIPTION, tstrJobDescription.c_str()); this->SetDlgItemText(IDC_BUTTON_DISMISS, TEXT("Cancel")); this->SetDlgItemText(IDC_STATIC_PRINT_PROGRESS, tstrStatus.c_str()); this->SetTimer(TIMER_ID, STATUSUPDATE_TIMER_MS); if (bHideCancelButton) { HWND hwndDismiss = this->GetDlgItem(IDC_BUTTON_DISMISS); ::ShowWindow(hwndDismiss, SW_HIDE); this->SetHasSystemMenu(FALSE); } return TRUE;}BOOL ProgressDialogWindow::CommandMsg(WPARAM wParam, LPARAM lParam) { Status status; Lock(); __try { status = m_status; } __finally { UnLock(); } BOOL bRetValue = FALSE; WORD wID = LOWORD(wParam); switch(wID) { case IDC_BUTTON_DISMISS: if (status.bAllDone) { //this->DestroyWindow(); this->EndDialog(0); } else { status.bUserCanceled = TRUE; status.bErrors = TRUE; Lock(); __try { m_status = status; } __finally { UnLock(); } } bRetValue = TRUE; break; default: break; } return bRetValue;}BOOL ProgressDialogWindow::CommonControlColorNotifyMsg(UINT msg, WPARAM wParam, LPARAM lParam) { Status status; Lock(); __try { status = m_status; } __finally { UnLock(); } static BOOL bSkipRecursion = FALSE; BOOL bRetValue = FALSE; // I WANT TO CALL THE DEFDLGPROC TO GET THE BACKGROUND BRUSH // BUT I WANT TO SET THE TEXT COLOR switch(msg) { case WM_CTLCOLORSTATIC: if (!bSkipRecursion) { if (status.bErrors) { HWND hwndControl = (HWND) lParam; int iCtrlID = ::GetDlgCtrlID(hwndControl); if (iCtrlID == IDC_STATIC_PRINT_PROGRESS) { HDC hdc = (HDC) wParam; // DEBUG-FIX : THIS CODE HAS TO BE EXPLICITLY TESTED AT SOME POINT, IM NOT SURE THIS WILL WORK // AVOID INFINITE RECURSIVE LOOP HERE - CALLING DEFDLGPROC RECURSES INTO THIS ROUTINE bSkipRecursion = TRUE; LRESULT lres = ::CallWindowProc(::DefDlgProc, this->hdlg(), WM_CTLCOLORSTATIC, wParam, lParam); bSkipRecursion = FALSE; bRetValue = (BOOL) lres; // RED TEXT COLOR FOR FAILURE CONDITION ::SetTextColor(hdc, RGB(0xff, 0, 0)); } } } break; default: break; } return bRetValue;}BOOL ProgressDialogWindow::NotificationMsg(UINT msg, WPARAM wParam, LPARAM lParam) { BOOL bRetValue = FALSE; switch(msg) { case WM_CLOSE: this->SendMessage(WM_COMMAND, (WPARAM) IDC_BUTTON_DISMISS, 0); bRetValue = TRUE; break; default: break; } return bRetValue;}BOOL ProgressDialogWindow::TimerMsg(WPARAM wParam, LPARAM lParam) { BOOL bRetValue = FALSE; switch(wParam) { case TIMER_ID: { this->DoStatusTick(); bRetValue = TRUE; } break; default: break; } return bRetValue;}void __cdecl ProgressDialogWindow::TheirThreadProc(void *pv) { ProgressDialogWindow *pdw = (ProgressDialogWindow *) pv; HWND hwndParent = pdw->GetDialogParent(); INT_PTR resultCode = pdw->DoModalDialog(hwndParent); pdw->SetDialogResultCode(resultCode);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -