ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 Excel Home精品图文教程库
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
300集Office 2010微视频教程 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 202691|回复: 402

[原创] VBA类之一(初识类)

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2009-12-13 17:06 | 显示全部楼层 |阅读模式
本帖已被收录到知识树中,索引项:类和类模块
前言


       本文是依据本人自身的经验和体会,以及参考了众多网络资料写成,由于本人只是自学的VB和VBA,从未系统的学习过编程,编程水平有限,谬误之处,在所难免,还望各位不吝指正,万分感谢!
                                                  ——Joforn
                                                   2009年11月21日星期六



-----------分隔线-----------  




第一章 开头篇
                                ——认识类


       Visual Basic是基于对象的编程(注:本文所有的代码和讨论将都以VB为基础模型,不过我会尽量使用一些大家在VBA中常见的例子来做说明的。),所以我们常见的一些东西其实都与类有关。不需惊讶,是的,类其实离我们很近,它们正和我们天天相处。可以夸张的说,如果离开了类,我们的VB(VBA)就无用武之地了。
        我们还是先来看一条非常简单的语句,让我们亲身体会一下类与我们的距离:

  1. '例一
  2. Sub Hello()
  3.   Range("A1").Value = "Hello,world"
  4. End Sub
复制代码

        我们就暂且称之为VBA的Hello world吧,看到这个简单到不能再简单的例子,或许你笑了,这个根本就和类没有关系嘛。是的,我们在这里并没有明显的看到类,但是我们看到了Range("A1")这个对象,而在Range("A1")前面,还隐藏着一个对象:ActiveSheet,而在ActiveSheet前面又有一个ActiveWorkbook,而在ActiveWorkbook前面还有一个Application。是的,这些都是对象,我们依旧没有看到类。先别急,我们再从后面往前面看一遍:Range("A1").Value="Hello,World"   Value是什么?Value是一个Range("A1")这个对象的一个属性。那它是从哪来的呢?它是由Range类定义的,是的,我们发现了第一个出现在我们的面前的类 Range。你或许一下还接受不了,你刚刚在前不是还说Range("A1")是一个对象吗?怎么现在又说Range又是一个类呢。呵呵,不着急,我们还是看看下面的这个例子,或许你就很快就会明白了。

  1. '例二
  2. Sub Hello()
  3.   Dim Range1 As Range             '引用一个Range类
  4.   Set Range1 = Range("A1")       '将类实例化
  5.   Range1.Value = "Hello,world"   '这时,Range1又是一个对象了
  6.   Set Range1 = Nothing                '销毁一个类的实例
  7. End Sub
复制代码
       或许你现在已经发现了,我们引用了一个Range类,并将之实例化后修改了它的属性。而在例一中,我们只不过是将这一切都以隐藏起来,直接对一个对象Range("A1")修改它的属性,但Range("A1")这个对象正是引用了Ragne这个类,才具有了Range类的属性"Value"。类本身并不直接为我们做什么,但是,它却又一直默默的隐藏在幕后规化着我们的动作。是的,这就是类,它往往都是通过对象的方式展现在我们的面前,让我们无时无刻与之交流,却又常常在不经意间忽视了它的存在。现在再回到例一去看,就会很容易的发现,ActiveSheet实际引用了Worksheet类、ActiveWorkbook引用了Workbook类,而Application则引用了和它同名的Application类(这也正是我们会经常被混淆一个概念,一个对象可以和被它所引用的类同名),原来我们在短短一个赋值的语句中,已经在与这么多的类打交道。
        类就像是我们呼吸的空气,我们一直深在其中,却又常常忘却了它的存在。那我们又要怎样来区分类和对象呢?其实它们经常成对的出现在我们面前,只是一个看得见摸得着的,一个却深藏不露。我们可以这样去理解类与对象:类是一个概念或是一种定义,每个类拥有其自己的特征和行为方式,而对象就是某个类的实例。就像"人","人"是一个定义,你一看到"人"就会想到它是直立行走、有头、五官……等各种特征,但当"人"被具体到你、我、或是某一个人的时候,它就是一个对象了。
        既然类与我们和程序息息相关,那么我们更应该去好好的了解它了。让我们准备好行囊,到神秘的类的领地去好好浏览一番吧。








