【QT】編寫第一個 QT 程序 對象樹 Qt 編程事項 內存泄露問題

目錄

1. 編寫第一個 QT 程序

1.1?使用 標簽 實現 ?

1.2 純代碼形式實現

1.3?使用 按鈕 實現?

1.3.1?圖形化界面實現?

1.3.2 純代碼形式實現

1.4?使用 編輯框 實現

1.4.1?圖形化界面實現

?1.4.2?純代碼形式實現?

1.4.3 內存泄露?

2. 認識對象模型(對象樹)

2.1 什么是對象樹

2.2?驗證對象樹

3. 解決編碼問題

4. Qt 編程注意事項

4.1 Qt 中的命名事項

4.2 Qt Creator 中的快捷鍵

4.3 使用幫助文檔

5. 小結


1. 編寫第一個 QT 程序

1.1?使用 標簽 實現 ?

1.創建好一個項目后,我們可以點擊 widget.ui 進入圖形化界面設計,可以直接通過拖拽的方式進行添加

2.拖拽 "標簽" 至 UI 設計界面中,并雙擊修改標簽內容

3. 此時ui界面就會生成對應的 XML 格式代碼,這個時候qmake就會根據這個XML代碼生成對應的C++代碼,我們也可以在同目錄下找到這個C++代碼

1.2 純代碼形式實現

我們點擊 widget.cpp 里面,會有一個 widget 的構造函數和析構函數,我們一般使用代碼進行編輯界面的時候,一般都是在 widget 的構造函數中實現,因為在 ?main 函數中調用了 widget 類之后就直接 show了,所以卸載構造函數中的時候,一旦執行到了 show 就一定可以顯示出設計的界面

#include "widget.h" // 創建生成時的文件
#include "ui_widget.h"
#include <QLabel>  // 包含標簽的頭文件Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this); // 將form file生成的界面和我們當前的widget進行關聯起來// 創建對象的兩種方法// QLabel label; // 在棧上創建QLabel* label = new QLabel(this); // 在堆上創建,推薦這種方法,還要傳遞 一個 this,給當前這個 lable 對象指定 父對象// 1. 設置標簽內容label->setText((QString)("顯式 Hello world"));label->setText("隱式 Hello World"); // QString 也提供了 C 風格字符串作為參數的構造函數來不顯示構造 QString// 注意:由于QString 對應的頭文件,已經被很多 Qt 內置的其他類給間接包含了.因此一般不需要顯式包含 QString 頭文件// 這里雖然有兩次 setText,但是下面內容會覆蓋上面內容// 2. 設置窗口大小setFixedSize(500, 400);// 3. 設置字體大小QFont font("楷體", 16);label->setFont(font);// 4. 設置標簽內容顯式位置label->move(200, 150);// 5. 設計標簽字體顏色label->setStyleSheet("color:blue");
}Widget::~Widget()
{delete ui;
}

void setText(const QString &);

這里我們會發下使用字符串的時候并不是我們 C++ 使用的標準庫中的 string,而是 Qt 自己包裝好的字符串 QString 。這個其實也是歷史原因,Qt 誕生于1991年,那個時候 C++ 還沒有定標準,而 Qt 為了更好的開發就自己包裝了一些容器。但是我們也還是可以使用 C++ 的標準庫中的容器來使用

1.3?使用 按鈕 實現?

1.3.1?圖形化界面實現?

1.?雙擊:"widget.ui" 文件

2. 拖拽控件至 ui 界面窗口并修改內容

  • 雖然那里有好幾個按鈕,但是我們這里用 Push Button(普通按鈕)

3. 構建并運行,效果如下所示

  • 這里的按鈕的確可以點擊,但是卻沒有任何反應,這個就設計到我們后面學的信號槽知識,后面會說的

  • QT 的信號槽機制:本質上就是給按鈕的點擊操作,關聯上一個處理函數,當用戶點擊的時候,就會執行這個處理函數

這里我們的按鈕沒有任何功能,假如我們要實現一定的功能,那該怎么做呢?

打開 widget.ui 文件,查看設計的右下角,則有

如下代碼:

