`
android_mylove
  • 浏览: 399567 次
社区版块
存档分类
最新评论

VC++改变对话框的背景色和VC++制作伸展自如、收缩随意的对话框

 
阅读更多

改变对话框的背景色

黄基前(广西桂林)

---- 笔者曾在《软件报》2000年第5期中讨论过如何改变控件的颜色,但还有
相当一部分的读者来信提问:一个基于对话框的MFC AppWizard应用程序中,如
何改变对话框的背景颜色呢?对于这个问题,其实可以由几种不同的方法来实
现,具体如下(粗斜体代码为增添的):

---- 方法一:调用CWinApp类的成员函数SetDialogBkColor来实现。

---- 其中函数的第一个参数指定了背景颜色,第二个参数指定了文本颜色。
下面的例子是将应用程序对话框设置为蓝色背景和红色文本,步骤如下:

---- ① 新建一个基于Dialog的MFC AppWizard应用程序ExampleDlg。

---- ② 在CExampleDlgApp ::InitInstance()中添加如下代码:

BOOL CExampleDlgApp: : InitInstance ( )
{

CExampleDlgDlg dlg;
m_pMainWnd = &dlg;

//先于DoModal()调用,将对话框设置为蓝色背景、红色文本
SetDialogBkColor(RGB(0,0,255),RGB(255,0,0));
int nResponse = dlg.DoModal();

}

---- 编译并运行,此时对话框的背景色和文本色已发生了改变。值得注意的
是:在调用DoModal()之前必须先调用SetDialogBkColor,且此方法是将改变
应用程序中所有的对话框颜色,并不能针对某一个指定的对话框。
---- 方法二:重载OnPaint(),即WM_PAINT消息。有关代码如下(以上例工程为准):

void CExampleDlgDlg::OnPaint()
{
if (IsIconic())

else
{
CRect rect;
CPaintDC dc(this);
GetClientRect(rect);
dc.FillSolidRect(rect,RGB(0,255,0)); //设置为绿色背景

CDialog::OnPaint();
}


---- 方法三:重载OnCtlColor (CDC* pDC, CWnd* pWnd, UINT nCtlColor),
即WM_CTLCOLOR消息。具体步骤如下(以上例工程为准):
---- ①在CExampleDlgDlg的头文件中,添加一CBrush的成员变量:

class CExampleDlgDlg : public CDialog
{
...
protected:
CBrush m_brush;
...
};


---- ②在OnInitDialog()函数中添加如下代码:
BOOL CExampleDlgDlg::OnInitDialog()
{
...
// TODO: Add extra initialization here
m_brush.CreateSolidBrush(RGB(0, 255, 0)); // 生成一绿色刷子
...
}

---- ③利用ClassWizard重载OnCtlColor(…),即WM_CTLCOLOR消息:
HBRUSH CExampleDlgDlg::OnCtlColor
(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
/*
** 这里不必编写任何代码!
**下行代码要注释掉
** HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
*/

return m_brush; //返加绿色刷子
}


---- 方法四:还是重载OnCtlColor (CDC* pDC, CWnd* pWnd, UINT nCtlColor),
即WM_CTLCOLOR消息。具体步骤如下(以上例工程为准):
---- 步骤①、②同上方法三中的步骤①、②。

---- 步骤③利用ClassWizard重载OnCtlColor(…)(即WM_CTLCOLOR消息)时则有
些不同:

HBRUSH CExampleDlgDlg::OnCtlColor
(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

//在这加一条是否为对话框的判断语句
if(nCtlColor ==CTLCOLOR_DLG)
return m_brush; //返加绿色刷子
return hbr;
}

---- 编译并运行即可。
---- 关于如何改变对话框背景颜色的问题,可能还有很多种不同方法可以实现,
笔者在这仅举出四种常见的方法。其中方法三的编程似乎有点不太规范,方法四则
要比方法三正统些,笔者这样的对比举例是为了拓宽VC编程爱好者特别是初学者的
编程思路,读者可以根据实际情况选用其中的一种。如果再结合《软件报》2000年第
5期中改变对话框上的控件颜色,相信会使您的MFC应用程序"增色"不少。

转载声明:本文转自http://wmnmtm.blog.163.com/blog/static/382457142009629110146/

===============================================================

VC++制作伸展自如、收缩随意的对话框

Visual C++以其可视化的编程风格成为目前Windows程序设计与开发的主流开发工具。而对话框在Visual C++编程中使用的尤其多。诸如模式对话框、无模式对话框、基于对话框的应用程序等。绝大部分的VC++的书籍中都花费大量的篇幅与笔墨来讲解对话框,这充分证明了对话框在Windows应用程序中的作用。
很多人可能都用过Bitware软件,不知大家还记不记得其界面对话框就可以伸展自如。按下一个按钮,对话框就向水平方向或垂直方向扩展。再按一下按钮,对话框又回复到原来的大小。其实这并不是一个很复杂的问题,下面我们就来讲解如何制作伸展自如的对话框。
1 打开VisualC++工作台,新建工程设为aaa。

2 创建基于对话框的应用程序如下所示:
其余选择皆为缺省即可。

3 在对话框资源中增加控件资源,如下图所示:

其中,最靠右边的一排控件和最靠近下面的两排控件将在对话框伸展或收缩时显示出来或被遮盖。并且为了示例方便,我们有意将他们的值对应起来。并且我们需要通过ClassWizard给每个控件分别关联成员变量,如下所示:
参考DoDataExchange()函数我们就可以知道每个控件所关联的变量了,如下所示:
DDX_Text(pDX, IDC_HEIGHT, m_wHeight);
DDX_Text(pDX, IDC_STREAM_ID, m_wStreamID);
DDX_Text(pDX, IDC_WIDTH, m_wWidth);
DDX_Text(pDX, IDC_SEQUENCE_ORDER, m_wSequenceOrder);
DDX_Text(pDX, IDC_MAX_RATE, m_dwMaxRate);
DDX_Text(pDX, IDC_MIN_RATE, m_dwMinRate);
DDX_Text(pDX, IDC_HEIGHT2, m_wHeight2);
DDX_Text(pDX, IDC_MAX_RATE2, m_dwMaxRate2);
DDX_Text(pDX, IDC_MIN_RATE2, m_dwMinRate2);
DDX_Text(pDX, IDC_SEQUENCE_ORDER2, m_wSequenceOrder2);
DDX_Text(pDX, IDC_STREAM_ID2, m_wStreamID2);
DDX_Text(pDX, IDC_WIDTH2, m_wWidth2);
DDX_Check(pDX, IDC_HORIZONTAL, m_bHorizontal);
DDX_Check(pDX, IDC_VERTICAL, m_bVertical);
实际上,我们也可以不用ClassWizard而直接将上面的一段代码copy到DoDataExchange()函数的
//{{AFX_DATA_MAP(CAaaDlg)
......
//}}AFX_DATA_MAP
之间,(注意一定要在“//{{AFX_DATA_MAP(CAaaDlg)”与“//}}AFX_DATA_MAP”之间)。
同时在aaaDlg.h文件中,在
//{{AFX_DATA(CAaaDlg)
enum { IDD = IDD_AAA_DIALOG };
......
//}}AFX_DATA
之间增加如下变量定义即可:
(注意一定要在“//{{AFX_DATA(CAaaDlg)”与“//}}AFX_DATA”之间)
UINT m_wHeight;
UINT m_wStreamID;
UINT m_wWidth;
UINT m_wSequenceOrder;
DWORD m_dwMaxRate;
DWORD m_dwMinRate;
UINT m_wHeight2;
DWORD m_dwMaxRate2;
DWORD m_dwMinRate2;
UINT m_wSequenceOrder2;
UINT m_wStreamID2;
UINT m_wWidth2;
BOOL m_bHorizontal;
BOOL m_bVertical;

5 在完成上面的步骤后,我们就可以定义几个新的变量用来保存窗口伸展状态时的信息以及收缩状态时的信息。如下:
WORD m_wOrigrinWidth; //原始状态下的窗口宽度
WORD m_wReducedWidth; //收缩状态下的窗口宽度

WORD m_wOrigrinHeight; //原始状态下的窗口高度
WORD m_wReducedHeight; //收缩状态下的窗口高度

WORD m_screenWidth; //屏幕宽度
WORD m_screenHeight; //屏幕高度

在完成以上所有的步骤后,就可以对窗口的伸展与收缩进行随心所欲的控制了,首先我们来侃侃具体的代码,下面再进行具体的解释。代码为:
CenterWindow(NULL);

m_screenWidth = GetSystemMetrics(SM_CXSCREEN);
m_screenHeight = GetSystemMetrics(SM_CYSCREEN);

WINDOWPLACEMENT* lpwndpl=new WINDOWPLACEMENT;
GetWindowPlacement(lpwndpl);
m_wOrigrinWidth = lpwndpl->rcNormalPosition.right;
m_wOrigrinWidth -= lpwndpl->rcNormalPosition.left;
m_wOrigrinHeight = lpwndpl->rcNormalPosition.bottom;
m_wOrigrinHeight -= lpwndpl->rcNormalPosition.top;

LPRECT lpRect1,lpRect2;
lpRect1=new RECT;
lpRect2=new RECT;
GetDlgItem(IDC_PROGRESS_BAR)->GetWindowRect(lpRect1);
GetDlgItem(IDC_STREAM_ID)->GetWindowRect(lpRect2);

lpwndpl->rcNormalPosition.right=(lpRect1->right+lpRect2->left)/2;
m_wReducedWidth = lpwndpl->rcNormalPosition.right;
m_wReducedWidth -= lpwndpl->rcNormalPosition.left;

GetDlgItem(IDC_PROGRESS_BAR)->GetWindowRect(lpRect1);
GetDlgItem(IDC_SEQUENCE_ORDER2)->GetWindowRect(lpRect2);
lpwndpl->rcNormalPosition.bottom=(lpRect1->bottom+lpRect2->top)/2;
m_wReducedHeight = lpwndpl->rcNormalPosition.bottom;
m_wReducedHeight -= lpwndpl->rcNormalPosition.top;

delete lpRect1;
delete lpRect2;

if(m_bHorizontal == TRUE)
{
lpwndpl->rcNormalPosition.right = lpwndpl->rcNormalPosition.left;
lpwndpl->rcNormalPosition.right += m_wOrigrinWidth;

lpwndpl->rcNormalPosition.bottom = lpwndpl->rcNormalPosition.top;
lpwndpl->rcNormalPosition.bottom += m_wReducedHeight;
}
else
{
lpwndpl->rcNormalPosition.right = lpwndpl->rcNormalPosition.left;
lpwndpl->rcNormalPosition.right += m_wReducedWidth;

lpwndpl->rcNormalPosition.bottom = lpwndpl->rcNormalPosition.top;
lpwndpl->rcNormalPosition.bottom += m_wReducedHeight;
}

if(m_bVertical == TRUE)
{
lpwndpl->rcNormalPosition.right = lpwndpl->rcNormalPosition.left;
lpwndpl->rcNormalPosition.right += m_wReducedWidth;

lpwndpl->rcNormalPosition.bottom = lpwndpl->rcNormalPosition.top;
lpwndpl->rcNormalPosition.bottom += m_wOrigrinHeight;
}
else
{

lpwndpl->rcNormalPosition.right = lpwndpl->rcNormalPosition.left;
lpwndpl->rcNormalPosition.right += m_wReducedWidth;

lpwndpl->rcNormalPosition.bottom = lpwndpl->rcNormalPosition.top;
lpwndpl->rcNormalPosition.bottom += m_wReducedHeight;
}

SetWindowPlacement(lpwndpl);

上面这段代码首先将窗口置于屏幕中间,这可以通过函数CenterWindow(GetDesktopWindow()) 来实现,函数 CenterWindow()的用法为:
void CenterWindow( CWnd* pAlternateOwner = NULL );
其中参数pAlternateOwner指向所想居中的窗口的指针。
然后利用函数GetSystemMetrics( int nIndex )得到系统当前设置如屏幕分辨率等。
nIndexs= SM_CXSCREEN 时函数返回屏幕的宽度;返回值单位为像素点。
nIndexs= SM_CYSCREEN 时函数返回屏幕的高度;返回值单位为像素点。
函数BOOL GetWindowPlacement( WINDOWPLACEMENT* lpwndpl ) 是最重要的。他的参数为一个指向结构变量WINDOWPLACEMENT的指针(lpwndpl);其中WINDOWPLACEMENT结构变量数据结构具体为:
typedef struct tagWINDOWPLACEMENT { /* wndpl */
UINT length;
UINT flags;
UINT showCmd;
POINT ptMinPosition;
POINT ptMaxPosition;
RECT rcNormalPosition;
} WINDOWPLACEMENT;
他包含了窗口在屏幕上的定位信息。其中成员变量的含义为:
length:指结构变量的长度,单位字节。
flags: 标志值,控制窗口最小化或窗口还原的方法,可以取如下值:
WPF_SETMINPOSITION:指定窗口最小化时的x位置和y位置。
WPF_RESTORETOMAXIMIZED:指定窗口以最大化方式还原,尽管可能窗口并不是在最大化时最小化的。不改变窗口的缺省还原方式。
showCmd:指定窗口的当前显示状态。可以取值:
SW_HIDE:隐藏窗口并激活另一窗口。
SW_MINIMIZE:最小化指定窗口并激活系统窗口列表中最顶层窗口。
SW_RESTORE:激活并显示窗口,如果窗口处于最小化或最大化状态,则窗口还原到原始大小和位置。
SW_SHOW:以窗口的当前大小和位置激活并显示窗口。
SW_SHOWMAXIMIZED:以最大化方式激活并显示窗口。
SW_SHOWMINIMIZED:以图标方式激活并显示窗口。
SW_SHOWMINNOACTIVE:以图标方式窗口。 但不改变窗口的活动状态。
SW_SHOWNA:以窗口的当前状态显示窗口。
SW_SHOWNOACTIVATE:以窗口最近一次的大小和位置显示窗口。 但不改变窗口的活 动状态。
SW_SHOWNORMAL:激活并显示窗口。如果窗口被最大化或最小化,则窗口还原到原始大小和位置。
ptMinPosition:指定窗口最小化时的左伤角坐标。
ptMaxPosition:指定窗口最大化时的左伤角坐标。
rcNormalPosition:指定窗口在还原时的坐标。
通过灵活使用函数GetWindowPlacement()就可以得到窗口的配置信息。
看到这,可能有些读者已经想到了GetWindowPlacement()函数的姐妹函数SetWindowPlacement(),不用多说,其用法如下:
BOOL SetWindowPlacement( WINDOWPLACEMENT* lpwndpl );
显然,通过函数SetWindowPlacement(),再加以简单的计算,我们就可以来设置窗口的位置、大小以及状态等,从而可以自如地控制窗口显示与否以及窗口的大小、位置等。这里我们就不再多解释了。

6 利用ClassWizard对控件IDC_HORIZONTAL和IDC_VERTICAL增加消息映射BB_CLICKED,

并分别在消息映射函数中增加如下代码如下:
void CAaaDlg::OnHorizontal()
{
// TODO: Add your control notification handler code here
m_bHorizontal = !m_bHorizontal;

UpdateData(FALSE);

WINDOWPLACEMENT* lpwndpl=new WINDOWPLACEMENT;
GetWindowPlacement(lpwndpl);
if(m_bHorizontal == TRUE)
{
lpwndpl->rcNormalPosition.right = lpwndpl->rcNormalPosition.left;
lpwndpl->rcNormalPosition.right += m_wOrigrinWidth;
/*
lpwndpl->rcNormalPosition.bottom = lpwndpl->rcNormalPosition.top;
lpwndpl->rcNormalPosition.bottom += m_wReducedHeight;
*/
}
else
{
lpwndpl->rcNormalPosition.right = lpwndpl->rcNormalPosition.left;
lpwndpl->rcNormalPosition.right += m_wReducedWidth;
/*
lpwndpl->rcNormalPosition.bottom = lpwndpl->rcNormalPosition.top;
lpwndpl->rcNormalPosition.bottom += m_wReducedHeight;
*/
}

SetWindowPlacement(lpwndpl);
delete lpwndpl;
}

void CAaaDlg::OnVertical()
{
// TODO: Add your control notification handler code here
m_bVertical = !m_bVertical;

UpdateData(FALSE);

WINDOWPLACEMENT* lpwndpl=new WINDOWPLACEMENT;
GetWindowPlacement(lpwndpl);

if(m_bVertical == TRUE)
{
lpwndpl->rcNormalPosition.bottom = lpwndpl->rcNormalPosition.top;
lpwndpl->rcNormalPosition.bottom += m_wOrigrinHeight;
}
else
{
lpwndpl->rcNormalPosition.bottom = lpwndpl->rcNormalPosition.top;
lpwndpl->rcNormalPosition.bottom += m_wReducedHeight;
}

SetWindowPlacement(lpwndpl);
delete lpwndpl;
}

7 最后利用ClassWizard对控件IDC_BEGIN_SIMULATE增加消息映射BB_CLICKED。在这里我们模拟了一个100次循环的随机数显示程序。具体大妈如下:
void CAaaDlg::OnBeginSimulate()
{
// TODO: Add your control notification handler code here
srand((unsigned)time(NULL));
char temp[10];
SetDlgItemText(IDC_STATIC11,"Now Beginning ...");
for(int i=0;i<m_maxRange;i++)
{
m_pProgressCtrl->SetPos(i);
m_wSequenceOrder = m_wSequenceOrder2 = i;
m_wStreamID = m_wStreamID2 = rand();
m_wHeight = m_wHeight2 = rand();
m_wWidth = m_wWidth2 = rand();
m_dwMaxRate = m_dwMaxRate2 = rand();
m_dwMinRate = m_dwMinRate2 = rand();
switch(i%4)
{
case 0:
sprintf(temp,"欢 迎 使 用");
break;
case 1:
sprintf(temp,"迎 使 用 欢");
break;
case 2:
sprintf(temp,"使 用 欢 迎");
break;
case 3:
sprintf(temp,"用 欢 迎 使");
break;
}
SetDlgItemText(IDC_WELCOME,temp);
UpdateData(FALSE);
UpdateWindow();
Sleep(50);
}
SetDlgItemText(IDC_WELCOME,"欢 迎 使 用");
SetDlgItemText(IDC_STATIC11,"Now Finnished ...");
}

8 完成以上所有的步骤之后,我们就可以编译程序并运行。运行结果如下:

(a) (b)
(a): 程序启动时对话框状态
(b): 点击Horizontal框后对话框状态。

(c) (d)
(c): 点击Vertical框后对话框状态。
(d): 点击BeginSimulating按钮后系统模拟运行对话框状态。

在本程序中,我们还用到了一些其它的技巧如修改窗口标题,进程状态条的显示、动态字符串显示以及不通过ClassWizard而直接通过在.cpp和.h文件中增加代码的方法来关联控件与成员变量和消息映射等,这些都是一些很实用的技巧,读者可以参考上面的代码以及源程序细细体会,这里我们就不多说了。
程序源工程文件见aaa.zip。在VisualC++6.0下编译通过。

转载声明:本文转自http://wmnmtm.blog.163.com/blog/static/382457142009629105340377/

===============================================================

分享到:
评论

相关推荐

    VC++对话框自动布局

    4. **对话框资源编辑器的锚定(Anchor)和自动伸展(Auto Stretch)特性**: 在Visual Studio的资源编辑器中,可以为对话框上的控件设置锚定属性,使其能够根据对话框的边界自动调整大小。锚定控件的角落到对话框的...

    VC 实现点击按钮折叠展开窗口部分区域.rar

     ①在对话框中放置一个按钮控件,清除其文本,把形状调整为细条状;  ②为按钮定义变量,类型改为CPluckButton;  ③在对话框的OnInitDialog()函数中用SetPluckButStyle()函数设置按钮初始风格。

    vc++6.0 设计的伸展窗体程序

    我们将主要关注以下几个方面:窗体的设计、伸展和收缩功能的实现以及VC++6.0编程的基本概念。 首先,我们需要了解VC++6.0是一个集成开发环境(IDE),它提供了用于创建Windows应用程序的工具和库。在创建伸展窗体...

    VC++经验技巧宝典配套代码06章

    0374设置对话框背景色 0375使用话刷绘制背景色 0376设置窗体颜色渐变 0377将对话框以位图形式保存到磁盘中 0378在对话框中显示HTML文件 0379在对话框中创建视图 0380如何共享对话框资源 0381如何实现窗体继承 0384在...

    android属性动画(伸展收缩)

    在这个"android属性动画(伸展收缩)"的示例中,我们将深入探讨如何利用属性动画来实现布局的伸展和收缩效果。这种效果常见于许多应用程序的展开式菜单、抽屉导航或折叠式控件中,为用户提供更丰富的视觉体验。 ...

    wpf datagrid RowDetailsTemplate绑定点击按钮会有伸展收缩

    本篇文章将深入探讨如何在DataGrid的RowDetailsTemplate中绑定点击按钮,以及如何实现行的伸展和收缩效果。 首先,我们需要了解RowDetailsTemplate的基本用法。在XAML中,我们可以使用DataGrid.RowDetailsTemplate...

    jQuery实现的FAQ文字伸展、收缩特效.rar

    jQuery实现的FAQ文字伸展、收缩特效,一段文字目录、内容展开与折叠的效果,可看作是一个非常酷的菜单,怎么说了,就像手风琴菜单一样,点右上角的小按钮可全部展开内容,再点击展开内容中的某一条标题,会继续展开...

    jQuery菜单滑动伸展收缩特效.zip

    "jQuery菜单滑动伸展收缩特效"是一个典型的应用实例,它旨在模仿淘宝网的菜单行为,实现优雅的展开和折叠效果。这个特效能够使用户界面更加友好,提升用户体验。 首先,jQuery的核心在于其简洁的API,使得开发者...

    VC++位图特效显示合集—交错、百叶窗、随机积木、飞入伸展

    《Windows界面编程第十三篇 位图显示特效合集》 ...配套程序。 自己封装了一些常用字的位图特效显示函数——交错、百叶窗、随机积木、飞入伸展。代码清晰可读,推荐大家试用下。

    asp无限级分类加js收缩伸展功能代码

    总的来说,"asp无限级分类加js收缩伸展功能代码"是一个结合了后端ASP处理无限级分类逻辑和前端JavaScript实现动态展示的技术方案。通过这种方式,可以创建一个可扩展性强、用户交互性好的分类系统。在开发过程中,...

    jQuery点击伸展收缩手风琴代码.zip

    总的来说,"jQuery点击伸展收缩手风琴代码"是一种实用的网页交互组件,结合了jQuery的易用性和Material Design的美观性,为用户提供了一种高效的信息浏览方式。通过深入理解并运用这段代码,开发者可以提高网站的...

    可伸展收缩的内容显示栏目.rar

    标题中的“可伸展收缩的内容显示栏目”暗示了一个网页设计中的交互功能,它允许用户根据需要展开或隐藏具体内容。在网页设计中,这样的功能通常通过JavaScript(JS)实现,以提供动态和用户友好的界面体验。...

    用Qt实现QQ好友列表界面伸缩功能(完全一模一样)(伸展和收缩、抽屉效果、类似树形控件)(鼠标划过QSS效果).zip

    总结用Qt的自定义按钮和QWidget界面实现QQ好友列表的界面伸展和收缩功能,以及鼠标滑过、鼠标单击的QSS样式表效果。原理讲解博客地址如下:https://blog.csdn.net/naibozhuan3744/article/details/102537152。编译...

    JS左边可伸展导航菜单

    4. 当点击事件触发时,JavaScript会更改子菜单的CSS属性,如`display`或使用过渡效果改变`height`,使得子菜单伸展或收缩。 5. 为了提供更好的反馈,可以添加过渡效果,如使用CSS的`transition`属性。 此外,“导航...

    基于jquery+bootstrap的侧边栏收缩菜单

    在网页设计和开发中,创建一个可伸展和收缩的侧边栏菜单是常见的需求,尤其是在响应式设计中。这个项目使用了jQuery和Bootstrap这两个强大的工具来实现这一功能。jQuery是一个轻量级、功能丰富的JavaScript库,而...

    支持界面列表视图单元的伸展和收缩特效

    "支持界面列表视图单元的伸展和收缩特效"这个项目,就是针对这种需求的一个实例,它实现了列表视图(UITableView)中单元格(UITableViewCell)的扩展和收缩功能,通常被称为下拉列表或展开式列表。在iOS应用中,...

    Flash扁字伸展效果

    这种效果的核心是利用Flash的ActionScript编程语言来控制文字的变形和运动,使原本扁平的文字逐渐拉伸或收缩,呈现出动态的伸展效果。在Flash CS4中,这种效果可以通过以下步骤实现: 1. **创建文字对象**:首先,...

Global site tag (gtag.js) - Google Analytics