第二篇 走近类
                                ——类的基本写法及注意项


        如果说上一篇让我们看到类隐藏在神秘面纱后的面孔,那么现在我们将要做的就是真正的看清楚它。不过,在此之前我还是要让大家再次熟悉一下面的几个关键词:
Public                外部,可供类或是模块自身外调用;
Private               内部,只能由类或是模块内部直接调用;
Friend                友元,只能由工程内调用(即:在当前工程内部调用时相当于Public,而对外部工程相当于Private。)。
SubFunction  过程(不返回值)和函数(返回值),在类中我们可将其视为类的方法;
Property Get      返回属性的值;
Property Let      设置属性的值;
Property Set      设置对象属性的值(即:该属性含有对象引用)。
        [注:Property往往是成双出现在类中的某一个属性上,甚至可能三者同时出现,当一个类中某个属性只有Property Get时代表这一属性为只读属性,比如在VB工程中Form类的hWnd属性。]
Event           定义用户自定义的事件
        [注:Event可以像声明过程的参数一样来声明事件的参数,但有以下不同:事件不能有带命名参数、Optional 参数、或者 ParamArray参数。事件没有返回值。];
RaiseEvent      引发在一个类、窗体、或者文档中的模块级中声明的一个事件。
Implements      指定要在包含该语句的类模块中实现的接口或类。

       当我们熟悉上面的几个关键词后,再来分析类,就会发现类其实也挺简单。我们将从一个简单的类开始来正式的学习类的定义和使用方法。不过在此之前,我建议大家先去读读qee用兄写的一个帖子:VBA类:隐者的秘密qee用兄在那个帖子中图文并茂,已经将类清晰的描绘出来,并亲自带领我们写了一个类。在此,让我们向qee用兄道声辛苦,并送上万分感激。好了,现在,我们来写一个非常简单的类,用它来实现两个数的四则运算。

  1. '类的名称定义为:四则运算
  2. Option Explicit

  3. Public Event OnError(ByVal Number As Long, ByVal Description As String, ByVal Source As String)

  4. Private lNum1 As Double, lNum2 As Double

  5. Public Property Let Number1(ByVal Number As Double)
  6.   lNum1 = Number
  7. End Property

  8. Public Property Get Number1() As Double
  9.   Number1 = lNum1
  10. End Property

  11. Public Property Let Number2(ByVal Number As Double)
  12.   lNum2 = Number
  13. End Property

  14. Public Property Get Number2() As Double
  15.   Number2 = lNum2
  16. End Property

  17. Public Property Get 和() As Double

  18.   On Error GoTo Error01
  19.   
  20.   和 = lNum1 + lNum2
  21.   Exit Property
  22. Error01:
  23.   RaiseEvent OnError(Err.Number, Err.Description, Err.Source)
  24.   Err.Clear
  25.   和 = 0
  26. End Property

  27. Public Property Get 差() As Double

  28.   On Error GoTo Error02
  29.   
  30.   差 = lNum1 - lNum2
  31.   Exit Property
  32. Error02:
  33.   RaiseEvent OnError(Err.Number, Err.Description, Err.Source)
  34.   Err.Clear
  35.   差 = 0
  36. End Property

  37. Public Property Get 积() As Double

  38.   On Error GoTo Error03
  39.   
  40.   积 = lNum1 * lNum2
  41.   Exit Property
  42. Error03:
  43.   RaiseEvent OnError(Err.Number, Err.Description, Err.Source)
  44.   Err.Clear
  45.   积 = 0
  46. End Property

  47. Public Property Get 商() As Double

  48.   On Error GoTo Error04
  49.   
  50.   商 = lNum1 / lNum2
  51.   Exit Property
  52. Error04:
  53.   RaiseEvent OnError(Err.Number, Err.Description, Err.Source)
  54.   Err.Clear
  55.   商 = 0
  56. End Property

  57. Public Sub ClearNumber()
  58.   lNum1 = 0: lNum2 = 0
  59. End Sub
