十一、Gtk4-Instance Initialization and destruction

news2024/11/23 22:29:14

  文本文件编辑器(tfe)的新版本将在本节和以下四节中编写。它是tfe5。与之前的版本相比,有很多变化。它们位于两个目录中,src/tfe5和src/tfetextview。

1 封装

我们将C源文件分为两部分。但就封装而言,这还不够。

  • tfe.c包含除Tfe TextView之外的所有内容。它至少应该分为两部分,tfeapplication.c和tfenotebook.c。
  • 头文件也需要组织。

然而,首先,我想关注TfeTextView对象。它是GtkTextView的一个子对象,其中有一个新的成员文件。重要的是管理file指向的Gfile对象。

  • 当你创建(或初始化)TfeTextView,对于GFile什么是必须的?
  • 当你销毁TfeTextView,对于GFile什么是必须的?
  • TfeTextView是否应该自己读/写文件?
  • 它如何与其他的对象交流?

在考虑类、实例和信号之前,你至少需要知道它们。我将在本节和下一节中解释它们。之后我会解释:

  • 组织功能(Organizing functions)
  • 如何使用GtkFileChooserDialog

2 GObject and its children

GObject及其子对象都是对象,它们既有class C结构,也有object C结构。首先,考虑实例。一个实例是具有对象结构的内存。下面是TfeTextView的结构。

/* This typedef statement is automatically generated by the macro G_DECLARE_FINAL_TYPE */
typedef struct _TfeTextView TfeTextView;

struct _TfeTextView {
  GtkTextView parent;
  GFile *file;
};

该结构的成员如下:

  • 父类的类型是GtkTextView,这是C结构体。它在gtktextview.h中声明。GtkTextView是TfeTextView的父类。
  • file是一个GFile类型的指针。如果没有文件对应于TfeTextView实例,它可以是NULL。

您可以在GTK和GLib的源文件中找到父类对象结构的声明。下面的代码是从源文件中提取的(不完全相同)。

typedef struct _GObject GObject;
typedef struct _GObject GInitiallyUnowned;
struct  _GObject
{
  GTypeInstance  g_type_instance;
  volatile guint ref_count;
  GData         *qdata;
};

typedef struct _GtkWidget GtkWidget;
struct _GtkWidget
{
  GInitiallyUnowned parent_instance;
  GtkWidgetPrivate *priv;
};

typedef struct _GtkTextView GtkTextView;
struct _GtkTextView
{
  GtkWidget parent_instance;
  GtkTextViewPrivate *priv;
};

在每个结构中,其父元素声明在成员元素的顶部。所以,所有的父类都包含在子对象中。TfeTextView的结构如下图所示。
在这里插入图片描述
派生类(父类)都有它们自己的私有数据区,这些私有数据区不包含在上述结构中。例如,GtkWidget的私有数据为GtkWidgetPrivate (C结构体)。

注意声明(declarations)不是定义(definitions)。因此,在声明C结构体时不会分配内存。在调用tfe_text_view_new函数时,会从堆区域为它们分配内存。同时,对于TfeTetView父类的私有区域也会被分配。它们从TfeTextView隐藏,不能直接访问它们。创建的内存称为实例(instance)。创建TfeTextView实例时,会给它三个数据区域。

  • 实例(C结构体)。
  • GtkWidgetPrivate结构体。
  • GtkTextViewPrivate结构体。

TfeTextView函数只能访问其实例。GtkWidgetPrivate和GtkTextViewPrivate被父类的函数使用。请看下面的例子。

GtkWidget *tv = tfe_text_view_new ();
GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));

父函数gtk_text_view_get_buffer访问GtkTextViewPrivate数据(由tv拥有)。私有区域中有一个指向GtkBuffer的指针,该函数返回该指针。(实际的行为有点复杂。)

TfeTextView实例像这样继承了父类函数。

每次调用tfe_text_view_new函数时,都会创建一个TfeTextView实例。因此,可以存在多个TfeTextView实例。

3 初始化TfeTextView实例

函数tfe_text_view_new创建了一个新的TfeTextView实例。

1 GtkWidget *
2 tfe_text_view_new (void) {
3   return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, "wrap-mode", GTK_WRAP_WORD_CHAR, NULL));
4 }