widget.hpp

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);void handleClick();~Widget();private:Ui::Widget *ui;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 按鈕的點擊操作 -- 信號槽// 在 Linux 網絡編程那也有個connect 函數,那里用來給 TCP socket 建立連接的,寫 TCP 客戶端的時候,就需要先建立連接才能讀寫數據// ui->pushButton:誰發出的信號// &QPushButton::clicked:發出了啥信號,點擊按鈕的時候自動觸發該信號// this: 誰來處理這個信號// Widget::handle:具體怎么處理connect(ui->pushButton, &QPushButton::clicked, this, &Widget::handleClick);  // 訪問到 form file(ui 文件)中創建的控件}Widget::~Widget()
{delete ui;
}void Widget::handleClick()
{if(ui->pushButton->text() == "Hello World"){ui->pushButton->setText("Hello IsLand");}else{ui->pushButton->setText("Hello World");}
}

返回上級目錄查看?ui_widget.h?文件

因此我們也可以把 PushButton 改成其他的,如下:

再次查看?ui_widget.h?文件,如下:

結論:在 objectName 中,設置成什么值,生成的變量名就叫啥名字就可以根據這個名字來獲取到對應的控件的變量了

1.3.2 純代碼形式實現

widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QPushButton>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);void handleClick();~Widget();private:Ui::Widget *ui;QPushButton* myButton;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);myButton = new QPushButton(this);myButton->setText("Hello World");connect(myButton, &QPushButton::clicked, this, &Widget::handleClick);  // 訪問到 form file(ui 文件)中創建的控件
}Widget::~Widget()
{delete ui;
}void Widget::handleClick()
{if(myButton->text() == QString("Hello World")){myButton->setText("Hello IsLand");}else{myButton->setText("Hello World");}
}

實現效果如下圖:

兩個版本比較:

  • 圖形化實現:此時按鈕對象不需要咱們自己 newnew 對象的操作已經是被 Qt 自動生成了而且這個按鈕對象,已經作為 ui 對象里的一個成員變量了,也無需作為 Widget 的成員

  • 純代碼實現:按鈕對象是咱們自己 new 的,為了保證其他函數中能夠訪問到這個變量,就需要把按鈕對象,設定為 Widget 類的成員變量

實際開發中,是通過代碼的方式構造界面為主,還是通過圖形化界面的方式構造界面為主??

  • 這兩種都很主要,難分主次!!

  • 如果你當前程序界面,界面內容是比較固定的,此時就會以?圖形化?的方式來構造界面

  • 但是如果你的程序界面,經常要動態變化,此時就會以?代碼?的方式來構造界面

  • 反正這兩種方式哪種方便用哪個,也可以配合來使用

1.4?使用 編輯框 實現

  • 單行編輯框:?QLineEdit
  • 多行編輯框:?QTextEdit
1.4.1?圖形化界面實現

  • 當然輸出的文本框,我們也可以在輸出里面進行修改啥的,但是不會影響代碼里面的文本數據

?1.4.2?純代碼形式實現?

1.4.3 內存泄露?

在上面的代碼實現中,我們使用 new 創建了對象,在棧上開辟了一塊空間之后,但是我們沒有使用delete進行釋放控件,這樣不就會導致內存泄漏啊

  • 其實上述代碼在 Qt 不會產生內存泄露, label ?對象會在合適的時候被析構釋放,之所以能夠把對象釋放掉,主要是因為把這個對象掛到了 對象樹 上?

  • 前端開發(網頁開發)也涉及到 類似的 對象樹 (DOM),本質上也是一個樹形結構(N 又樹),通過樹形結構把界面上的各種元素組織起來

  • Qt 中也是類似,也是搞了一個對象樹,也是 N 又樹,把界面上的各種元素組織起來了

  • 用對象樹把這些內容組織起來,最主要的目的:就是為了能夠在合適的時機(窗口關閉和銷毀),把這些對象統一進行釋放。通過這個樹形結構,就把界面上要顯示的這些控件對象都組織起來了。
  • 這里的樹上的這些對象,統一銷毀是最好不過的,如果某個對象提前銷毀,此時就會導致對應的控件就在界面上不存在了。

2. 認識對象模型(對象樹)

2.1 什么是對象樹