复制代码
       然后,将下面的代码写到ThisWorkbook模块中:

  1. Option Explicit

  2. Private WithEvents Class1 As 四则运算

  3. Sub TestClass()
  4.   If Class1 Is Nothing Then Set Class1 = New 四则运算
  5.   Class1.ClearNumber
  6.   Class1.Number1 = 9
  7. '  Class1.Number2 = 8
  8.   Debug.Print Class1.和
  9.   Debug.Print Class1.差
  10.   Debug.Print Class1.积
  11.   Debug.Print Class1.商
  12. End Sub

  13. Private Sub Class1_OnError(ByVal Number As Long, ByVal Description As String, ByVal Source As String)
  14.   MsgBox "类中发生错误,错误代码:" & Number & " 错误提示:" & Description & " 错误源:" & Source
  15. End Sub
复制代码
       这是一个非常简单的类的定义和应用(当然,实际编程时很少有人会为了四则运算而专门写个类。),虽然它很简单,不过它却几乎包含了类所有常见的特征:属性、方法、事件。运行TestClass后我们可以看到立即窗口中的输出,并接收到一个MsgBox的窗体,它提示了我们在类运行过程中产生了一个除数为零的错误,而这正是类中的OnError事件激发的。
       虽然这个类本身没有什么实际的应用的意义,但是我们却可以用它来做一个模版,我们只要参照这个类,就可以很快的写出自己想要的类。
       你现在是不是已经有了自己马上要编写一个类的冲动呢?那么我们开始准备动手吧,不过在你动手之前,我这里还要给你几点关于类的建议(这些都是笔者自身积累的经验或是前辈们的忠告。):
       一、在正式编写一个类的前期,最好尽可能规定好所有要用到的接口与方法。一旦一个类被正式发行后(封装成DLL并被其它的工程引用),后期维护时尽量不要再去修改已有的接口函数及其参数,除非你打算将所有的工程全部重写;
       二、为你类中的属性、方法、事件取个有意义的名字(特别是声明为Public方式的),如果允许的话,最好使用“工具”->“过程属性”为其添加一些描叙,说明它的意义或是调用方式,这样可以方便查看其属性并让客户(甚至是自己)能很快明白这个函数的用途;
       三、只暴露必须的接口供外部调用,不要将一些可能仅在类内部使用属性和方法暴露给类外部;
       四、不到万不得已,不要在类中定义Public方式的变量;
       五、重新编译新版本的DLL时,最好是按“版本相同版本兼容版本不兼容”这个次序来选择编译后DLL版本兼容性,即:能用“版本相同”方式就不要用“版本兼容”,更不要用“版本不兼容”,因为“版本不兼容”方式就意味着你的旧工程在其重新编译前将无法使用这个DLL。一旦准备使用无兼容性版本,那么就要考虑如何减少部件的用户以后可能遇到的麻烦。如果以后的版本还要做一些可能破坏兼容性的修改,那么最好把这些修改集中在一次进行。计划对不兼容进行的修改时,把工程作为一个新的任务来对待,应该投入尽可能多的精力进行计划,就象在创建新的部件。创建不兼容版本,这要求三个步骤:改变工程名,改变文件名以及通过选定不兼容进行编译(注:这三个步骤最好是一定要做到,否则将会让我们在后面安装引用此类时会发生各种问题而导致我们无法使用类);
       六、可能的话,不要忘了在类内部添加错误处理过程,尽管这些错误处理过程可能会损耗我们的运行时间,但它们能让我们的类更健壮;
       七、类中不能定义Public方式的结构(Type),如果必需要这么做的话,可以使用一个类来代替Type
       八、在类的Class_Terminate()事件中释放被当前类所引用的类或是数据。当我们某个类的实例已经不再需要时,请将其使用 Set [I]Object[/I] = Nothing 的方式来销毁它;
       九、……(留给大家填吧)……









