|
本帖最后由 神女软件定制 于 2024-12-15 03:22 编辑
之前发布了个软件,结果界面有点杂乱,很多人不会用
搓了个界面向导的轮子,让用户方便理解一点
功能描述:
[C++] 纯文本查看 复制代码 CUITour tour;
//添加一个帧,有两个高亮区域
tour.AddFrame(_T("第1个页面的说明"), FALSE, CRect(0, 0, 100, 24), CRect(0, 32, 100, 56));
//添加一个帧,有3个高亮区域,分别绑定到指定的子控件句柄
tour.AddFrame(_T("第2个页面的说明\r\n第二行,巴拉巴拉"), FALSE, btn1.GetSafeHwnd(),btn2.GetSafeHwnd(),btn3.GetSafeHwnd());
//添加一个帧,没有高亮区域
tour.AddFrame(_T("The End"), FALSE);
tour.CreateTour(this->GetSafeHwnd());
可以在指定窗口上,创建一个向导控件,创建之前,添加好说明和对应的高亮区域或者控件(使用AddFrame)
当它被创建的时候,它会让主窗口变灰,依次显示每个帧的说明,和对应的高亮区域
高亮区域可以指定固定的矩形,也可以指定窗口句柄(对于控件可能会移动或调解尺寸的情况),可以混合指定0个或多个
得益于C++的可变参数模板,可以接收任意数量任意类型的参数,template <typename... Types> void AddFrame(CString tip, BOOL bUnion = FALSE, Types... args)
vc开源:
头文件:
[C++] 纯文本查看 复制代码 #pragma once
#include <afxwin.h>
#include <list>
#include <vector>
using namespace std;
class CUITour :
public CWnd
{
public:
BOOL CreateTour(HWND hwndTarget);
//目标窗口,移动,改变尺寸,需要通知过来
void TargetChange();
template <typename... Types> void AddFrame(CString tip, BOOL bUnion = FALSE, Types... args) {
FRAME frame;
frame.tip = tip;
frame.bUnion = bUnion;
AddToList(frame.lsItems, args...);
m_frames.push_back(frame);
}
void Step(int n);
afx_msg void OnPaint();
afx_msg void OnDestroy();
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);
afx_msg void OnKillFocus(CWnd* pNewWnd);
private:
HWND m_hwndTarget;
int m_cx;
int m_cy;
int m_nStep;
CDC m_dcOrgin;
CBitmap m_mapOrgin;
CDC m_dcGray;
CBitmap m_mapGray;
CFont m_font;
struct ITEM {
enum {
Rect, Handle,
}type;
CRect rc;
HWND hwnd;
};
struct FRAME {
CString tip;
BOOL bUnion;
vector<ITEM> lsItems;
};
vector<FRAME> m_frames;
inline void AddToList(vector<ITEM>& ls) {
}
inline void AddToList(vector<ITEM>& ls, HWND hwnd) {
ls.push_back({ ITEM::Handle,CRect(),hwnd });
}
inline void AddToList(vector<ITEM>& ls,CRect rc) {
ls.push_back({ ITEM::Rect,rc,NULL });
}
template <typename T, typename... Types>void AddToList(vector<ITEM>& ls, T value, Types... args) {
AddToList(ls, value);
AddToList(ls, args...);
}
DECLARE_MESSAGE_MAP()
};
源文件:
[C++] 纯文本查看 复制代码 #include "pch.h"
#include "CUITour.h"
BEGIN_MESSAGE_MAP(CUITour, CWnd)
ON_WM_PAINT()
ON_WM_DESTROY()
ON_WM_LBUTTONDOWN()
ON_WM_RBUTTONDOWN()
ON_WM_KEYDOWN()
ON_WM_MOUSEWHEEL()
ON_WM_KILLFOCUS()
END_MESSAGE_MAP()
BOOL CUITour::CreateTour(HWND hwndTarget)
{
if (!GetSafeHwnd()) {
if (CWnd* pTarget = CWnd::FromHandle(hwndTarget)) {
CRect rc;
pTarget->GetClientRect(&rc);
pTarget->ClientToScreen(&rc);
static LPCTSTR clsName = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW, ::LoadCursor(NULL, IDC_ARROW));
if (CreateEx(0, clsName, _T("UITour"), WS_VISIBLE | WS_POPUP, rc, pTarget, 0)) {
m_hwndTarget = hwndTarget;
m_nStep = 0;
CClientDC dcTemplate(this);
int cxScreen = GetSystemMetrics(SM_CXSCREEN);
int cyScreen = GetSystemMetrics(SM_CYSCREEN);
m_dcOrgin.CreateCompatibleDC(&dcTemplate);
m_mapOrgin.CreateCompatibleBitmap(&dcTemplate, cxScreen, cyScreen);
m_dcOrgin.SelectObject(m_mapOrgin);
m_dcGray.CreateCompatibleDC(&dcTemplate);
m_mapGray.CreateCompatibleBitmap(&dcTemplate, cxScreen, cyScreen);
m_dcGray.SelectObject(m_mapGray);
m_font.CreatePointFont(120, _T("SimHei"));
TargetChange();
ShowWindow(SW_SHOW);
return TRUE;
}
}
}
return FALSE;
}
void CUITour::TargetChange()
{
if (GetSafeHwnd()) {
if (CWnd* pTarget = CWnd::FromHandle(m_hwndTarget)) {
CRect rc;
pTarget->GetClientRect(&rc);
pTarget->ClientToScreen(&rc);
m_cx = rc.Width();
m_cy = rc.Height();
pTarget->PrintWindow(&m_dcOrgin, PW_CLIENTONLY);
m_dcGray.PatBlt(0, 0, m_cx, m_cy, BLACKNESS);
BLENDFUNCTION blf{ 0 };
blf.BlendOp = AC_SRC_OVER;
blf.SourceConstantAlpha = 38;//36
m_dcGray.AlphaBlend(0, 0, m_cx, m_cy,
&m_dcOrgin, 0, 0, m_cx, m_cy, blf);
MoveWindow(rc);
InvalidateRect(NULL);//有可能并没有实际移动
}
else {//目标丢失
DestroyWindow();
}
}
}
void CUITour::Step(int nAdd)
{
m_nStep += nAdd;
if (m_nStep >= 0 && m_nStep < m_frames.size()) {
InvalidateRect(NULL);
}
else {
DestroyWindow();
}
}
void CUITour::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: 在此处添加消息处理程序代码
// 不为绘图消息调用 CWnd::OnPaint()
dc.BitBlt(0, 0, m_cx, m_cy, &m_dcGray, 0, 0, SRCCOPY);
CWnd* pTarget = CWnd::FromHandle(m_hwndTarget);
if (m_nStep < m_frames.size()) {
vector<CRect> rcItems;
for (auto& e : m_frames[m_nStep].lsItems) {//采集所有矩形
if (e.type == ITEM::Handle) {
e.rc.SetRectEmpty();
if (CWnd* pWnd = CWnd::FromHandle(e.hwnd)) {
pWnd->GetWindowRect(e.rc);
ScreenToClient(e.rc);
}
}
rcItems.push_back(e.rc);
}
if (m_frames[m_nStep].bUnion) {//判断是不是联合
CRect rcUnion;
for (auto& e : rcItems) {
rcUnion.UnionRect(rcUnion, e);
}
rcItems.resize(1);
rcItems[0] = rcUnion;
}
for (auto& e : rcItems) {
dc.BitBlt(e.left, e.top, e.Width(), e.Height(), &m_dcOrgin, e.left, e.top, SRCCOPY);
}
list<CRect> rcLeft = { CRect(0,0,m_cx,m_cy) };
for (auto& e : rcItems) {//分裂矩形,求出所有剩下的小矩形区域
for (auto& itor = rcLeft.begin(); itor != rcLeft.end();) {
CRect rcTemp;
if (rcTemp.IntersectRect(*itor, e)) {//有交集
//itor表示大矩形
if (itor->left < e.left) {//左
rcLeft.push_back(CRect(itor->left, itor->top, e.left, itor->bottom));
}
if (itor->right > e.right) {//右
rcLeft.push_back(CRect(e.right, itor->top, itor->right, itor->bottom));
}
if (itor->top < e.top) {//上
rcLeft.push_back(CRect(itor->left, itor->top, itor->right, e.top));
}
if (itor->bottom > e.bottom) {//下
rcLeft.push_back(CRect(itor->left, e.bottom, itor->right, itor->bottom));
}
rcLeft.erase(itor++);
//break;
}
else {
itor++;
}
}
}
#if false
TCHAR buff[128];
wsprintf(buff, _T("空白区域数量: %d \r\n"), rcLeft.size());
OutputDebugString(buff);
for (auto& rc : rcLeft) {
CPen pen;
pen.CreatePen(PS_DASH, 1, rand());
dc.SelectObject(pen);
dc.SelectObject(::GetStockObject(NULL_BRUSH));
dc.Rectangle(rc);
dc.MoveTo(rc.left, rc.top);
dc.LineTo(rc.right, rc.bottom);
dc.MoveTo(rc.right, rc.top);
dc.LineTo(rc.left, rc.bottom);
}
#endif
CString strTip;
strTip.Format(_T("%s\r\n\r\n< UI向导 %d/%lld >"), m_frames[m_nStep].tip, m_nStep + 1, m_frames.size());
dc.SetBkMode(TRANSPARENT);
dc.SetTextColor(RGB(255, 255, 255));
dc.SelectObject(m_font);
auto &itor=max_element(rcLeft.begin(), rcLeft.end(), [](const CRect& a, const CRect& b) {
return b.Width() * b.Height() > a.Width() * a.Height();
if (min(b.Width(), b.Height()) > min(a.Width(), a.Height())) {
return true;
}
else if (min(b.Width(), b.Height()) == min(a.Width(), a.Height())) {
if (max(b.Width(), b.Height()) > max(a.Width(), a.Height())) {
return true;
}
}
return false;
});
CRect rcOrigon = *itor;
CRect rc= rcOrigon;
UINT nFormat = DT_CENTER | DT_WORDBREAK | DT_END_ELLIPSIS;
dc.DrawText(strTip, &rc, nFormat | DT_CALCRECT);
if (rcOrigon.Height() > rc.Height()) {
rcOrigon.top += (rcOrigon.Height() - rc.Height()) / 2;
}
dc.DrawText(strTip, &rcOrigon, nFormat);
}
}
void CUITour::OnDestroy()
{
CWnd::OnDestroy();
// TODO: 在此处添加消息处理程序代码
m_dcOrgin.DeleteDC();
m_mapOrgin.DeleteObject();
m_dcGray.DeleteDC();
m_mapGray.DeleteObject();
m_font.DeleteObject();
}
void CUITour::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
Step(1);
CWnd::OnLButtonDown(nFlags, point);
}
void CUITour::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
Step(-1);
CWnd::OnRButtonDown(nFlags, point);
}
void CUITour::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
int nAdd = 0;
switch (nChar)
{
case VK_ESCAPE:
DestroyWindow();
return;
case VK_LEFT:
case VK_UP:
case VK_PRIOR:
nAdd = -1;
break;
case VK_RIGHT:
case VK_DOWN:
case VK_NEXT:
case VK_SPACE:
case VK_RETURN:
nAdd = 1;
break;
case VK_HOME:
nAdd = -m_nStep;
break;
case VK_END:
nAdd = m_frames.size() - m_nStep - 1;
break;
default:
break;
}
if(nAdd)
Step(nAdd);
CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
}
BOOL CUITour::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
Step(zDelta < 0 ? 1 : -1);
return CWnd::OnMouseWheel(nFlags, zDelta, pt);
}
void CUITour::OnKillFocus(CWnd* pNewWnd)
{
CWnd::OnKillFocus(pNewWnd);
// TODO: 在此处添加消息处理程序代码
//SetFocus();
#if false
if (pNewWnd->GetSafeHwnd() == m_hwndTarget) {
OutputDebugString(_T("主窗口得到焦点\r\n"));
}
else if (pNewWnd->GetSafeHwnd() == GetSafeHwnd()) {
OutputDebugString(_T("自己得到焦点\r\n"));
}
else {
TCHAR buff[128];
wsprintf(buff, _T("焦点: %d \r\n"), pNewWnd->GetSafeHwnd());
OutputDebugString(buff);
}
#endif
}
有空了再转成易语言的
|
|