IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> WTL 自绘控件库 (CQsEdit) -> 正文阅读

[游戏开发]WTL 自绘控件库 (CQsEdit)

概述:

CQsEdit 继承CEdit而来,CQsEdit 没有太多的绘制,只是对背景和边框线进行了绘制,并且对输入字符进行处理。

代码实现如下:

#pragma once
#include "UserMessage.h"
#include "QsInclude.h"
#include <atlmisc.h>


#define ES_COMBO        (0x00000200)   /* Undocumented. Parent is a combobox */

#define ES_AUTOSUGGEST	ES_COMBO


#define EN_QUERY_SUGGETST_DROP		(0x8000)	// is suggest dropped
#define EN_SUGGETST_DROP_HIDE			(0x8001)
#define EN_SUGGETST_DROP_SHOW			(0x8002)
#define EN_SUGGETST_DROP_SHOW_NEXT		(0x8003)
#define EN_SUGGETST_DROP_SHOW_PRE		(0x8004)

//#define WINDOW_CUSTOM_STYLE_MASK		(0xFFFF)
#define EDIT_STYLE_MASK					WINDOW_CUSTOM_STYLE_MASK


typedef bool (*CharFilter)(wchar_t wch);

/* CQsEdit class */

class CQsEdit : 
	public CWindowImpl<CQsEdit, CEdit>,
	public CImageMgrCtrlBase< CQsEdit>
{
	typedef CWindowImpl< CQsEdit, CEdit > theBaseClass;
	typedef CImageMgrCtrlBase< CQsEdit> theImageCtrlBaseClass;

	BOOL			m_bBtnFlag;						//是否启用清除内容按钮
	CRect			rcButton;						//清除内容按钮区域
	Image			*m_pImage;						//清除按钮图片
	volatile bool	m_bDrawBorder;					//绘制边框标志
	volatile bool	m_bPassword;					//密码框标志
	CString	        m_strBkText;					//输入提示文字
	WTL::CFont		m_editfont;					    //输入提示文字字体

public:

	DECLARE_WND_SUPERCLASS(_T("QsEdit"), CEdit::GetWndClassName())

	BEGIN_MSG_MAP( CQsEdit )

		MESSAGE_HANDLER( WM_KILLFOCUS, OnFocusChanged )
		MESSAGE_HANDLER( WM_SETFOCUS, OnFocusChanged )
		MESSAGE_HANDLER( WM_PAINT, OnPaint )
		MESSAGE_HANDLER( WM_ERASEBKGND, OnEraseBKGnd )
		//MESSAGE_HANDLER( WM_KEYDOWN, OnKeyDown )
		MESSAGE_HANDLER( WM_CHAR, OnChar )
		//MESSAGE_HANDLER( WM_GETDLGCODE, OnGetDlgCode )
		MESSAGE_HANDLER( WM_KEYDOWN, OnKeydown )
		CHAIN_MSG_MAP( theImageCtrlBaseClass )
		DEFAULT_REFLECTION_HANDLER()

	END_MSG_MAP()

	/**
	*@method   CQsEdit
	*@brief    CQsEdit's default constructor.
	*    
	*@return   
	*/
	CQsEdit():
	m_bBtnFlag( FALSE ),
		m_bDrawBorder( True ),
		m_bPassword( false ),
		m_fnCharFilter(NULL)
	{

	}

    /**
	*@method   ~CQsEdit
	*@brief    CQsEdit's destructor.
	*    
	*@return   
	*/
	virtual ~CQsEdit()
	{
		DeleteQSFont();
	}

	/**
	*@method   Create
	*@brief    
	*    
	*@param    HWND hWndParent
	*@param    ATL::_U_RECT rect = NULL
	*@param    LPCTSTR szWindowName = NULL
	*@param    DWORD dwStyle = 0
	*@param    DWORD dwExStyle = 0
	*@param    ATL::_U_MENUorID MenuOrID = 0U
	*@param    LPVOID lpCreateParam = NULL
	*@return   HWND
	*/
	HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
		DWORD dwStyle = 0, DWORD dwExStyle = 0, 
		ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
	{		
		theBaseClass::Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, MenuOrID, lpCreateParam);

		CRect rtClient;
		//CRect textRect;

		GetClientRect(&rtClient);

		rtClient.MoveToXY( 2 * GetEditBorder(), 2 * GetEditBorder() );
		//GetRect( &textRect );
		//SetWindowPos( NULL, -1, -1, textRect.Width() + 8, textRect.Height() + 8, SWP_NOMOVE|SWP_NOZORDER );
		//SetWindowPos( NULL, -1, -1, textRect.Width() , textRect.Height() , SWP_NOMOVE|SWP_NOZORDER );

		//textRect.MoveToXY( 2, 2 );
		SetRect( &rtClient );
		GetRect( &rtClient );

		return m_hWnd;
	}

    /**
	*@method   SubclassWindow
	*@brief    Use this function to subclass one window
	*    
	*@param    HWND hWnd    subclass binding window handle
	*@return   BOOL success return TRUE, failed return FALSE
	*/
	BOOL SubclassWindow( HWND hWnd )
	{
		BOOL bRet = theBaseClass::SubclassWindow( hWnd );

		CRect rtClient;
		//CRect textRect;

		GetClientRect(&rtClient);

		rtClient.MoveToXY( 2 * GetEditBorder(), 2 * GetEditBorder() );
		//GetRect( &textRect );
		//SetWindowPos( NULL, -1, -1, textRect.Width() + 8, textRect.Height() + 8, SWP_NOMOVE|SWP_NOZORDER );
		//SetWindowPos( NULL, -1, -1, textRect.Width() , textRect.Height() , SWP_NOMOVE|SWP_NOZORDER );

		//textRect.MoveToXY( 2, 2 );
		SetRect( &rtClient );
		GetRect( &rtClient );

		return bRet;
	}

	/**
	*@method   EnabledBorder
	*@brief    Call this function to enable edit's border
	*    
	*@param    bool bFlag   True to enable border, false disable border
	*@return   bool Current flag
	*/
	bool EnabledBorder( bool bFlag )
	{
		if( m_bDrawBorder != bFlag )
		{
			m_bDrawBorder = bFlag;
		}

		return m_bDrawBorder;
	}

	/**
	*@method   EnabledPassword
	*@brief    Call this function to enable edit's password mode
	*    
	*@param    bool bFlag   True to password mode, false disable password mode
	*@return   bool
	*/
	bool EnabledPassword( bool bFlag )
	{
		if( m_bPassword != bFlag )
		{
			m_bPassword = bFlag;
		}

		return m_bPassword;
	}

	/**
	*@method   SetBkText
	*@brief    Set default text of background
	*    
	*@param    LPCTSTR pszText  the text string to set
	*@return   void
	*/
	void SetBkText( LPCTSTR pszText )
	{
		m_strBkText = pszText;
	}

	/**
	*@method   SetCharFilter
	*@brief    Set character filter callback function to mask not accept chars
	*    
	*@param    CharFilter   NewFilter Callback function to set
	*@return   CharFilter   Old char filter
	*/
	CharFilter SetCharFilter(CharFilter NewFilter)
	{
		CharFilter oldFilter = m_fnCharFilter;

		m_fnCharFilter = NewFilter;
		return oldFilter;
	}
	/**
	*@method   DeleteQSFont
	*@brief       删除字体对象
	*    
	*@return   void
	*/
	void DeleteQSFont()
	{
		if (NULL != m_editfont.m_hFont)
		{
			m_editfont.DeleteObject();
		}
	}
	/**
	*@method   SetQSFont
	*@brief     设置文字的大小
	*    
	*@param    TCHAR * fontName  字体名称 不得大小32
	*@param    int lfHeight  字体大小
	*@param    int lfWeight
	*@param    BYTE fCharSet
	*@return   void
	*/
	void SetQsFont(LPCTSTR fontName,int lfHeight,int lfWeight = FW_BOLD,BYTE fCharSet = DEFAULT_CHARSET)
	{
		DeleteQSFont();
		LOGFONT itemFont;
		itemFont.lfCharSet = fCharSet;
		itemFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
		itemFont.lfEscapement = 0;
		memset(itemFont.lfFaceName, 0, LF_FACESIZE);
		memcpy_s(itemFont.lfFaceName, LF_FACESIZE, fontName, LF_FACESIZE);
		itemFont.lfHeight = lfHeight;
		itemFont.lfItalic = FALSE;
		itemFont.lfOrientation = 0;
		itemFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
		itemFont.lfPitchAndFamily = DEFAULT_PITCH | FF_SWISS;
		itemFont.lfQuality = CLEARTYPE_NATURAL_QUALITY;
		itemFont.lfStrikeOut = FALSE;
		itemFont.lfUnderline = FALSE;
		itemFont.lfWeight = lfWeight;
		itemFont.lfWidth = 0;

		m_editfont = ::CreateFontIndirect( &itemFont);
		SetFont(m_editfont);
	}
	/**
	*@method   SetEditStyle
	*@brief    Set edit control style
	*    
	*@param    DWORD    dwNewStyle New edit style
	*@return   DWORD    Old edit style
	*/
	DWORD SetEditStyle(DWORD dwNewStyle)
	{
		DWORD dwOldStyle = GetStyle();
		BOOL bSucc;

		//dwOldStyle = dwNewStyle & EDIT_STYLE_MASK;
		bSucc = ModifyStyle(dwNewStyle, dwOldStyle);
		ATLASSERT(bSucc);

		//dwOldStyle = dwOldStyle & EDIT_STYLE_MASK;

		return dwOldStyle;
	}

	static int GetEditBorder()
	{
		return 1;
	}

