Skip to content

Commit

Permalink
新增鼠标提示会实时更新;优化关于启动时弹出“已经有一个程序正在运行”的处理;增加无法嵌入任务栏时自动重试的处理;历史流量统计对话框中增加图…
Browse files Browse the repository at this point in the history
…形指示;
  • Loading branch information
zhongyang219 committed Dec 31, 2017
1 parent 1a9716d commit 63b17ec
Show file tree
Hide file tree
Showing 19 changed files with 1,107 additions and 149 deletions.
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

19 changes: 14 additions & 5 deletions TrafficMonitor/Common.cpp
Expand Up @@ -283,6 +283,13 @@ void CCommon::FillStaticColor(CStatic & static_ctr, COLORREF color)
pDC->FillSolidRect(rect, color);
}

void CCommon::SetDrawArea(CDC * pDC, CRect rect)
{
CRgn rgn;
rgn.CreateRectRgnIndirect(rect);
pDC->SelectClipRgn(&rgn);
}


bool CCommon::IsForegroundFullscreen()
{
Expand Down Expand Up @@ -329,10 +336,6 @@ bool CCommon::CopyStringToClipboard(const wstring & str)

bool CCommon::WhenStart(int time, bool write_log)
{
//GetTickCount函数用于获取系统启动到现在的时间,但是如果在“控制面板\系统和安全\电源选项\选择电源按钮的功能”中
//勾选了“启用快速启动(推荐)”的话,这其实是一种混合休眠模式,这种情况下,开机时此函数获取到的值就不会被重置,
//也就是说此函数获取到的是上次完全关机后开机到现在的时间,或上次重启到现在的时间(重启就相当于完全关机一次)。
//由于Win10貌似默认开启快速启动功能,所以此函数不适合在Win10上使用,但是我目前还没有找到较好的方法获取开机时间。
int tick_count = GetTickCount();
if (write_log)
{
Expand Down Expand Up @@ -389,5 +392,11 @@ bool CCommon::IsWindows10FallCreatorOrLater()
{
int major_version, minor_version, build_number;
GetWindowsVersion(major_version, minor_version, build_number);
return ((major_version == 10 && build_number >= 16299) || major_version > 10);
if (major_version > 10)
return true;
else if (major_version == 10 && minor_version > 0)
return true;
else if (major_version == 10 && minor_version == 0 && build_number >= 16299)
return true;
else return false;
}
9 changes: 6 additions & 3 deletions TrafficMonitor/Common.h
Expand Up @@ -6,7 +6,7 @@ struct HistoryTraffic
int year;
int month;
int day;
unsigned kBytes; //当天使用的流量(以KB为单位)
unsigned int kBytes; //当天使用的流量(以KB为单位)

//比较两个HistoryTraffic对象的日期,如果a的时间大于b,则返回true
static bool DateGreater(const HistoryTraffic& a, const HistoryTraffic& b)
Expand Down Expand Up @@ -41,7 +41,7 @@ class CCommon
//将一个int类型数据写入ini文件,如果成功则返回true
static bool WritePrivateProfileIntW(const wchar_t * AppName, const wchar_t * KeyName, int value, const wchar_t * Path);

//根据数据在大小转换成以KB、MB、GB为单位的字符串
//根据数据的大小转换成以KB、MB、GB为单位的字符串
static CString DataSizeToString(unsigned int size);

static CString KBytesToString(unsigned int kb_size);
Expand Down Expand Up @@ -84,6 +84,9 @@ class CCommon
//为一个Static控件填充指定的颜色
static void FillStaticColor(CStatic& static_ctr, COLORREF color);

//设置绘图的剪辑区域
static void SetDrawArea(CDC* pDC, CRect rect);

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* 函数名称:IsForegroundFullscreen
* 功能说明:判断当前正在与用户交互的前台窗口是否是全屏的。
Expand All @@ -98,7 +101,7 @@ class CCommon
//将一个字符串保存到剪贴板
static bool CopyStringToClipboard(const wstring& str);

//判断现在是否刚开机,在刚开机的time毫秒内返回true,否则返回false
//判断现在是否刚开机,在刚开机的time毫秒内返回true,否则返回false(在启用了快速启动时,此函数可能会无法得到正确的结果)
static bool WhenStart(int time, bool write_log = false);

//显示鼠标提示
Expand Down
128 changes: 122 additions & 6 deletions TrafficMonitor/HistoryTrafficDlg.cpp
Expand Up @@ -21,6 +21,16 @@ CHistoryTrafficDlg::~CHistoryTrafficDlg()
{
}

void CHistoryTrafficDlg::SaveConfig() const
{
CCommon::WritePrivateProfileIntW(L"histroy_traffic", L"use_log_scale", m_use_log_scale, theApp.m_config_path.c_str());
}

void CHistoryTrafficDlg::LoadConfig()
{
m_use_log_scale = (GetPrivateProfileInt(_T("histroy_traffic"), _T("use_log_scale"), 0, theApp.m_config_path.c_str()) != 0);
}

void CHistoryTrafficDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
Expand All @@ -29,6 +39,10 @@ void CHistoryTrafficDlg::DoDataExchange(CDataExchange* pDX)


BEGIN_MESSAGE_MAP(CHistoryTrafficDlg, CDialog)
ON_WM_GETMINMAXINFO()
ON_WM_INITMENU()
ON_COMMAND(ID_USE_LINEAR_SCALE, &CHistoryTrafficDlg::OnUseLinearScale)
ON_COMMAND(ID_USE_LOG_SCALE, &CHistoryTrafficDlg::OnUseLogScale)
END_MESSAGE_MAP()


Expand All @@ -40,6 +54,10 @@ BOOL CHistoryTrafficDlg::OnInitDialog()
CDialog::OnInitDialog();

// TODO: 在此添加额外的初始化
SetIcon(AfxGetApp()->LoadIcon(IDI_NOFITY_ICON), FALSE); // 设置小图标

LoadConfig();

//获取dpi设置
CWindowDC dc(this);
HDC hDC = dc.GetSafeHdc();
Expand All @@ -50,10 +68,23 @@ BOOL CHistoryTrafficDlg::OnInitDialog()
m_history_list.GetClientRect(rect);
m_history_list.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_LABELTIP);
int width0, width1;
width0 = rect.Width() / 5 * 2;
width1 = rect.Width() - width0 - 21 * dpi / 96;
width0 = rect.Width() / 3;
width1 = rect.Width() - 2 * width0 - 21 * dpi / 96;
m_history_list.InsertColumn(0, _T("日期"), LVCFMT_LEFT, width0); //插入第0列
m_history_list.InsertColumn(1, _T("使用的流量(上传+下载)"), LVCFMT_LEFT, width1); //插入第1列
m_history_list.InsertColumn(1, _T("使用的流量(上传+下载)"), LVCFMT_LEFT, width0); //插入第1列
m_history_list.InsertColumn(2, _T("图表"), LVCFMT_LEFT, width1);

//获取历史流量列表中流量的最大值
unsigned int max_traffic{};
for (const auto& traffic : m_history_traffics)
{
if (traffic.kBytes > max_traffic)
max_traffic = traffic.kBytes;
}
m_history_list.EnableDrawItemRange();
m_history_list.SetDrawItemRangeRow(2);
m_history_list.SetDrawItemRangMargin(4 * dpi / 96);
m_history_list.SetDrawItemRangInLogScale(m_use_log_scale);

for (int i{}; i<m_history_traffics.size(); i++)
{
Expand All @@ -70,10 +101,95 @@ BOOL CHistoryTrafficDlg::OnInitDialog()

m_history_list.InsertItem(i, date_str);
m_history_list.SetItemText(i, 1, k_bytes_str);

double range = static_cast<double>(m_history_traffics[i].kBytes) *1000 / max_traffic;
COLORREF color;
if (m_history_traffics[i].kBytes < 102400) //流量小于100MB时绘制蓝色
color = RGB(0, 183, 238);
else if (m_history_traffics[i].kBytes < 1024 * 1024) //流量小于1GB时绘制绿色
color = RGB(128, 194, 105);
else if (m_history_traffics[i].kBytes < 10 * 1024 * 1024) //流量小于10GB时绘制黄色
color = RGB(255, 216, 58);
else //流量大于10GB时绘制红色
color = RGB(255, 95, 74);
m_history_list.SetDrawItemRangeData(i, range, color);
}
//LVITEMW item;
//m_history_list.GetSub;

//获取初始时窗口的大小
GetWindowRect(rect);
m_min_size.cx = rect.Width();
m_min_size.cy = rect.Height();

m_menu.LoadMenu(IDR_HISTORY_TRAFFIC_MENU);

return TRUE; // return TRUE unless you set the focus to a control
// 异常: OCX 属性页应返回 FALSE
}


void CHistoryTrafficDlg::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//限制窗口最小大小
lpMMI->ptMinTrackSize.x = m_min_size.cx; //设置最小宽度
lpMMI->ptMinTrackSize.y = m_min_size.cy; //设置最小高度

CDialog::OnGetMinMaxInfo(lpMMI);
}


