Отправляет email-рассылки с помощью сервиса Sendsay

Школа программирования

  Все выпуски  

Школа программирования


Программа waterEyeKeeper (часть 3)

Доброе время суток:)
Вспомним на чем мы остановились в последний раз - это алгоритм.

1. При старте загружаем время между перерывами и время перерыва.
2. Прячем оба окна.
3. Запускаем таймер и счетчик.
4. Как только счетчик становится равен времени между перерывами, сбрасываем счетчик и показываем всплывающее окно.
5. Как только счетчик становится равен времени перерыва, сбрасываем счетчик и закрываем всплывающее окно.

В процессе написания кода, я понял, что упустил одну настройку (а может и не одну:). Это загружать/ не загружать программу при запуске Windows. Поэтому первый пункт алгоритма чуть измениться, и у нас получится:

1. При старте загружаем время между перерывами, время перерыва и признак загрузки при старте Windows.
2. Прячем оба окна.
3. Запускаем таймер и счетчик.
4. Как только счетчик становится равен времени между перерывами, сбрасываем счетчик и показываем всплывающее окно.
5. Как только счетчик становится равен времени перерыва, сбрасываем счетчик и закрываем всплывающее окно.

Постоянное изменение - это жизнь. Да, я понимаю, что людям хочется постоянства:) Не даром у китайцев есть (сам не проверял - слышал) что-то типа плохого пожелания "Чтоб ты жил в эпоху перемен":) Поэтому в этом постоянно меняющемся мире нужно что-то постоянное:) Я предлагаю (в данном случае) завести привычку писать документацию! Да, не откладывать ее написание на последний момент, а прямо сейчас взять и начать писать. В первую очередь для себя (и в не последнюю для пользователей). Т.е. как минимум должно быть два руководства: руководство программиста и руководство пользователя. В первом будем писать про алгоритмы, трудности реализации и т.д. , а во втором, как человек будет работать с программой. Причем документация тоже будет меняться (в процессе написания программы), но привычка должна остаться:)

Итак приступим к реализации алгоритма:) Что у нас по плану? План, кстати, это тоже реализация принципа разделяй и властвуй:) Первым пунктом идет загрузка параметров. Мы будет загружать параметры и сохранять параметры в файле. Программа у нас называется waterEyeKeeper и файл настроек, где будут храниться временные параметры, назовем waterEyeKeeper.ini. Допишем методы LoadSettings() и SaveSettings().

LoadSettings() будем вызывать при загрузке, а SaveSettings() при нажатии на кнопку Применить.

void CWaterEyeKeeperDlg::LoadSettings()
{
    CString _path = GetFilePath() + ".ini";
   
    if (ReadFromIniFile(_path,"Settings","MinutesDelayBetweenRest", m_minutes_delay_between_rest)==false)
        m_minutes_delay_between_rest = 50;

    if (ReadFromIniFile(_path,"Settings","MinutesRestTime", m_minutes_rest_time)==false)
        m_minutes_rest_time = 10;

    if (ReadFromIniFile(_path,"Settings","LoadOnStart", (int&)m_load_on_start)==false)
        m_load_on_start = false;

}
//--------------------------------------------------------------------------
void CWaterEyeKeeperDlg::SaveSettings()
{
    CString _path = GetFilePath() + ".ini";
   
    WriteToIniFile(_path,"Settings","MinutesDelayBetweenRest", m_minutes_delay_between_rest);
    WriteToIniFile(_path,"Settings","MinutesRestTime", m_minutes_rest_time);
    WriteToIniFile(_path,"Settings","LoadOnStart", m_load_on_start);
       
   
}
//--------------------------------------------------------------------------
CString CWaterEyeKeeperDlg::GetFilePath()
{
    TCHAR sFilename[_MAX_PATH];
    TCHAR sDrive[_MAX_DRIVE];
    TCHAR sDir[_MAX_DIR];
    TCHAR sFname[_MAX_FNAME];
    TCHAR sExt[_MAX_EXT];

    GetModuleFileName(NULL, sFilename, _MAX_PATH);
    _tsplitpath(sFilename, sDrive, sDir, sFname, sExt);
   
   
    return CString(sDrive) + sDir + sFname;
}
//--------------------------------------------------------------------------
bool CWaterEyeKeeperDlg::ReadFromIniFile(CString ini_path, CString section, CString name, int &val)
{
    char lpReturnedString[100];
   
   
    if (GetPrivateProfileString(section,name,"",lpReturnedString,99,ini_path)>=0)
    {
        if (CString(lpReturnedString)=="")
            return false;

        val = atoi(lpReturnedString);
        return true;
    }
    return false;
}
//--------------------------------------------------------------------------
bool CWaterEyeKeeperDlg::WriteToIniFile(CString ini_path, CString section, CString name, int val)
{
    CString val_str;
    val_str.Format("%d",val);
   
    if (WritePrivateProfileString(section, name, val_str , ini_path)>0)
        return true;
    return false;
}
//--------------------------------------------------------------------------