调用这个函数时,会创建并初始化一个TfeTextView实例。初始化过程如下。

  • 当创建实例时,也创建了GtkWidgetPrivate和GtkTextViewPrivate结构体。
  • 在TfeTextView实例中初始化GObject (GInitiallyUnowned)部分。
  • 在TfeTextView实例和GtkWidgetPrivate结构中初始化GtkWidget部分(第一个priv)。
  • 初始化GtkTextView部分(第二个priv)在TfeTextView实例和GtkTextViewPrivate结构。
  • 在TfeTextView实例中初始化TfeTextView部分(文件)。

第二到第四步由g_object_init、gtk_widget_init和gtk_text_view_init完成。它们由系统自动调用,你不需要关心它们。第四步是由tfetextview.c中的函数tfe_text_view_init完成的。

1 static void
2 tfe_text_view_init (TfeTextView *tv) {
3   tv->file = NULL;
4 }

这个函数只是将tv->file初始化为NULL。

4 方法和类

在Gtk中,所有从GObject派生的对象都有类和实例(抽象对象除外)。实例是C结构体的内存,在前两个小节中描述过。每个对象可以有多个实例。这些实例具有相同的结构。实例只有数据。因此,它没有定义对象的行为。我们至少需要两样东西。一个是函数,另一个是类方法。

你已经见过很多函数了。例如,

  • TfeTextView *tfe_text_view_new (void);是一个创建TfeTextView实例的函数。
  • GtkTextBuffer *gtk_text_view_get_buffer (GtkTextView *textview)是一个从GtkTextView获取GtkTextBuffer的函数。

函数是公有的,这意味着它们可以被其他对象使用。它们类似于面向对象语言中的公共方法。

类(C结构体)主要由指向函数指针组成。这些函数被称为类方法,由对象本身或其后代对象使用。例如,GObject类在GLib源文件的GObject .h中声明。

 1 typedef struct _GObjectClass             GObjectClass;
 2 typedef struct _GObjectClass             GInitiallyUnownedClass;
 3 
 4 struct  _GObjectClass
 5 {
 6   GTypeClass   g_type_class;
 7 
 8   /*< private >*/
 9   GSList      *construct_properties;
10 
11   /*< public >*/
12   /* seldom overridden */
13   GObject*   (*constructor)     (GType                  type,
14                                  guint                  n_construct_properties,
15                                  GObjectConstructParam *construct_properties);
16   /* overridable methods */
17   void       (*set_property)		(GObject        *object,
18                                          guint           property_id,
19                                          const GValue   *value,
20                                          GParamSpec     *pspec);
21   void       (*get_property)		(GObject        *object,
22                                          guint           property_id,
23                                          GValue         *value,
24                                          GParamSpec     *pspec);
25   void       (*dispose)			(GObject        *object);
26   void       (*finalize)		(GObject        *object);
27   /* seldom overridden */
28   void       (*dispatch_properties_changed) (GObject      *object,
29 					     guint	   n_pspecs,
30 					     GParamSpec  **pspecs);
31   /* signals */
32   void	     (*notify)			(GObject	*object,
33 					 GParamSpec	*pspec);
34 
35   /* called when done constructing */
36   void	     (*constructed)		(GObject	*object);
37 
38   /*< private >*/
39   gsize		flags;
40 
41   gsize         n_construct_properties;
42 
43   gpointer pspecs;
44   gsize n_pspecs;
45 
46   /* padding */
47   gpointer	pdummy[3];
48 };
49 

第23行有一个指向函数dispose的指针。

void (*dispose) (GObject *object);

这个声明有点复杂。标识符dispose之前的星号表示指针。因此,指针分配指向一个只有一个参数的函数,它指向一个GObject结构,并且没有返回值。同样,第24行说finalize是一个指向函数的指针,它有一个参数,指向GObject结构,并且没有返回值。

void (*finalize) (GObject *object);

看看_GObjectClass的声明,你会发现大多数成员都是指向函数的指针。

  • 13:当实例创建的时候,通过constructor调用被指向的函数。它完成实例的初始化。
  • 25:当实例析构时调用dispose指向的函数。销毁过程分为两个阶段。第一个被称为处理(disposing)。在这个阶段,实例释放对其他实例的所有引用。第二阶段是finalizing。
  • 26:由finalize指向的函数完成析构过程。
  • 其他指针指向在实例生命周期期间调用的函数。

这些函数称为类方法(class method)。这些方法对其后代开放。但不向非后代对象开放。

5 TfeTextView类

TfeTextView类是一个结构体,它包含了它所有父类。因此,类与实例具有相似的层次结构。

GObjectClass (GInitiallyUnownedClass) -- GtkWidgetClass -- GtkTextViewClass -- TfeTextViewClass