BOOL CHistoryTrafficDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
// TODO: 在此添加专用代码和/或调用基类

LPNMHDR lpnmhdr = (LPNMHDR)lParam;
if (lpnmhdr->code == NM_RCLICK)
{
CPoint point;
GetCursorPos(&point);//获得光标的位置
m_history_list.ScreenToClient(&point);//获得list控件在窗口上的坐标
CWnd* pWnd = m_history_list.ChildWindowFromPoint(point);
CHeaderCtrl* pHeader = m_history_list.GetHeaderCtrl();//获取列表视图控件的标题控件
CRect item_rect;
pHeader->GetItemRect(2, item_rect); //获取列表标题控件第2列的矩形区域,只有光标在第2列点击时才弹出右键菜单
if (pWnd && (pWnd->GetSafeHwnd() == pHeader->GetSafeHwnd()) && item_rect.PtInRect(point))
{
HDHITTESTINFO info{};
info.pt = point;
pHeader->SendMessage(HDM_HITTEST, 0, (LPARAM)&info);
CMenu * pMenu = m_menu.GetSubMenu(0);
GetCursorPos(&point);
pMenu->TrackPopupMenu(TPM_RIGHTBUTTON, point.x, point.y, this);
}
}
return CDialog::OnNotify(wParam, lParam, pResult);
}