第三篇 为什么要使用类
                                ——类的作用及其重要性


       现在,我们已经初步的认识了类,甚至我们已经可以自己开始写自己的类了。但是我们却还不是很清楚,类给我们带来了什么?我们为什么要用类?我们就先来看看类的好处吧。
       1、代码重用;
       2、降低程序的藕合度;
       3、增强程序的可拓展性;
       4、易修改性;
       5、……

       “藕合度”指的是程序模块间存在联系的紧密程度。如果一个程序各模块存在的联系太紧密时,就意味后期的修改将会非常复杂,甚至于有时为了修改某一个代码功能时可能要全部工程文件都修改一次,并且由于各模块间的函数与变量相互相交调用,严重的影响了程序的可读性。自然,我们不希望发生这种情况。而类正是我们规避这个情况发生的首选工具。因为类对于外部而言,我们所需要的仅仅是调用类的接口函数,而类内部的结构与运行我们并不需要去关心它。就像一个用来处理数据的类,我们只要约定好类的接口,就可以在外部直接获取或是修改我们想要的数据。但是数据存在哪,用什么方式或是结构组成我们根本就不需要了解,我们所要做的只是在外部直接调用就好了。这就意味着我们一旦约定好了接口,就可以同时开始开发前台与后台的数据处理块。而且,当我们需要修改数据的存储方式时,也会变得更加简单。比如:我们现有一个处理数据的类,它目前是使用文件来存储数据,现在我们需要把数据存储改为SQL数据库,这时我们要做的仅仅是在类内部修改要数据的处理过程,而对于整个工程而言,我们甚至不用做任何的修改就可以直接用了。这样对于大型工程而言,犹为重要,因为我们常常把类封装成DLL,这就意味我们仅仅只需要重新编译这个DLL,然后发布给用户升级就完成了这次修改,否则的话我们只能将整个工程全部修改后重新发布给用户才能使用。如果你经常使用VBA的话就一定会常常遇见Range这个类,Office每一次大版本升级,其内部的文件结构都会有变动,但是我们在VBA中对Range的操作却无需更改就可以直接使用了,这个正是因为Range类虽然内部改动了,但是它的接口还是一样,所以我们原有的VBA工程并不需要改动就可以直接使用了。
现在我们再来通过一个选中区域高亮显示的例子来看看类的其它几个特性吧:

  1. Option Explicit

  2. Private Type TypeRageLast
  3.   Range       As Range
  4.   ColorIndex  As Long
  5. End Type

  6. Private Const ColorIndex = 5&
  7. Private RangeLast() As TypeRageLast

  8. Private Sub Worksheet_SelectionChange(ByVal Target As Range)
  9.   Dim I As Long
  10.   Dim Range1 As Range
  11.   
  12.   On Error Resume Next
  13.   If UBound(RangeLast) = -1 Then
  14.     ReDim RangeLast(0)
  15.   ElseIf UBound(RangeLast) Then
  16.     For I = 1 To UBound(RangeLast)
  17.       If RangeLast(I).Range.Interior.ColorIndex = ColorIndex Then
  18.         RangeLast(I).Range.Interior.ColorIndex = RangeLast(I).ColorIndex
  19.       End If
  20.     Next I
  21.   End If
  22.   
  23.   I = 0
  24.   ReDim RangeLast(0)
  25.   
  26.   For Each Range1 In Target
  27.     I = I + 1: ReDim Preserve RangeLast(I)
  28.     RangeLast(I).ColorIndex = Range1.Interior.ColorIndex
  29.     Set RangeLast(I).Range = Range1   
  30.   Next Range1
  31.   Target.Interior.ColorIndex = ColorIndex
  32. End Sub