在?Qt?中創建很多對象的時候會提供一個 Parent對象指針,下面來解釋這個 parent 到底是干什么的。

  • QObject ?是以對象樹的形式組織起來的。

  • 當創建一個 QObject 對象時,會看到 QObject 的構造函數接收一個 QObject 指針作為參數,這個參數就是 parent,也就是父對象指針。

  • 這相當于,在創建 QObject 對象時,可以提供一個其父對象,我們創建的這個 QObject 對象會自動添加到其父對象的 children()列表。

  • 當父對象析構的時候,這個列表中的所有對象也會被析構。(注意,這里的父對象并不是繼承意義上的父類!)

這種機制在 GUI程序設計中相當有用。例如,一個按鈕有一個 QShortcut(快捷鍵)對象作為其子對象。當刪除按鈕的時候,這個快捷鍵理應被刪除。這是合理的。

  • Qwidget 是能夠在屏幕上顯示的一切組件的父類。
  • Qwidget 繼承自 QObject,因此也繼承了這種對象樹關系。一個孩子自動地成為父組件的-個子組件。因此,它會顯示在父組件的坐標系統中,被父組件的邊界剪裁。例如,當用戶關閉一個對話框的時候,應用程序將其刪除,那么,我們希望屬于這個對話框的按鈕、圖標等應該(-起被刪除。事實就是如此,因為這些都是對話框的子組件。
  • 當然,我們也可以自己刪除子對象,它們會自動從其父對象列表中刪除。比如,當我們刪除了個工具欄時,其所在的主窗口會自動將該工具欄從其子對象列表中刪除,并且自動調整屏幕顯示。

Qt 引入對象樹的概念,在一定程度上解決了內存問題。

  • 當一個 QObject 對象在堆上創建的時候,Qt 會同時為其創建一個對象樹。不過,對象樹中對象的順序是沒有定義的。這意味著,銷毀這些對象的順序也是未定義的。

  • 任何對象樹中的 QObject 對象 delete 的時候,如果這個對象有 parent,則自動將其從 parentchildren() 列表中刪除;如果有孩子,則自動 delete 每一個孩子。Qt 保證沒有 QObject 會被delete 兩次,這是由析構順序決定的。

如果?QObject?在棧上創建,Qt 保持同樣的行為。正常情況下,這也不會發生什么問題。來看下面的代碼片段:

{QWidget window;QLabel label("hello", &window); // 指定父類是widow
}

作為父組件的 ?window 和作為子組件的? label?都是 QObject 的子類(事實上,它們都是 Qwidget的子類,而 Qwidget 是 QObject 的子類)。這段代碼是正確的,label?的析構函數不會被調用兩次,因為標準 C++ 要求,局部對象的析構順序應該按照其創建順序的相反過程。因此,這段代碼在超出作用域時,會先調用 label?的析構函數,將其從父對象 window 的子對象列表中刪除,然后才會再調用 ?window 的析構函數。

  • 但是一旦我們的代碼稍微修改一點就會出錯
{QLabel label("hello"); // 指定父類是widowQWidget window;label.setParent(&window);
}

情況又有所不同,析構順序就有了問題。我們看到,在上面的代碼中,作為父對象的 window 會首先被析構,因為它是最后一個創建的對象。在析構過程中,它會調用子對象列表中每一個對象的析構函數,也就是說,label此時就被析構了。然后,代碼繼續執行,在 window 析構之后,label也會被析構,因為 label也是一個局部變量,在超出作用域的時候當然也需要析構。但是,這時候已經是第二次調用 label的析構函數了,C++不允許調用兩次析構函數,因此,程序崩潰了。

由此我們看到,Qt?的對象樹機制雖然在一定程度上解決了內存問題,但是也引入了一些值得注意的事情。這些細節在今后的開發過程中很可能時不時跳出來煩擾一下,所以,我們最好從開始就養成良好習慣,即 在 Qt 中,盡量將其開辟在堆上,并指定好其?parent 父類對象

比如:

  • 如果我們把最初的代碼改成在棧上開辟的話我們運行程序會發現什么都沒有

Qt 對象樹如下:

2.2?驗證對象樹

首先我們自定義一個label類,并在析構部分打上日志,如下步驟:

1. 選中工程名,鼠標右鍵------->"add new..."(或 "添加新文件" )

結果圖如下:?

  • 上面 Qt Creator 是幫我們生成了一些代碼,但是沒完全生成,頭文件沒有給我們主動包含,上面的頭文件也是我自己手動包含的?
  • 此時我們可以按F4來進行?.h文件?和?.cpp文件?來回切換

此時我們的?mylabel.cpp?中就是

#include "mylabel.h"
#include <iostream>MyLabel::MyLabel(QWidget* parent) : QLabel(parent)
{
}MyLabel::~MyLabel()
{std::cout << "MyLabel 被銷毀" << std::endl;
}

midget.cpp?中的代碼就是

#include "widget.h"
#include "ui_widget.h"
#include "mylabel.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this); // 將form file生成的界面和我們當前的widget進行關聯起來// 使用自己定義的 MyLabel 代替原來的 QLabel,所謂的 “繼承” 本質上是擴展,保持原有功能不變的基礎上// 給對象擴展出一個析構函數,通過這個析構函數,打印一個自定義日志,方便觀察程序運行結果MyLabel *label = new MyLabel(this);label->setText("Hello World");}Widget::~Widget()
{delete ui;
}
  • 此時我們運行代碼,就可以看到窗口上有?Hello World?的字樣,只要我們關閉窗口,就會輸出我們的日志

這里也是驗證了對象樹自動釋放對象的能力

  • 這里日志是有的,說明析構函數是執行了,雖然沒有 手動?delete,但是由于把 MyLabel 掛到了對象樹上,此時窗口被銷毀的時候,就會自動銷毀對象樹中的所有對象!!所以MyLabel 的析構是執行到了

但是這里似乎出現了亂碼的情況

  • 亂碼問題出現的原因有且僅有一個?編碼方式不匹配(不僅僅局限于 C++)
  • 比如字符串本身是 utf8 編碼的,但是終端(控制臺)是按照 gbk 的方式來解析顯示的,就會出現亂碼(相當于拿著 utf8 的數值 去查詢 gbk 的 碼表)

utf8 和 gbk?

目前,表示漢字字符集, 主要是兩種方式

  1. GBK(中國大陸) 使用 2 個字節表示一個漢字!Windows 簡體中文版,默認的字符集就是 GBK
  2. UTF-8 / utf8?變長編碼,表示一個符號,使用的字節數有變化,2-4但是在?utf8?中。一個漢字一般是 3 個字節
  3. Linux 默認就是?utf8

3. 解決編碼問題

我們用文本文件打開?mylabel.cpp?文件,可以看到這個文件的編碼方式

可看到這個文件的編碼方式是?utf8,但是??Qt?的這個終端的編碼方式肯定不是?utf8?,但是Qt不支持修改編碼方式,所以這里我們就需要借助?Qt?自己提供的打印日志的功能?qDebug,或者使用?QString?來處理編碼方式。

#include "mylabel.h"
#include <iostream>#include <QtDebug> // 頭文件MyLabel::MyLabel(QWidget* parent) : QLabel(parent)
{}MyLabel::~MyLabel()
{// std::cout << "MyLabel 被銷毀" << std::endl;qDebug() << "MyLabel 被銷毀"; // qDebug 這個宏封裝了 QDebug 對象,使用 qDebug 相當于使用 cout
}
#define qDebug QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).debug

此時中文就不會出現亂碼情況,如下:?

  • 后續在 Qt 中,如果想通過打印日志的方式,輸出一些調試信息,都優先使用 qDebug。雖然使用 cout 也行,但是 cout 對于編碼的處理不太好,在windows 上容易出現亂碼(如果是 Linux 使用 Qt Creator, 一般就沒事了,Linux 默認的編碼一般都是 utf8)

  • 使用 qDebug, 還有一個好處:打印的調試日志是可以統一進行關閉的!!

  • 輸出的日志,是開發階段、調試程序的時候使用的。如果你的程序發布給用戶,不希望用戶看到這些日志的!!

  • qDebug 可以通過編譯開關,來實現一鍵式關閉

之前調試程序, 都是用調試器.VS/gdb,這里為啥要打印日志調試呢??

  • 調試器很多時候是有局限性的,是無法使用的,
  • 假設當前 bug 是一個概率性的 bug。出現的概率是 1% 甚至更小要想調試,無法使用調試器了
  • 使用?日志? 就可以很好的解決這種問題
  • 無論是哪種方式本質上都是觀察程序執行的中間過程和中間結果~

4. Qt 編程注意事項

4.1 Qt 中的命名事項

  • 類名:首字母大寫,單詞和單詞之間首字母大寫;

  • 函數名及變量名:首字母小寫,單詞和單詞之間首字母大寫

  • 起的名字要有描述性,不要使用 abc, xyz 這種比較無規律的名字來描述

  • 如果名字比較長,由多個單詞構成的,就需要使用適當的方式來進行區分不同單詞

  • 一般可以采用 蛇形命名法 或者 駝峰命名法

4.2 Qt Creator 中的快捷鍵

其里面內置 Vim 插件,因此我們也可以按照使用 Vim 操作來使用

  • 注釋:ctrl+/

  • 運行:ctrl+R

  • 編譯:ctrl+B

  • 字體縮放:ctrl+鼠標滑輪

  • 查找:ctrl+F

  • 整行移動:ctrl+shift+↑/↓

  • 幫助文檔:F1

  • 自動對齊:ctrl+i

  • 同名之間的.h和.cpp 的切換:F4

  • 生成函數聲明的對應定義:alt+enter

  • 跳轉到控件定義: 鼠標左鍵 + ctrl,返回就是:alt + <-

4.3 使用幫助文檔

打開幫助文檔有三種方式,實際編程中使用哪種都可以

  1. 光標放到要查詢的類名/方法名上,直接按 F1

  2. Qt Creator 左側邊欄中直接用鼠標單擊"幫助"按鈕

點擊 "幫助" 之后,出現如下圖:

3、找到?Qt Creator?的安裝路徑,在 "bin" 文件夾下找到 assistant.exe,雙擊打開

使用示例

  1. 新建項目,在新建的項目中使用 Qt 中的"QpushButton" 控件。

  2. 打開幫助手冊,在"索引"里面輸入"QpushButton":

注意:一定不要使用中文文檔!!!

  • 閱讀英文文檔是每個程序員必備的專業技能,必須要練,不能退縮

  • Qt的文檔從通俗易懂的角度來說,是技術類文檔中非常出類拔萃的,只要大家稍微有點耐心,基本都能讀懂個八九不十

5. 小結

  • 認識 QLabel 類,能夠在界面上顯示字符串。通過 setText 來設置的,參數 QString(Qt 中把 C++ 里的很多容器類,進行了重新封裝,歷史原因)

  • 內存泄露/文件資源泄露

  • 對象樹Qt 中通過對象樹,來統一的釋放界面的控件對象,Qt 還是推薦使用 new 的方式在堆上創建對象,通過對象樹,統一釋放對象創建對象的時候,在構造函數中,指定父對象(此時才會掛到對象樹上),如果你的對象沒有掛到對象樹上,就必須要記得手動釋放!!

  • 通過繼承自 Qt 內置的類,就可以達到對現有控件進行功能擴展效果Qt 內置的 QLabel,沒法看到銷毀過程的。為了看清楚,就創建類 MyLabel, 繼承自 QLabel 重寫析構函數。在析構函數中加上日志,直觀的觀察到對象釋放的過程了,也可以重寫控件中的任何功能。不僅僅是析構函數, 達到功能擴展目的

  • 亂碼問題 和 字符集~ MySQL(很多地方都涉及到)

  • 如何在 Qt 中打印日志,作為調試信息使用 cout 固然可以, 但是并不是上策(字符編碼處理的不好,也不方便統一進行關閉)Qt 中推薦使用 qDebug() 完成日志的打印

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/77933.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/77933.shtml
英文地址,請注明出處:http://en.pswp.cn/web/77933.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

在pycharm中創建Django項目并啟動

Django介紹 Django 是一個基于 Python 的開源 Web 應用框架&#xff0c;采用了 MTV&#xff08;Model - Template - View&#xff09;軟件設計模式 &#xff0c;由許多功能強大的組件組成&#xff0c;能夠幫助開發者快速、高效地創建復雜的數據庫驅動的 Web 應用程序。它具有以…

在Carla中構建自動駕駛:使用PID控制和ROS2進行路徑跟蹤

機器人軟件開發什么是 P、PI 和 PID 控制器&#xff1f;比例 &#xff08;P&#xff09; 控制器比例積分 &#xff08;PI&#xff09; 控制器比例-積分-微分 &#xff08;PID&#xff09; 控制器橫向控制簡介CARLA ROS2 集成縱向控制橫向控制關鍵要點結論引用 機器人軟件開發 …

【KWDB 創作者計劃】_深度解析KWDB存儲引擎

文章目錄 每日一句正能量引言一、存儲引擎核心模塊結構二、寫前日志 WAL&#xff08;Write-Ahead Log&#xff09;三、列式壓縮存儲&#xff08;Columnar Compression&#xff09;四、索引機制與混合查詢調度五、分布式核心功能&#xff1a;租約管理實戰六、時間序列數據處理&a…

Apache Tomcat 漏洞(CVE-2025-24813)導致服務器面臨 RCE 風險

CVE-2025-24813Apache Tomcat 中發現了一個嚴重安全漏洞,標識為,該漏洞可能導致服務器面臨遠程代碼執行 (RCE)、信息泄露和數據損壞的風險。 此缺陷影響以下版本: Apache Tomcat11.0.0-M1通過11.0.2Apache Tomcat10.1.0-M1通過10.1.34Apache Tomcat9.0.0-M1通過9.0.98了解 …

全面解析SimHash算法:原理、對比與Spring Boot實踐指南

一、SimHash算法概述 SimHash是一種局部敏感哈希算法&#xff0c;由Google工程師Moses Charikar提出&#xff0c;主要用于海量文本的快速去重與相似度檢測。其核心思想是將高維特征向量映射為固定長度的二進制指紋&#xff08;如64位&#xff09;&#xff0c;通過計算指紋間的…

臨床回歸分析及AI推理

在醫療保健決策越來越受數據驅動的時代&#xff0c;回歸分析已成為臨床醫生和研究人員最強大的工具之一。無論是預測結果、調整混雜因素、建模生存時間還是理解診斷性能&#xff0c;回歸模型都為將原始數據轉化為臨床洞察提供了統計學基礎。 AI推理 然而&#xff0c;隨著技術…

西門子PLC S7-1200 電動機的軟啟動控制

1 PWM 控制的基本概念 PWM 是 PulseWidth Modulation 的簡稱。 PWM 控制是一種脈沖寬度調制技術,通過對一系列脈沖的寬度進行調制來等效獲得所需要的波形(含形狀和幅值)。PWM 控制技術在逆變電路中應用比較廣泛,所應用的逆變電路絕大部分是PWM 型。除此之外, PWM 控制技術…

【學習 python day5】

學習目標&#xff1a; python基礎 掌握函數的定義及調用方法掌握模塊的用法掌握包的用法掌握如何捕獲異常 web自動化測試 能完成selenium自動化環境部署及結果驗證掌握selenium實現自動化測試的核心步驟 學習內容&#xff1a; 一、Python基礎 1、集合[了解] 1, 集合 set, …

day006-實戰練習題-參考答案

老男孩教育-99期-實戰練習題 1. 你作為"老男孩教育99期云計算"新晉運維工程師&#xff0c;在入職首日遭遇緊急事件&#xff1a; "生產環境3臺Web服務器突發性能告警&#xff0c;技術總監要求你立即完成&#xff1a; 快速建立故障診斷工作區收集關鍵系統指標分…

C# 實現列式存儲數據

C#實現列式存儲數據指南 一、列式存儲概述 列式存儲(Columnar Storage)是一種數據存儲方式&#xff0c;它將數據按列而非行組織。與傳統的行式存儲相比&#xff0c;列式存儲在以下場景具有優勢&#xff1a; ??分析型查詢??&#xff1a;聚合計算、分組統計等操作效率更高…

Mysql索引分類、索引失效場景

索引分類 按數據結構分類? B-Tree索引&#xff08;BTree&#xff09; 描述??&#xff1a;默認的索引類型&#xff0c;大多數存儲引擎&#xff08;如InnoDB、MyISAM&#xff09;支持。實際使用BTree結構&#xff0c;數據存儲在葉子節點&#xff0c;葉子節點通過指針連接&a…

SpringBoot+Redis全局唯一ID生成器

&#x1f4e6; 優雅版 Redis ID 生成器工具類 支持&#xff1a; 項目啟動時自動初始化起始值獲取自增 ID 方法yml 配置化起始值可靈活擴展多業務線 ID &#x1f4cc; application.yml 配置 id-generator:member-start-value: 1000000000&#x1f4cc; 配置類&#xff1a;IdG…

深入掌握CSS背景圖片:從基礎到實戰

背景圖片&#xff1a; 本文將通過系統化的講解實戰案例&#xff0c;幫助讀者徹底掌握CSS背景圖片的六大核心知識點。每個知識點都包含對比演示和記憶技巧&#xff0c;建議結合代碼實操學習。 一、背景圖片基礎設置 使用background-image&#xff08;路徑&#xff09;屬性設置…

WPF之XAML基礎

文章目錄 XAML基礎&#xff1a;深入理解WPF和UWP應用開發的核心語言1. XAML簡介XAML與XML的關系 2. XAML語法基礎元素語法屬性語法集合語法附加屬性 3. XAML命名空間命名空間映射關系 4. XAML標記擴展靜態資源引用數據綁定相對資源引用常見標記擴展對比 5. XAML與代碼的關系XAM…

驅動車輛診斷測試創新 | 支持診斷測試的模擬器及數據文件轉換生成

一 背景和挑戰 | 背景&#xff1a; 隨著汽車功能的日益豐富&#xff0c;ECU和域控制器的復雜性大大增加&#xff0c;導致測試需求大幅上升&#xff0c;尤其是在ECU的故障診斷和性能驗證方面。然而&#xff0c;傳統的實車測試方法難以滿足高頻率迭代和驗證需求&#xff0c;不僅…

免疫細胞靶點“破局戰”:從抗體到CAR-T,自免疾病治療的3大技術突破

引言 人體免疫系統組成了一個嚴密調控的“網絡”&#xff0c;時刻檢測著外來病原體&#xff0c;并將其與自身抗原區分開來。但免疫系統也可能會被“策反”&#xff0c;錯誤的攻擊我們自身&#xff0c;從而導致自身免疫性疾病的發生。 目前已知的自免疾病超過100種&#xff0c…

計算機網絡應用層(5)-- P2P文件分發視頻流和內容分發網

&#x1f493;個人主頁&#xff1a;mooridy &#x1f493;專欄地址&#xff1a;《計算機網絡&#xff1a;自頂向下方法》 大綱式閱讀筆記_mooridy的博客-CSDN博客 &#x1f493;本博客內容為《計算機網絡&#xff1a;自頂向下方法》第二章應用層第五、六節知識梳理 關注我&…

十二種存儲器綜合對比——《器件手冊--存儲器》

存儲器 名稱 特點 用途 EEPROM 可電擦除可編程只讀存儲器&#xff0c;支持按字節擦除和寫入操作&#xff0c;具有非易失性&#xff0c;斷電后數據不丟失。 常用于存儲少量需要頻繁更新的數據&#xff0c;如設備配置參數、用戶設置等。 NOR FLASH 支持按字節隨機訪問&…

第十六屆藍橋杯 2025 C/C++組 旗幟

目錄 題目&#xff1a; 題目描述&#xff1a; 題目鏈接&#xff1a; 思路&#xff1a; 思路詳解&#xff1a; 代碼&#xff1a; 代碼詳解&#xff1a; 題目&#xff1a; 題目描述&#xff1a; 題目鏈接&#xff1a; P12340 [藍橋杯 2025 省 AB/Python B 第二場] 旗幟 -…

比亞迪再獲國際雙獎 以“技術為王”書寫中國汽車出海新篇章

近日&#xff0c;全球汽車行業權威獎項“2025世界汽車大獎”&#xff08;World Car Awards&#xff09;在紐約國際車展舉行頒獎典禮&#xff0c;比亞迪海鷗&#xff08;BYD SEAGULL/BYD DOLPHIN MINI&#xff09;摘得“2025世界城市車&#xff08;World Urban Car&#xff09;”…