下面的代码从源代码中提取(不完全相同)。

  1 struct _GtkWidgetClass
  2 {
  3   GInitiallyUnownedClass parent_class;
  4 
  5   /*< public >*/
  6 
  7   /* basics */
  8   void (* show)                (GtkWidget        *widget);
  9   void (* hide)                (GtkWidget        *widget);
 10   void (* map)                 (GtkWidget        *widget);
 11   void (* unmap)               (GtkWidget        *widget);
 12   void (* realize)             (GtkWidget        *widget);
 13   void (* unrealize)           (GtkWidget        *widget);
 14   void (* root)                (GtkWidget        *widget);
 15   void (* unroot)              (GtkWidget        *widget);
 16   void (* size_allocate)       (GtkWidget           *widget,
 17                                 int                  width,
 18                                 int                  height,
 19                                 int                  baseline);
 20   void (* state_flags_changed) (GtkWidget        *widget,
 21                                 GtkStateFlags     previous_state_flags);
 22   void (* direction_changed)   (GtkWidget        *widget,
 23                                 GtkTextDirection  previous_direction);
 24 
 25   /* size requests */
 26   GtkSizeRequestMode (* get_request_mode)               (GtkWidget      *widget);
 27   void              (* measure) (GtkWidget      *widget,
 28                                  GtkOrientation  orientation,
 29                                  int             for_size,
 30                                  int            *minimum,
 31                                  int            *natural,
 32                                  int            *minimum_baseline,
 33                                  int            *natural_baseline);
 34 
 35   /* Mnemonics */
 36   gboolean (* mnemonic_activate)        (GtkWidget           *widget,
 37                                          gboolean             group_cycling);
 38 
 39   /* explicit focus */
 40   gboolean (* grab_focus)               (GtkWidget           *widget);
 41   gboolean (* focus)                    (GtkWidget           *widget,
 42                                          GtkDirectionType     direction);
 43   void     (* set_focus_child)          (GtkWidget           *widget,
 44                                          GtkWidget           *child);
 45 
 46   /* keyboard navigation */
 47   void     (* move_focus)               (GtkWidget           *widget,
 48                                          GtkDirectionType     direction);
 49   gboolean (* keynav_failed)            (GtkWidget           *widget,
 50                                          GtkDirectionType     direction);
 51 
 52   gboolean     (* query_tooltip)      (GtkWidget  *widget,
 53                                        int         x,
 54                                        int         y,
 55                                        gboolean    keyboard_tooltip,
 56                                        GtkTooltip *tooltip);
 57 
 58   void         (* compute_expand)     (GtkWidget  *widget,
 59                                        gboolean   *hexpand_p,
 60                                        gboolean   *vexpand_p);
 61 
 62   void         (* css_changed)                 (GtkWidget            *widget,
 63                                                 GtkCssStyleChange    *change);
 64 
 65   void         (* system_setting_changed)      (GtkWidget            *widget,
 66                                                 GtkSystemSetting      settings);
 67 
 68   void         (* snapshot)                    (GtkWidget            *widget,
 69                                                 GtkSnapshot          *snapshot);
 70 
 71   gboolean     (* contains)                    (GtkWidget *widget,
 72                                                 double     x,
 73                                                 double     y);
 74 
 75   /*< private >*/
 76 
 77   GtkWidgetClassPrivate *priv;
 78 
 79   gpointer padding[8];
 80 };
 81 
 82 struct _GtkTextViewClass
 83 {
 84   GtkWidgetClass parent_class;
 85 
 86   /*< public >*/
 87 
 88   void (* move_cursor)           (GtkTextView      *text_view,
 89                                   GtkMovementStep   step,
 90                                   int               count,
 91                                   gboolean          extend_selection);
 92   void (* set_anchor)            (GtkTextView      *text_view);
 93   void (* insert_at_cursor)      (GtkTextView      *text_view,
 94                                   const char       *str);
 95   void (* delete_from_cursor)    (GtkTextView      *text_view,
 96                                   GtkDeleteType     type,
 97                                   int               count);
 98   void (* backspace)             (GtkTextView      *text_view);
 99   void (* cut_clipboard)         (GtkTextView      *text_view);
100   void (* copy_clipboard)        (GtkTextView      *text_view);
101   void (* paste_clipboard)       (GtkTextView      *text_view);
102   void (* toggle_overwrite)      (GtkTextView      *text_view);
103   GtkTextBuffer * (* create_buffer) (GtkTextView   *text_view);
104   void (* snapshot_layer)        (GtkTextView      *text_view,
105 			          GtkTextViewLayer  layer,
106 			          GtkSnapshot      *snapshot);
107   gboolean (* extend_selection)  (GtkTextView            *text_view,
108                                   GtkTextExtendSelection  granularity,
109                                   const GtkTextIter      *location,
110                                   GtkTextIter            *start,
111                                   GtkTextIter            *end);
112   void (* insert_emoji)          (GtkTextView      *text_view);
113 
114   /*< private >*/
115 
116   gpointer padding[8];
117 };
118 
119 /* The following definition is generated by the macro G_DECLARE_FINAL_TYPE */
120 typedef struct {
121   GtkTextView parent_class;
122 } TfeTextViewClass;
123 
  • 120-122:这3行代码由宏G_DECLARE_FINAL_TYPE生成。因此,它们不是写在tfe_text_view.h或tfe_text_view.c中。
  • 3,84, 121:每个类在其结构的第一个成员处都有父类。它与实例结构相同。
  • 父类中的类成员对后代类开放。因此,它们可以在tfe_text_view_class_init函数中更改。例如,GObjectClass中的finalize指针将在稍后的tfe_text_view_class_init中被覆盖。Override是一个面向对象的编程术语。Override是在子类中重写父类的方法。)
  • 有些类方法经常会被重写。set_property、get_property、dispose、finalize和construct就是这样的方法。
    在这里插入图片描述