复制代码
这段代码的功能很简单(我们在这里并不去讨论它的功能),只是在工作表中,选中某个区域后就把该区域的背景色设置为并且恢复上次被选中区域的原有背景色。我们只要把上面的代码拷贝到我们需要的工作表的代码中就可以实现这个功能了。但是,当我在实际使用过程中就会发现一些新的问题:
       1、如果我们的工作簿中有200个工作表需要这个功能,我们就要复制200次——晕倒……
       2、复制完200次后,我们再在各个工作表中实际测试一下。就会发现新的问题:当我们在各个工作表之间切换焦点时,原工作表中最后一次被高亮的区域没有被还原!现在我们需要修改代码——在每一个工作表中Deactivate事件中加上相应处理代码。天啊,又得200次……又要晕了吧?
       3、文档开始正式使用了,但是当我们新增一个工作表后发现:我们又得重新切换到VBA中再复制一次代码!如果这个文档是给客户使用的,难道我们还要要求客户每次增加工作表时自己去复制VBA代码?……这次彻底晕了吧?^_^
       难道就没有更方便的方法吗?(下接二楼)


[ 本帖最后由 joforn 于 2009-12-15 17:16 编辑 ]

评分

2

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2009-12-13 17:07 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
(上接一楼)
       当然有了。我们就用类来试试吧,我们先建一个clsSelHeightColor类:

  1. ‘类名:clsSelHeightColor
  2. Option Explicit

  3. Private Type TypeRageLast
  4.   Range       As Range
  5.   ColorIndex  As Long
  6. End Type

  7. Private Const ColorIndex = 5&
  8. Private WithEvents mSheet As Worksheet
  9. Private WithEvents Workbook  As Workbook
  10. Private RangeLast() As TypeRageLast

  11. Private Sub mSheet_Activate()
  12.   Dim I As Long
  13.   Dim Range1 As Range
  14.   
  15.   On Error Resume Next
  16.   I = 0
  17.   ReDim RangeLast(0)
  18.   
  19.   For Each Range1 In Selection
  20.     I = I + 1: ReDim Preserve RangeLast(I)
  21.     RangeLast(I).ColorIndex = Range1.Interior.ColorIndex
  22.     Set RangeLast(I).Range = Range1
  23.     Range1.Interior.ColorIndex = ColorIndex
  24.   Next Range1
  25. End Sub

  26. Private Sub mSheet_Deactivate()
  27.   mSheet_SelectionChange Nothing
  28. End Sub

  29. Private Sub mSheet_SelectionChange(ByVal Target As Range)
  30.   Dim I As Long
  31.   Dim Range1 As Range
  32.   
  33.   On Error Resume Next
  34.   
  35.   If UBound(RangeLast) Then
  36.     For I = 1 To UBound(RangeLast)
  37.       If RangeLast(I).Range.Interior.ColorIndex = ColorIndex Then
  38.         RangeLast(I).Range.Interior.ColorIndex = RangeLast(I).ColorIndex
  39.       End If
  40.     Next I
  41.   End If
  42.   
  43.   I = 0
  44.   ReDim RangeLast(0)
  45.   
  46.   For Each Range1 In Target
  47.     I = I + 1: ReDim Preserve RangeLast(I)
  48.     RangeLast(I).ColorIndex = Range1.Interior.ColorIndex
  49.     Set RangeLast(I).Range = Range1
  50.   Next Range1
  51.   Target.Interior.ColorIndex = ColorIndex
  52. End Sub

  53. Public Property Set Sheet(ByVal mSheet1 As Worksheet)
  54.   If Not (mSheet Is Nothing) Then mSheet_SelectionChange Nothing
  55.   Set mSheet = mSheet1
  56.   Call mSheet_Activate
  57. End Property

  58. Public Property Get Sheet() As Worksheet
  59.   Set Sheet = mSheet
  60. End Property

  61. Private Sub Class_Initialize()
  62.   ReDim RangeLast(0)
  63. End Sub

  64. Private Sub Class_Terminate()
  65.   mSheet_SelectionChange Nothing
  66.   Erase RangeLast
  67. End Sub