protected:

	/**
	*@method   OnChar
	*@brief    WM_CHAR message handle function
	*    
	*@param    UINT uMsg    Message id
	*@param    WPARAM wParam    word param
	*@param    LPARAM lParam    LParam
	*@param    BOOL& bHandled   if message is handled
	*@return   LRESULT      whether function call is success
	*/
	LRESULT OnChar( UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled )
	{
		bool bAccept;
		wchar_t wCh;

		wCh = wchar_t(wParam);

		//If is not visible char, always accept it.
		if (wCh <= ' ')
		{
			bHandled = FALSE;
			return 0;
		}

		//If have filter, call it first
		if (m_fnCharFilter)
		{
			bAccept = m_fnCharFilter(wchar_t(wParam));
			if ( !bAccept )
			{
				return TRUE;
			}
			else
			{
				bHandled = FALSE;
				return FALSE;
			}
		}
		else
		{
			bHandled = FALSE;
		}

		return 0;
	}

    /**
	*@method   OnKeyDown
	*@brief    WM_KEYDOWN message handle function
	*    
	*@param    UINT uMsg    Message id
	*@param    WPARAM wParam    word VK_
	*@param    LPARAM lParam    LParam
	*@param    BOOL& bHandled   if message is handled
	*@return   LRESULT  whether function call is success
	*/
	LRESULT OnKeyDown( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
	{
		bHandled = FALSE;

		CWindowImpl<CQsEdit, CEdit>* pEdit = this;

		TCHAR tchKey = (TCHAR)wParam;
		if ( ( 'A' == tchKey ) || ( 'a' == tchKey ) )
		{
			SHORT sCtrlState = GetKeyState( VK_CONTROL );
			if ( sCtrlState & 0X8000 )
			{
				int nLen = GetWindowTextLength( );
				SetSel( 0, nLen, FALSE );
				Invalidate();

				pEdit = NULL;
			}
		}
		if ( VK_RETURN == tchKey )
		{
			::SendMessage( GetParent().m_hWnd, WM_EDITRETURN, 0, 0 );
			pEdit = NULL;
		}

		return pEdit != NULL? pEdit->DefWindowProc(uMsg, wParam, lParam): 0;
	}

	/**
	*@method   OnFocusChanged
	*@brief    WM_SETFOCUS message handle function
	*    
	*@param    UINT uMsg    Message id
	*@param    WPARAM wParam    word param
	*@param    LPARAM lParam    LParam
	*@param    BOOL& bHandled   if message is handled
	*@return   LRESULT  whether function call is success
	*/
	LRESULT OnFocusChanged( UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled )
	{
		Invalidate();
		bHandled = FALSE;
		return 0;
	}

    /**
	*@method   OnPaint
	*@brief    WM_PAINT message handle function
	*    
	*@param    UINT uMsg    Message id
	*@param    WPARAM wParam    word param
	*@param    LPARAM lParam    LParam
	*@param    BOOL& bHandled   if message is handled
	*@return   LRESULT  whether function call is success
	*/
	LRESULT OnPaint( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/ )
	{

		HWND hwnd = GetFocus();
		int len = GetWindowTextLength();
		if( ( len > 0 ) || ( hwnd == m_hWnd ) || ( m_strBkText.GetLength() <= 0 ) )
		{
			if( !m_bPassword )
			{
				return DefWindowProc( uMsg, wParam, lParam );
			}
		}

		WTL::CPaintDC paintDC( m_hWnd );
		paintDC.SetBkMode( TRANSPARENT );

		CRect rc;
		GetRect( rc );

		//创建内存作图对象
		WTL::CDC memDC;
		memDC.CreateCompatibleDC( paintDC.m_hDC );
		WTL::CBitmap memBitmap;
		memBitmap.CreateCompatibleBitmap( paintDC.m_hDC, rc.Width(), rc.Height() );
		HBITMAP hOldBmp = memDC.SelectBitmap( memBitmap );

		//获得控件当前使用的字体
		HFONT hFont = GetDefaultFont();
		//HFONT hFont = m_bkTxtFont.m_hFont;
		HFONT hOldFont = memDC.SelectFont( hFont );
		//还原背景
		memDC.BitBlt( 0, 0, rc.Width(), rc.Height(), paintDC.m_hDC, rc.left, rc.top, SRCCOPY );

		CRect textRect( 0, 0, rc.Width(), rc.Height() );
		memDC.SetTextColor( RGB( 128, 128, 128 ) );
		memDC.DrawText( m_strBkText, m_strBkText.GetLength(), &textRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);

		//提交图像
		paintDC.BitBlt( rc.left, rc.top, rc.Width(), rc.Height(), memDC.m_hDC, 0, 0, SRCCOPY );

		CFont font = hFont;
		memDC.SelectFont( hOldFont );
		memDC.SelectBitmap( hOldBmp );

		memDC.DeleteDC();
		memBitmap.DeleteObject();
		

		//::DeleteObject( hFont );

		return 0;
	}

	/**
	*@method   OnEraseBKGnd
	*@brief    WM_ERASEBKGND message handle function
	*    
	*@param    UINT uMsg    Message id
	*@param    WPARAM wParam    word param
	*@param    LPARAM lParam    LParam
	*@param    BOOL& bHandled   if message is handled
	*@return   LRESULT  whether function call is success
	*/
	LRESULT OnEraseBKGnd( UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/ )
	{
		WTL::CDCHandle bkdc( ( HDC ) wParam );

		//如果需要绘制边框
		if( m_bDrawBorder )
		{
			CRect rc;
			GetClientRect( rc );

			//创建内存作图对象
			WTL::CDC dc;
			dc.CreateCompatibleDC( bkdc.m_hDC );
			WTL::CBitmap memBitmap;
			memBitmap.CreateCompatibleBitmap( bkdc.m_hDC, rc.Width(), rc.Height() );
			HBITMAP hOldBmp = dc.SelectBitmap( memBitmap );

			//还原背景
			dc.BitBlt( 0, 0, rc.Width(), rc.Height(), bkdc.m_hDC, 0, 0, SRCCOPY );

			WTL::CPen pen;
			pen.CreatePen( PS_SOLID, 1, RGB( 255, 255, 255 ) );

			//画一个淡蓝色的边框
			HPEN hOldPen = dc.SelectPen( pen );
			dc.RoundRect( 0, 0, rc.Width(), rc.Height(), 0, 0 );
			dc.SelectPen( hOldPen );

			//提交图像
			bkdc.BitBlt( 0, 0, rc.Width(), rc.Height(), dc.m_hDC, 0, 0, SRCCOPY );

			dc.SelectBitmap( hOldBmp );
			dc.DeleteDC();
			memBitmap.DeleteObject();
			pen.DeleteObject();
	

		}

		return 0;
	}

	/**
	*@method   OnGetDlgCode
	*@brief    
	*    
	*@param    UINT uMsg
	*@param    WPARAM wParam
	*@param    LPARAM lParam
	*@param    BOOL& bHandled
	*@return   LRESULT
	*/
	LRESULT OnGetDlgCode( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/ )
	{
		LRESULT lRes;
		BOOL bDropped;

		

		if (lParam && (((LPMSG)lParam)->message == WM_KEYDOWN))
		{
			WPARAM wNotify;
			int vk = (int)((LPMSG)lParam)->wParam;

			if ( (GetStyle() & ES_AUTOSUGGEST ) 
				&& !(GetStyle() & ES_MULTILINE ) 
				&& (vk == VK_RETURN || vk == VK_ESCAPE || vk == VK_UP || vk == VK_DOWN) )
			{
				bDropped = (BOOL)SendMessageW(GetParent(), WM_COMMAND, EN_QUERY_SUGGETST_DROP, 0);

				if(vk == VK_UP || vk == VK_DOWN)
				{
					if (FALSE == bDropped)
					{
						wNotify = MAKEWPARAM(GetWindowLong(GWL_ID), EN_SUGGETST_DROP_SHOW);
					}
					else if( TRUE == bDropped  && vk == VK_DOWN )
					{
						wNotify = MAKEWPARAM(GetWindowLong(GWL_ID), EN_SUGGETST_DROP_SHOW_NEXT);
					}
					else if( TRUE == bDropped  && vk == VK_UP )
					{
						wNotify = MAKEWPARAM(GetWindowLong(GWL_ID), EN_SUGGETST_DROP_SHOW_PRE);
					}
				}

				if(vk == VK_RETURN || vk == VK_ESCAPE)
				{
					wNotify = MAKEWPARAM(GetWindowLong(GWL_ID), EN_SUGGETST_DROP_HIDE);
				}

				SendMessage(GetParent(), WM_COMMAND, wNotify, (LPARAM)m_hWnd);
				lRes = DLGC_WANTARROWS;
			}
			else
			{
				lRes = DefWindowProc( uMsg,  wParam,  lParam);
			}
		}
		else
		{
			lRes = DefWindowProc( uMsg,  wParam,  lParam);
			lRes |= DLGC_WANTARROWS | DLGC_WANTTAB | DLGC_WANTALLKEYS | DLGC_WANTMESSAGE | DLGC_HASSETSEL;
		}

		return lRes;
	}

	/**
	*@method   OnKeydown
	*@brief    
	*    
	*@param    UINT uMsg
	*@param    WPARAM wParam
	*@param    LPARAM lParam
	*@param    BOOL& bHandled
	*@return   LRESULT
	*/
	LRESULT OnKeydown( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
	{
		LRESULT lRes = 0;
		BOOL bDropped;
		int nVirtKey = (int) wParam;    // virtual-key code 
		//int lKeyData = lParam;          // key data 

		

		WPARAM wNotify = 0;
		int vk = nVirtKey;

		if ( (GetStyle() & ES_AUTOSUGGEST ) && !(GetStyle() & ES_MULTILINE ) 
			&& (vk == VK_RETURN || vk == VK_ESCAPE || vk == VK_UP || vk == VK_DOWN) )
		{
			bDropped = (BOOL)SendMessageW(GetParent(), WM_COMMAND, EN_QUERY_SUGGETST_DROP, 0);

			if(vk == VK_UP || vk == VK_DOWN)
			{
				if (FALSE == bDropped)
				{
					wNotify = MAKEWPARAM(GetWindowLong(GWL_ID), EN_SUGGETST_DROP_SHOW);
				}
				else if( TRUE == bDropped  && vk == VK_DOWN )
				{
					wNotify = MAKEWPARAM(GetWindowLong(GWL_ID), EN_SUGGETST_DROP_SHOW_NEXT);
				}
				else if( TRUE == bDropped  && vk == VK_UP )
				{
					wNotify = MAKEWPARAM(GetWindowLong(GWL_ID), EN_SUGGETST_DROP_SHOW_PRE);
				}
			}

			if(vk == VK_RETURN || vk == VK_ESCAPE)
			{
				wNotify = MAKEWPARAM(GetWindowLong(GWL_ID), EN_SUGGETST_DROP_HIDE);
			}

			::PostMessage(GetParent(), WM_COMMAND, wNotify, (LPARAM)m_hWnd);
			bHandled = FALSE;
		}
		else
		{
			return DefWindowProc( uMsg, wParam, lParam );
		}

		return lRes;
	}

private:

	/**
	*@method   GetEditTextFormat
	*@brief    Get edit control align style, used by DrawText()
	*    
	*@param    const LONG lStyle    The style of edit
	*@return   UINT text align style
	*/
	UINT GetEditTextFormat(const LONG lStyle)
	{
		UINT uFormat = DT_SINGLELINE;//button上的字必须是一行

		//x方向
		if ( (lStyle & ES_CENTER)==ES_CENTER )//x方向,中
			uFormat |= DT_CENTER;
		else if ( (lStyle & ES_RIGHT)==ES_RIGHT )//x方向,右
			uFormat |= DT_RIGHT;
		else if ( (lStyle & ES_LEFT) == ES_LEFT )//x方向,左
			uFormat |= DT_LEFT;
		else//缺省,x中
			uFormat |= DT_CENTER;

		return uFormat;
	}

private:
	CharFilter	m_fnCharFilter;			/**< char filter callback function, WM_CHAR handle function will callback to filter chars */
	CRect		m_rtBkText;
};




  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-04-15 00:35:02  更:2022-04-15 00:36:17 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/16 21:13:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码