6 TfeTextView销毁

从GObject派生的每个对象都有一个引用计数。如果一个对象A引用了一个对象B,那么A会在A中保留一个指向B的指针,同时使用g_object_ref (B)函数将B的引用计数增加1。如果A不再需要B,那么A会丢弃指向B的指针(通常是通过将指针赋值NULL来实现,表示不再使用),并使用g_object_unref (B)函数将B的引用计数减少1。

如果两个对象A和B都指向C,那么C的引用计数是2。如果A不再需要C,则A丢弃指向C的指针,并将C中的引用计数减1。现在C的引用计数是1。同样,如果B不再需要C,则B丢弃指向C的指针,并将C中的引用计数减少1。此时,没有对象引用C, C的引用计数为0。这意味着C不再有用。然后,C会销毁自身,最终分配给C的内存会被释放。

在这里插入图片描述
上面的想法是基于一个假设,即由nothing引用的对象的引用计数为零。当引用计数降到0时,对象开始销毁过程。销毁过程分为两个阶段:disposing和finalizing。在disposing过程中,对象调用其类中的dispose指向的函数,以释放对其他实例的所有引用。之后,它会调用类中的finalize指向的函数来完成析构过程。例如,处理程序或处理方法。

在销毁过程中,TfeTextView需要解引用通过tv->file指向的GFile。必须编写处理程序tfe_text_view_dispose。

1 static void
2 tfe_text_view_dispose (GObject *gobject) {
3   TfeTextView *tv = TFE_TEXT_VIEW (gobject);
4 
5   if (G_IS_FILE (tv->file))
6     g_clear_object (&tv->file);
7 
8   G_OBJECT_CLASS (tfe_text_view_parent_class)->dispose (gobject);
9 }
  • 5、6:如果tv->file指向GFile,则减少其引用计数。g_clear_object减少引用计数并将NULL赋值给tv->file。在处置处理程序中,我们通常使用g_clear_object而不是g_object_unref。
  • 8:调用父类的dispose处理程序。(稍后会解释。)

在处理过程中,对象使用其类中的指针来调用处理程序。因此,在初始化TfeTextView类时,需要在类中注册tfe_text_view_dispose。函数tfe_text_view_class_init是类初始化函数,它在G_DEFINE_TYPE宏扩展中声明。

static void
tfe_text_view_class_init (TfeTextViewClass *class) {
  GObjectClass *object_class = G_OBJECT_CLASS (class);

  object_class->dispose = tfe_text_view_dispose;

}

每个父类在创建TfeTextViewClass之前已经创建。因此,有四个类,每个类都有一个指向每个释放处理程序的指针。请看下图。有四个类——GObjectClass (GInitiallyUnownedClass), GtkWidgetClass, GtkTextViewClass和TfeTextViewClass。每个类都有自己的处理程序——dh1、dh2、dh3和tfe_text_view_dispose。
在这里插入图片描述现在,看看上面的tfe_text_view_dispose程序。它首先释放tv->file指向的GFile对象的引用。然后在第8行中调用其父类的dispose处理程序。