复制代码
然后再把下面的代码复制到ThisWorkbook中的代码框中:

  1. Option Explicit

  2. Dim mSheets As Collection

  3. Private Sub Workbook_BeforeClose(Cancel As Boolean)
  4.   Set mSheets = Nothing
  5. End Sub

  6. Private Sub Workbook_NewSheet(ByVal Sh As Object)
  7.   Dim clsSheet As New clsSelHeightColor
  8.   
  9.   Set clsSheet.Sheet = Sh
  10.   mSheets.Add clsSheet
  11.   Set clsSheet = Nothing
  12. End Sub

  13. Private Sub WorkBook_Open()
  14.   Dim clsSheet As clsSelHeightColor
  15.   Dim Sheet As Worksheet
  16.   
  17.   On Error Resume Next
  18.   
  19.   Set mSheets = New Collection
  20.   For Each Sheet In Sheets
  21.       Set clsSheet = New clsSelHeightColor
  22.       Set clsSheet.Sheet = Sheet
  23.       mSheets.Add clsSheet
  24.       Set clsSheet = Nothing
  25.   Next
  26. End Sub
复制代码
保存后重开工作簿测试……嘿嘿,全部搞定!而且当我们要增加的Deactivate事件中的代码仅仅只需类中添加一次,只有一行代码(上面的类中已经添加好了),方便吧?当我们新增工作表时,也不再需要去复制一次代码了,一行代码都不用写了就已经实现了这个功能。当其它工作簿也需要这个代码时,我们只要在ThisWorkbook代码中增加相应的代码,并导入这个类就行了,比一个一个表去复制代码方便多——一想到相同的代码要在每个工作表中复制一次就头晕了。
       在此,我们对类的功能和特性有了一定的了解,不过,还有更多的东西在等待我们去发现。当下面向对象编程如此风行,类在其中的功劳是无与伦比的。
       现在,还犹豫什么?快去和类做一次“0距离接触”吧……

       在此,此文也终于要作一个小小的终结了。大家也跟随我初步对类作了点了解,也算是对类有了个第一印象吧。当然,类的高级应用和复杂型的类我们并没有去了解,或许哪天你会引领我去浏览一番?
       我也谢谢大家浪费不少时间来看完这个帖子,如果对我有意见或是觉得我在胡说八道要拍我砖头的,请下手留点情——我很怕疼,有意见扔扔鸡蛋或是RMB就好了。如果觉得看完对你有所帮助的话就帮顶下吧,或是你看完有什么问题的话也可以直接问,只要我会的我一定回(太难的问题还请恕我无能为力)。


[ 本帖最后由 joforn 于 2009-12-13 17:42 编辑 ]

选中高亮.rar

12.71 KB, 下载次数: 2825

最后一个例子的文档

点评

之二呢?快出呀  发表于 2012-4-12 00:20

评分

2

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2009-12-13 17:13 | 显示全部楼层
一个用类写出来的扫雷游戏,有兴趣的可以下载看看。已经在另一个版块发了,这里就不重新上传了。想下载的点击这里下载。
类之二酝酿中……

[ 本帖最后由 joforn 于 2010-1-6 17:06 编辑 ]

TA的精华主题

TA的得分主题

发表于 2009-12-13 17:14 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
我回一下。。。

TA的精华主题

TA的得分主题

发表于 2009-12-13 17:33 | 显示全部楼层
虽然看了不少类的介绍,但始终没自己写过一个类,

不敢去捅破这层膜

TA的精华主题

TA的得分主题

发表于 2009-12-13 17:40 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2009-12-13 17:48 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
板凳学习,谢谢LZ分享

TA的精华主题

TA的得分主题

发表于 2009-12-13 17:55 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
楼主辛苦,学习学习。

TA的精华主题

TA的得分主题

发表于 2009-12-13 18:02 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
排队支持楼主。收藏之

TA的精华主题

TA的得分主题

 楼主| 发表于 2009-12-13 20:26 | 显示全部楼层
正在打算用纯代码写个扫雷游戏…… 那个要写完了,基本上就可真正的展示一下类的威力……
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

关闭

最新热点上一条 /1 下一条

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-4-20 04:52 , Processed in 0.042999 second(s), 12 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表