void CHistoryTrafficDlg::OnInitMenu(CMenu* pMenu)
{
CDialog::OnInitMenu(pMenu);

// TODO: 在此处添加消息处理程序代码
if (m_use_log_scale)
pMenu->CheckMenuRadioItem(ID_USE_LINEAR_SCALE, ID_USE_LOG_SCALE, ID_USE_LOG_SCALE, MF_BYCOMMAND | MF_CHECKED);
else
pMenu->CheckMenuRadioItem(ID_USE_LINEAR_SCALE, ID_USE_LOG_SCALE, ID_USE_LINEAR_SCALE, MF_BYCOMMAND | MF_CHECKED);
}


void CHistoryTrafficDlg::OnUseLinearScale()
{
// TODO: 在此添加命令处理程序代码
m_use_log_scale = false;
m_history_list.SetDrawItemRangInLogScale(m_use_log_scale);
SaveConfig();
}


void CHistoryTrafficDlg::OnUseLogScale()
{
// TODO: 在此添加命令处理程序代码
m_use_log_scale = true;
m_history_list.SetDrawItemRangInLogScale(m_use_log_scale);
SaveConfig();
}
15 changes: 14 additions & 1 deletion TrafficMonitor/HistoryTrafficDlg.h
@@ -1,6 +1,7 @@
#pragma once
#include "afxcmn.h"
#include "Common.h"
#include "ListCtrlEx.h"

// CHistoryTrafficDlg 对话框

Expand All @@ -18,12 +19,24 @@ class CHistoryTrafficDlg : public CDialog
#endif

protected:
CListCtrl m_history_list;
CListCtrlEx m_history_list;
deque<HistoryTraffic>& m_history_traffics;
CSize m_min_size;

CMenu m_menu;
bool m_use_log_scale{ false }; //绘制表示历史流量数值的矩形时是否使用对数比例

void SaveConfig() const;
void LoadConfig();

virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持

DECLARE_MESSAGE_MAP()
public:
virtual BOOL OnInitDialog();
afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI);
virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult);
afx_msg void OnInitMenu(CMenu* pMenu);
afx_msg void OnUseLinearScale();
afx_msg void OnUseLogScale();
};
83 changes: 83 additions & 0 deletions TrafficMonitor/ListCtrlEx.cpp
@@ -0,0 +1,83 @@
#include "stdafx.h"
#include "ListCtrlEx.h"

IMPLEMENT_DYNAMIC(CListCtrlEx, CListCtrl)

CListCtrlEx::CListCtrlEx()
{
}


CListCtrlEx::~CListCtrlEx()
{
}
void CListCtrlEx::SetDrawItemRangeData(int item, double range, COLORREF color)
{
if (item < 0) return;
if (item >= m_item_rage_data.size())
m_item_rage_data.resize(item + 1);
m_item_rage_data[item].data_value = range;
m_item_rage_data[item].color = color;
}