Следующим пунктом идет спрятать оба окна. Покажем пиктограмму в трее через вызов ShowInSysTray()

#define WM_MYICONNOTIFY    WM_USER+1

void CWaterEyeKeeperDlg::ShowInSysTray()
{

    NOTIFYICONDATA nf;
    memset(&nf, 0, sizeof(nf));
    nf.cbSize = sizeof(nf);

    nf.hWnd = m_hWnd;
    nf.uID = NULL;
   
    nf.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
    nf.uCallbackMessage = WM_MYICONNOTIFY;
    strcpy(nf.szTip,"waterEyeKeeper");
   
    HICON hIcon;
    hIcon=AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    nf.hIcon = hIcon;
    Shell_NotifyIcon(NIM_ADD,&nf);
}
//-----------------------------------------------------------------------------
void CWaterEyeKeeperDlg::RemoveFromSysTray()
{
    NOTIFYICONDATA nf;
    nf.hWnd = m_hWnd;
    nf.uID = NULL;
    nf.uFlags = NIF_ICON;
    nf.uCallbackMessage = NULL;
    nf.hIcon = NULL;
    Shell_NotifyIcon(NIM_DELETE,&nf);
}
//-----------------------------------------------------------------------------
void CWaterEyeKeeperDlg::OnIcon(WPARAM wp, LPARAM lp)
{
   
   
    if (lp==WM_RBUTTONDOWN)
    {
       
        CPoint point;     
        GetCursorPos(&point);
       
        HMENU menu;
        menu = ::CreatePopupMenu();
       
        ::AppendMenu(menu, MF_STRING, 65409 , "Настройки");
        ::AppendMenu(menu, MF_STRING, 65410 , "Выход");
       
        ::SetForegroundWindow(m_hWnd);
       
        int    SelId = ::TrackPopupMenu(menu, TPM_LEFTALIGN|TPM_RETURNCMD, point.x, point.y, 0, m_hWnd, NULL);
        ::DestroyMenu(menu);
       
       
        switch (SelId)
        {
        case 65409:
            ShowDLGWindow(true);
            break;
           
        case 65410:
           
            CDialog::OnOK();
            break;
        }
       
       
    }
   
    if (lp==WM_LBUTTONDBLCLK)
    {
        ShowDLGWindow(true);
    }

   
}
//-----------------------------------------------------------------------------


И спрячем основное окно через

void CWaterEyeKeeperDlg::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos)
{
    if(m_visible == false)
    {
        lpwndpos->flags &= ~SWP_SHOWWINDOW;
    }

   
    CDialog::OnWindowPosChanging(lpwndpos);
}

m_visible - это флаг видимости для диалога настроек.

Сделаем так, чтобы по нажатию
ESCAPE наш диалог не закрывался, а просто прятался

BOOL CWaterEyeKeeperDlg::PreTranslateMessage(MSG* pMsg)
{
    if (pMsg->message == WM_KEYDOWN)
        if (pMsg->wParam == VK_ESCAPE)
        {
            ShowDLGWindow(false);
            return true;
        }

   
    return CDialog::PreTranslateMessage(pMsg);
}


Для того, чтобы закрыть приложение только из меню
void CWaterEyeKeeperDlg::OnClose()
{
    
ShowDLGWindow(false);
}


void CWaterEyeKeeperDlg::ShowDLGWindow(bool _show)
{
    m_visible = _show;
    if (_show == true)
    ShowWindow(SW_SHOW);
        else
    ShowWindow(SW_HIDE);

}

Если интересно, то про иконки можно прочитать например тут Иконки в «System Tray» (http://www.rsdn.ru/article/winshell/shellicons.xml)

И на последок хочу поделиться ссылкой на хорошую бесплатною книгу про интерфейс и не только. Книга называется "Дизайн пользовательского интерфейса II. Искусство мыть слона". Скачать ее можно с сайта http://uibook2.usethics.ru Полезного чтения:)

P.S. Не забывайте про документацию:)

В избранное