G_OBJECT_CLASS (tfe_text_view_parent_class)->dispose (gobject);

变量tfe_text_view_parent_class由G_DEFINE_TYPE宏创建,是一个指向父对象类的指针。gobject变量是一个指向TfeTextView实例的指针,该实例被强制转换为gobject实例。因此,G_OBJECT_CLASS (tfe_text_view_parent_class)->dispose指向上图中的处理程序dh3。语句G_OBJECT_CLASS (tfe_text_view_parent_class)->dispose (gobject)与dh3 (gobject)相同,这意味着它在TfeTextView实例中,会释放GtkTextViewPrivate中其他实例的所有引用。之后,dh3调用dh2, dh2调用dh1。最后释放所有的引用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/158285.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】线程控制

目录&#x1f308;前言&#x1f338;1、Linux线程控制&#x1f361;1.1、创建线程(pthread_create)&#x1f362;1.2、通过指令查看线程PID和LWP&#x1f367;1.3、获取线程ID(pthread_self)&#x1f368;1.4、线程终止(pthread_exit/cancel)&#x1f368;1.5、线程等待(pthrea…

一文读懂PCB阻焊工艺

PCB阻焊油墨根据固化方式&#xff0c;阻焊油墨有感光显影型的油墨&#xff0c;有热固化的热固油墨&#xff0c;还有UV光固化的UV油墨。而根据板材分类&#xff0c;又有PCB硬板阻焊油墨&#xff0c;FPC软板阻焊油墨&#xff0c;还有铝基板阻焊油墨&#xff0c;铝基板油墨也可以用…

力扣算法(Java实现)—数组入门(11题)

文章目录1.删除排序数组中的重复项2.买卖股票的最佳时机 II3.旋转数组4.存在重复元素5.找出只出现一次的元素6.两个数组的交集7.移动零8.加一9.两数之和10.有效的数独11.旋转图像&#x1f48e;&#x1f48e;&#x1f48e;&#x1f48e;&#x1f48e; 更多资源链接&#xff0c;欢…

【手写 Vue2.x 源码】第十八篇 - 根据 render 函数,生成 vnode

一&#xff0c;前言 上篇&#xff0c;介绍了render 函数的生成&#xff0c;主要涉及以下两点&#xff1a; 使用 with 对生成的 code 进行一次包装将包装后的完整 code 字符串&#xff0c;通过 new Function 输出为 render 函数 本篇&#xff0c;根据 render 函数&#xff0c…

linux系统中QT里面的视频播放器的实现方法

大家好&#xff0c;今天主要和大家聊一聊&#xff0c;如何使用QT中视频播放器的方法。 目录 第一&#xff1a;视频播放器基本简介 第二&#xff1a;视频播放器头文件说明 第三&#xff1a;源文件的具体实现方法 第四&#xff1a;运行效果显示 第一&#xff1a;视频播放器基本…

ADS振铃仿真

目录 无振铃时的原理图 无振铃时的Vout和VL输出波形 ​LineCalc对微带线阻抗的计算结果 将微带线线宽Width统一由116改为130 将微带线线宽Width统一由116改为80 将微带线TL9线宽由116改为300 将微带线TL9线宽由116改为50 本文介绍了微带线线宽变化时100MHz信号的反射现象…

2023 年 15 大测试自动化趋势

在过去&#xff0c;软件测试只是为了发现软件产品中的错误。目标是——提高软件质量。但如今&#xff0c;软件测试的范围已经扩大。在软件测试方面&#xff0c;自动化测试一直走在前列。按照最新的测试自动化趋势&#xff0c;软件测试行业有望比过去十年发展得更快。 根据 Mar…

Java面向对象综合训练

Java面向对象综合训练一、文字版格斗游戏Role类测试类输出结果二、对象数组练习对象数组1商品类测试类输出结果对象数组2汽车类测试类输出结果对象数组3手机类测试类输出结果对象数组4女朋友类测试类输出结果对象数组5学生类测试类输出结果一、文字版格斗游戏 Role类 import j…

去掉 域名后面的 /#/ vue-router 和 hbuilder发布 web项目和h5项目

1. vue-router vue-router默认的路由模式是hash&#xff0c;我们要去掉url中的#需要将路由模式切换为history const router new VueRouter({base: test, // 如果项目项目在 域名 根目录下&#xff0c;则去掉这行mode: history, // 路由模式... })这样子&#xff0c;url中的#…

为什么ERP和项目管理的集成是必要的?