void CListCtrlEx::SetDrawItemRangInLogScale(bool log_scale)
{
m_use_log_scale = log_scale;
Invalidate();
}

BEGIN_MESSAGE_MAP(CListCtrlEx, CListCtrl)
ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CListCtrlEx::OnNMCustomdraw)
END_MESSAGE_MAP()


void CListCtrlEx::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult)
{
if (m_draw_item_range)
{
*pResult = CDRF_DODEFAULT;
LPNMLVCUSTOMDRAW lplvdr = reinterpret_cast<LPNMLVCUSTOMDRAW>(pNMHDR);
NMCUSTOMDRAW& nmcd = lplvdr->nmcd;
switch (lplvdr->nmcd.dwDrawStage) //判断状态
{
case CDDS_PREPAINT:
*pResult = CDRF_NOTIFYITEMDRAW;
break;
case CDDS_ITEMPREPAINT: //如果为画ITEM之前就要进行颜色的改变
if (nmcd.dwItemSpec >= 0 && nmcd.dwItemSpec < m_item_rage_data.size())
{
double range = m_item_rage_data[nmcd.dwItemSpec].data_value;
CDC* pDC = CDC::FromHandle(nmcd.hdc); //获取绘图DC
CRect item_rect, draw_rect;
GetSubItemRect(nmcd.dwItemSpec,m_draw_item_range_row, LVIR_BOUNDS, item_rect); //获取绘图单元格的矩形区域
CCommon::SetDrawArea(pDC, item_rect); //设置绘图区域为当前列
draw_rect = item_rect;
if (draw_rect.Height() > 2 * m_margin)
{
draw_rect.top += m_margin;
draw_rect.bottom -= m_margin;
}
int width;
if (m_use_log_scale) //使用对数比例(y=ln(x+1))
{
range = std::log(range + 1);
width = static_cast<int>(range*draw_rect.Width() / std::log(1000 + 1));
}
else //使用线性比例(y=x)
{
width = static_cast<int>(range*draw_rect.Width() / 1000);
}
draw_rect.right = draw_rect.left + width;
pDC->FillSolidRect(draw_rect, m_item_rage_data[nmcd.dwItemSpec].color);

//当前列绘制完成后将绘图区域设置为左边的区域,防止当前列的区域被覆盖
CRect rect1{ item_rect };
rect1.left = 0;
rect1.right = item_rect.left;
CCommon::SetDrawArea(pDC, rect1);
}
*pResult = CDRF_DODEFAULT;
break;
}
}
}
33 changes: 33 additions & 0 deletions TrafficMonitor/ListCtrlEx.h
@@ -0,0 +1,33 @@
#pragma once
#include "afxcmn.h"
#include "Common.h"
class CListCtrlEx :
public CListCtrl
{
DECLARE_DYNAMIC(CListCtrlEx)
public:
CListCtrlEx();
~CListCtrlEx();

void EnableDrawItemRange(bool draw = true) { m_draw_item_range = draw; } //设置是否要在某一列单元格中绘制表示数值大小的矩形
void SetDrawItemRangeRow(int row) { m_draw_item_range_row = row; } //设置要绘制表示数值大小的矩形的列,注意此列必须为最右边的列,否则,此列右边的所有列将无法显示
void SetDrawItemRangeData(int item, double range, COLORREF color); //设置某一行的项目数据大小(取值为1~1000)和颜色
void SetDrawItemRangMargin(int margin) { m_margin = margin; } //设置绘制绘制的矩形的边缘到单元格边框的矩形,此值越大则绘制的矩形越细,但是不能超过列表行距的一半
void SetDrawItemRangInLogScale(bool log_scale); //设置要绘制表示数值大小的矩形时是否使用对数比例,否则使用线性比例

protected:
struct ItemData
{
double data_value; //要绘制的矩形表示的数值大小,范围为0~1000
COLORREF color; //要绘制的矩形的颜色
};
bool m_draw_item_range{ false }; //是否需要在某一列单元格中绘制表示数值大小的矩形
int m_draw_item_range_row{}; //需要绘制表示数值大小的矩形的列
int m_margin{};
vector<ItemData> m_item_rage_data; //用于表示每一项需要绘制的数据大小和绘图的颜色
bool m_use_log_scale{ false }; //如果为true则使用对数比例绘制矩形,否则使用线性比例

DECLARE_MESSAGE_MAP()
afx_msg void OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult);
};

0 comments on commit 63b17ec

Please sign in to comment.