在一个企业中&#xff0c;传统的责任分工意味着会计人员看管资金和维持财务标准&#xff0c;而职能经理分配人力资源和维持技术标准。项目经理指导分配的资金和其他资源&#xff0c;同时努力实现项目目标。每个学科都有自己的业务规则&#xff0c;自己的做法&#xff0c;自己的…

C++ | 左值、右值、将亡值和引用的概念 | 聊聊我对它们的深入理解

文章目录前言左右值的辨析一个特殊的问题将亡值引用的深刻理解前言 这篇文章是我在探究完美转发这个语法点时&#xff0c;引发的相关问题思考&#xff0c;为了使自己的理解更深刻&#xff0c;故写下这篇博客 左右值的辨析 首先需要明白两个概念&#xff1a;类型&#xff08;…

1577_AURIX_TC275_MTU中检测控制相关寄存器

全部学习汇总&#xff1a; GreyZhang/g_TC275: happy hacking for TC275! (github.com) 开篇介绍的功能室之前看过很多次的一个握手的功能。快速行以及快速列模式的测试中&#xff0c;这个行列其实是对应的存储的bit阵列信息。一个对应相应的字&#xff0c;另一个则对应bit序列…

【Linux】进程创建、终止、等待、替换、shell派生子进程的理解…

柴犬&#xff1a; 你好啊&#xff0c;屏幕前的大帅哥or大美女&#xff0c;和我一起享受美好的今天叭&#x1f603;&#x1f603;&#x1f603; 文章目录一、进程创建1.调用fork之后&#xff0c;内核都做了什么&#xff1f;2.如何理解fork函数有两个返回值&#xff1f;3.如何理…

(短信服务)java SpringBoot 阿里云短信功能实现发送手机验证码

一.阿里云准备工作 1.阿里云短信服务-注册账号 阿里云官网: https://www.aliyun.com/ 点击官网首页注册按钮。 2.阿里云短信服务-设置短信签名&#xff08;阿里云提供测试的签名&#xff0c;暂时可以跳过&#xff09; 注册成功后&#xff0c;点击登录按钮进行登录。登录后…

简单方式调用WebService服务

好久没有进行过WebService开发了&#xff0c;由于项目需要&#xff0c;重拾WebService&#xff0c;记录一下简单的服务调用方法。拿到需求&#xff0c;仅半页word&#xff0c;其他的就没有了&#xff0c;为了快速开发&#xff0c;尝试过使用插件逆向生成调用的一大堆类&#xf…

AWVS安装与激活

AWVS安装与激活 1.AWVS简介 AWVS&#xff08;Acunetix Web Vulnerability Scanner&#xff09;是一款知名的网络漏洞扫描工具&#xff0c;通过网络爬虫测试网站安全&#xff0c;检测流行的Web应用攻击&#xff0c;如跨站脚本、sql 注入等。据统计&#xff0c;75% 的互联网攻击…

pmp备考全攻略

我这里分享一下我备考的经验&#xff0c;如何对大家有帮助也可以稍微给点支持&#xff0c;让更多人了解&#xff01; 一&#xff0c;我的pmp备考经验 1.一阶段&#xff1a;铺底&#xff0c;花费时间1.5周左右 主要是熟悉考试框架和内容&#xff0c;通过看网盘资料里的章节重…

vue3+ts实现自定义按钮导航

效果图 点击对应按钮&#xff0c;相应按钮被激活&#xff0c;背景平移至激活按钮&#xff0c;字体高亮&#xff0c;其余按钮重置&#xff0c;由于ele没有类似tab&#xff0c;就简单记录下。 实现 <template><div class"tab_wrapper"><spanv-for&q…

这些技巧你值得学会

技巧一&#xff1a;多图合并为PDF文件 处理合并多份PDF文件外&#xff0c;使用PS的【PDF演示文稿】工具&#xff0c;也能一同将多张图片合并成PDF文档&#xff01;通过合并的方式&#xff0c;不但能够批量归纳汇总图片&#xff0c;而且还能根据自身需求&#xff0c;将图片与PD…

Visual studio C++程序内使用Sqlite3

Visual studio C程序内使用Sqlite3 前言 本篇讲解了如何在Visual studio开发的C桌面应用程序内使用Sqlite数据库&#xff0c;Sqlite的语法和Mysql是一样的&#xff0c;所以本篇文章不对数据库语法做过多介绍&#xff0c;介绍一些常用Sqlite的API ★提高阅读体验★ &…