Qt6.0開發 第四章 常用介面元件的使用

Mesonoxian發表於2024-03-13

第四章 常用介面元件的使用


在Qt類庫中,所有介面元件類的位元組或間接父類都是QWidget.

QWidget的父類是QObject與QPaintDevice.所以QWidget是多重繼承的類.

QObject支援元物件系統,其訊號與槽機制為程式設計中物件間通訊提供了極大便利.

QPaintDevice是能使用QPainter類在繪圖裝置上繪圖的類.

所有從QWidget繼承而來的介面元件被稱為widget元件,他們是構成GUI應用程式的視窗介面基本元素.

介面元件可以從視窗系統接收滑鼠事件,鍵盤事件和其他事件,然後在螢幕上繪製自己.

常用的介面元件

按鈕類元件

按鈕類繼承關係:

  • QAbstractButton:抽象類,提供按鈕共有特性
    • QPushButton:普通按鈕
      • QCommandLinkButton:單選按鈕,多個互斥項間選擇.
    • QToolButton:工具按鈕
    • QRadioButton:單選按鈕
    • QCheckBox:核取方塊
  • QDialogButttonBox:複合元件類,可設定為多個按鈕組合

輸入類元件

輸入類元件繼承關係:

  • QComboBox:下拉選單框,也稱組合框
    • QFontComboBox:字型下拉選單框,自動從系統獲取字型
  • QLineEdit:編輯框,用於輸入單行文字
  • QFrame:基本控制元件的基類
    • QAbstractScrollArea:抽象類
      • QTextEdit:文字編輯框,支援富文字格式,包括markdown.
      • QPlainTextEdit:純文字編輯器,支援多段落純文字.
  • QAbstractSpinBox:抽象類
    • QSpinBox:整數輸入框,用於輸入整數或離散型資料.
    • QDoubleSpinBox:浮點數輸入框.
    • QDateTimeEdit:允許使用者編輯日期與時間
      • QDateEdit:日期編輯框
      • QTimeEdit:時間編輯框
  • QAbstractSlider:抽象類
    • QDial:錶盤,用於在設定的範圍內輸入和顯示數值.
    • QScrollBar:卷滾條,用於在大的顯示區域內滑動.
    • QSlider:滑動條,具有設定的數值範圍.
  • QKeySequenceEdit:按鍵序列編輯器,一般用於處理快捷鍵

顯示類元件

顯示類元件繼承關係:

  • QFrame:基本控制元件的基類
    • QLabel:標籤,用於顯示文字,圖片等
    • QAbstractScrollArea:抽象類
      • QTextEdit:文字編輯框,支援富文字格式,包括markdown.
        • QTextBrowser:文字瀏覽器,用於顯示富文字格式內容
      • QGraphicsView:圖形檢視元件,圖形/檢視架構中的檢視元件
    • QLCDNumber:LCD數字顯示元件,模仿LCD顯示效果的元件
  • QCalendarWidget:日曆元件,用於顯示日曆
  • QProgressBar:進度條,用於表示某個操作的進度
  • QOpenGLWidget:OpenGL顯示元件,用於在Qt程式啟動OpenGL圖形
  • QQuickWidget:QML顯示元件,用於自動載入QML檔案

容器類元件

容器類元件繼承關係:

  • QGroupBox:分組框,具有標題和邊框的容器元件
  • QFrame:框架元件,是具有邊框的介面元件的父類
    • QAbstractScrollArea:抽象類
      • QScrollArea:卷滾區域,具有水平和垂直捲軸的容器
      • QMdiArea:MDI工作區元件,在MDI應用程式中用於管理多文件視窗
    • QToolBox:工具箱,垂直方向的多頁容器元件
    • QStackedWidget:堆疊多頁元件,沒有標籤欄的多頁元件
  • QTabWidget:帶標籤欄的多頁元件
  • QDockWidget:停靠元件,可以停靠在QMainWindow視窗的停靠區域,也可以浮動
  • QAxWidget:ActiveX顯示元件,用於顯示ActiveX控制元件

Item元件

Item元件繼承關係:

  • QAbstractItemView
    • QListView
      • QUndoView
      • QListWidget
    • QTreeView
      • QTreeWidget
    • QTableView
      • QTableWidget
    • QColumnView

Item Views元件大多是用於模型/檢視結果,每一種檢視元件需要相應的一種模型用於儲存資料.

Item Widgets元件類是相應Item Views元件類的子類,它們直接使用項(item)儲存資料,稱為相應檢視類的便利類(convenience class)

其他介面類

還有一些介面元件並沒有出現在元件皮膚裡,例如常用的選單欄(QMenuBar類),選單(QMenu類),工具欄(QToolBar類),狀態列(QStatusBar類)等元件.

QWidget類的主要屬性和介面函式

QWidget作為介面元件時的屬性

屬性名稱 屬性值型別 功能
enabled bool 元件的使能狀態
geometry QRect 元件的幾何形狀
sizePolicy QSizePolicy 元件預設的佈局特性
minimumSize QSize 元件最小尺寸
maximumSize QSize 元件最大尺寸
palette QPalette 元件的調色盤
font QFont 元件使用的字型
cursor QCursor 滑鼠游標移到元件上的形狀
mouseTracking bool 元件是否響應滑鼠移動
tabletTracking bool 元件是否響應平板追蹤
focusPolicy Qt::FocusPolicy 元件的焦點策略
contextMenuPolicy Qt::ContextMenuPolicy 組建的上下文選單策略
acceptDrops bool 元件是否接收拖動來的其他物件
toolTip QString 滑鼠移動到元件上時,顯示簡短提示
statusTip QString 滑鼠移動到元件上時,主視窗狀態列顯示提示文字
autoFillBackground bool 元件背景是否自動填充
styleSheet QString 組建的樣式表

元件負責預設佈局特性的sizePolicy是QSizePolicy型別,定義了元件在水平和垂直方向的尺寸變化策略.

為了訪問元件的sizePolicy,應當透過其Widget內部的sizePolicy()方法訪問.

QSizePolicy是一個列舉型別,因而有以下列舉常量:

  • QSizePolicy::Fixed:固定尺寸,元件大小不改變
  • QSizePolicy::Minimum:最小尺寸,使用sizeHint()的返回值或minimumuSize作為最小尺寸.
  • QSizePolicy::Maximum:最大尺寸,使用sizeHint()的返回值或maximumuSize作為最大尺寸.
  • QSizePolicy::Preferred:首選尺寸,元件仍然可以調整,但是放大時不會超過sizeHint()返回的尺寸.
  • QSizePolicy::Expanding:可擴充套件尺寸,元件可擴充套件.
  • QSizePolicy::MinimumExpanding:最小可擴充套件尺寸,綜合了可擴充套件尺寸與最小尺寸.
  • QSizePolicy::Ignored:忽略尺寸,sizeHint()函式的返回值被忽略,元件佔據儘可能大的空間.

在使用QSizePolicy的時候,QWidget的sizeHint()函式會起到很大作用.

在元件的父元件尺寸發生變化時,sizeHint()返回元件的建議尺寸.

一般不需要修改元件的sizePolicy屬性,使用其預設值即可.

部分部件的尺寸策略還進一步細分為水平策略與垂直策略

水平延伸因子與垂直延伸因子都是整數值,其取值範圍在0~255.

QWidget作為視窗時的屬性

屬性 屬性值型別 功能
windowTitle QString 視窗標題欄的文字
windowIcon QIcon 視窗標題上的圖表
windowOpacity qreal 視窗的不透明度(範圍0.0~1.0)
windowFilePath QString 視窗相關的含路徑檔名
windowModified bool 顯示視窗內文件是否被修改(*)
windowModality Qt::WindowModality 視窗的模態,表示視窗是否在上層
windowFlags Qt::WindowFlags 視窗的標誌,是其一些值的組合

QWidget作為獨立的視窗時,實際上還有一些與視窗顯示有關的共用槽函式.

名稱 功能
close() 關閉視窗
hide() 隱藏視窗
show() 顯示視窗
showFullScreen() 以全屏方式顯示視窗
showMaximized() 視窗最大化
showMinimized() 視窗最小化
showNormal() 恢復正常視窗

佈局管理

在Qt Designer的元件皮膚裡有用於佈局管理的兩組元件,Layouts與Spacers.

QLayout繼承自QObject與QLayoutItem.是Layouts中所有元件的基類.QLayout不是從QWidget繼承來的.

從QLayout繼承而來的幾個類是常用的佈局管理類:

  • QVBoxLayout:垂直佈局
  • QHBoxLayout:水平佈局
  • QGridLayout:網格佈局,使元件按行與列網格狀佈局
  • QFormLayout:表單佈局,與Grid相似,但只有兩列
  • QStackedLayout:堆疊佈局,用於管理多個頁面

任何佈局類物件在視覺化設計時都有layoutLeftMargin,layoutTopMargin,layoutRightMargin和layoutBottomMargin這個4個邊距屬性用於設定佈局元件與父容器的4個邊距的最小值.

下面是一個調整邊距屬性值及layoutSpacing的例子:

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    this->windowTitle().clear();
    this->setWindowTitle(QString("this is my window"));

    QVBoxLayout* total_layout;
    total_layout= new QVBoxLayout;

    QGroupBox *btn_group;
    btn_group= new QGroupBox(this);
    btn_group->setGeometry(QRect(260,310,341,43));

    QPushButton* btn_1,*btn_2,*btn_3;
    btn_1= new QPushButton("button_1",btn_group);
    btn_2= new QPushButton("button_2",btn_group);
    btn_3= new QPushButton("button_3",btn_group);

    QHBoxLayout* btn_layout;
    btn_layout= new QHBoxLayout;
    btn_layout->setSpacing(10);
    btn_layout->setContentsMargins(15,25,5,5);
    btn_layout->addWidget(btn_1);
    btn_layout->addWidget(btn_2);
    btn_layout->addWidget(btn_3);

    total_layout->addLayout(btn_layout);
    this->setLayout(total_layout);
}

在上面的例子中,所有的QPushButton都以QGroupBox為父物件.

使用QGroupBox::setGeometry()設定了元件的幾何形狀.

使用QHBoxLayout::setSpacing()設定了元件間的最小間距.

使用QHBoxLayout::setContentMargins()設定了四個邊距的值.

網格佈局

視覺化設計網格佈局時一般是在一個容器元件內先擺放元件,使各元件的位置和大小與期望的效果大致相同,然後點選工具欄上的網格佈局按鈕進行網格佈局.

除了4個邊距屬性,網格佈局還有幾個特有的屬性:

  • layoutHorizontalSpacing:水平方向上元件最小間距
  • layoutVerticalSpacing:垂直方向上元件最小間距
  • layoutRowStretch:各行的延展因子
  • layoutColumnStretch:各列的延展因子
  • layoutRowMinimumHeight:各行的最小高度,單位為畫素
  • layoutColumnMinimumWidth:各列的最小寬度,單位為畫素
  • layoutSizeConstraint:佈局的尺寸限制方式

下面是應用網格佈局應用的一個例子:

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QGroupBox *groupBox=new QGroupBox(this);
    groupBox->setGeometry(QRect(290,160,200,230));

    QGridLayout *gridLayout=new QGridLayout(groupBox);
    gridLayout->setHorizontalSpacing(7);
    gridLayout->setVerticalSpacing(12);
    gridLayout->setContentsMargins(10,10,-1,-1);

    QPushButton *pushButton=new QPushButton(groupBox);
    gridLayout->addWidget(pushButton,0,0,1,1);
    QPushButton *pushButton_2=new QPushButton(groupBox);
    gridLayout->addWidget(pushButton_2,0,1,1,1);
    QComboBox *comboBox=new QComboBox(groupBox);
    comboBox->addItem(QString());
    gridLayout->addWidget(comboBox,1,0,1,2);
    QPlainTextEdit *plainTextEdit=new QPlainTextEdit(groupBox);
    gridLayout->addWidget(plainTextEdit,2,0,1,2);
    this->setLayout(gridLayout);
}


其中,下面的語句表示將表格新增至0行0列,佔據1行1列的位置.

    gridLayout->addWidget(pushButton,0,0,1,1);

其他語句以此類推.

分割條佈局

實現分割條功能的類是QSplitter,分隔條可以實現水平分割或垂直分割.一般是在兩個可以自由改變大小的元件間分割.

分割條主要有以下幾個屬性:

  • orientation:方向,即水平分割或垂直分割
  • opaqueResize:如果值為true,則拖動分割條時,元件是動態改變大小的.
  • handleWidth:進行分割操作的拖動條的寬度,單位為畫素.
  • childrenCollapsible:表示進行分割操作時,子元件大小是否可以為0.

下面是一個使用分割條的例子:

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QSplitter *splitter=new QSplitter(this);
    splitter->setOrientation(Qt::Horizontal);
    splitter->setOpaqueResize(true);
    splitter->setHandleWidth(8);
    splitter->setMinimumSize(QSize(350,200));
    splitter->setChildrenCollapsible(true);

    QGroupBox *groupBox=new QGroupBox(splitter);
    groupBox->setMinimumSize(QSize(10,0));
    splitter->addWidget(groupBox);
    QPlainTextEdit *plainTextEdit;
    plainTextEdit=new QPlainTextEdit;
    splitter->addWidget(plainTextEdit);

}


QChar字元

QChar是一個類,用於處理Qt中的字元.可以將其理解為一個加強版的char.

QChar有很多介面函式,常用的有:

  • isDigital():是否為數字
  • isLetter():是否為字母
  • isLetterOrNumber():是否為字母或數字
  • isLower():是否為小寫數字
  • isUpper():是否為大寫數字
  • isMark():是否為記號
  • isNonCharacter():是否為非文字字元
  • isNull():是否為'\0'
  • isNumber():判斷字元是否為一個數,包括①之類的序號
  • isPrint():判斷字元是否為可列印字元
  • isPunct():判斷字元是否為標點符號
  • isSpace():判斷字元是否為分割符號,如空格,製表符
  • isSymbol():判斷字元是否為符號
  • toLower():返回小寫形式
  • toUpper():返回大寫形式
  • (char16_t)unicode():返回16位編碼數值

其中值得注意的是一個靜態函式QChar::fromLatin1(),其用於將Latin1字元轉換為QChar字元.

與之對應的,QChar有一個toLatin1()函式用於將QChar字元轉換為Latin1字元.

提供一個使用例子:

QString str="String";
QChar ch=QChar::fromLatin1('Q');
str[0]=ch;

與之相似的,在QChar與UTF-16值轉換方面有unicode()方法與QChar::fromUsc2(char16_t c)函式.

QString字串

QString是Qt中的一個類,用於儲存字串.一般來說,Qt使用到字串的地方都使用QString.

而一般的std::string與QString互轉需要透過QString::fromStdString(str)與qstr.toStdString().

QString是由QChar組成的一個串,QChar使用的是UTF-16編碼.

QString使用隱式共享來減少記憶體佔用.這意味著只有在修改一個字串的時候,這個字串才會複製.

QString的建立與初始化

QString可以直接透過const char*初始化.

QString str="Hello World";

QString在被建立與初始化後,其儲存的就是一個QChar的字元陣列.可以對其進行索引.

QString str="Hello";
QChar ch0=str[0];

QString字串常用操作

可以使用加法運算子進行字串拼接.

QString str1="Hello ";
QString str2="World";
Qstring str3=str1+str2;

也可以透過append()在字串後新增字串,透過prepend()在字串前新增字串.

QString str1="igg";
str1.preend(QString("n"));
str1.append(QString("a")); 

front()返回第一個字元,back()返回最後一個字元.

left(n)返回前n個字元,right(n)返回後n個字元.注意:轉義符視為一個字元處理.

mid(pos,n)返回字串中的字元數,pos為起始位置,n為返回字元的個數.

sliced()與mid()功能相同,但是其不判斷是否在邊界內.

函式section()用於從字串中提取sep作為分隔符,從start段到end段的字串.

例如:

QString str1="學生姓名,男,2004-09-15,漢族,湖南",str2;
str2=str1.section(",",0,0);//學生姓名
str2=str1.section(",",1,1);//男
str2=str1.section(",",1,2);//男,2004-09-15
str2=str1.section(",",4,4);//湖南

isNull()和isEmpty()作用相似,但是isNull()會對'\0'進行判定,而isEmpty()判定'\0'為true.

QString str1="",str2;
str1.isNull();//false
str1.isEmpty();//true
str2.isNull();//true
str2.isEmpty();//true

count(),若帶有引數,可以統計某個字元在字串中出現的次數.若不帶引數,count(),size()與length()都返回字串長度.

clear()函式清空當前字串,使字串為NULL.

resize()用於改變字串長度,但如果長度短於當前字串則會截斷;長度長於當前字串則會導致未初始化的記憶體.

如果resize內含有引數,那麼則使用該QChar填充字串填充部分.

與resize()不同,函式fill()則將字串中每個字元都用一個新字元替換.其同樣可以透過引數調整字串長度.

indexOf()與lastIndexOf()的功能是在字串內查詢某個字串首次與最後一次出現的位置.

contains()判斷當前字串是否包含某個字串.可透過Qt::CaseInsensitive表示是否分辨大小寫.

endsWith()和startWith()判斷字串是否以某個字串開頭或結尾.

count()用於統計當前字串中某個字串出現的次數.可以設定Qt::CaseInsensitive是否分辨大小寫.

函式toUpper()和toLower()用於將字串內的字母全部轉換為大寫字母或小寫字母.

trimmed()和simplified(),trimmed()會去掉字串首尾的空格,函式simplified()不僅去掉首尾空格,還會將中間的連續空格用單個空格替換.

chop(n)去掉字串末尾的n個字元,如果n大於實際意義,字串內容就變為空.

insert(pos,str),函式insert用於在某個位置插入一個字串.如果pos大於實際意義,字串會自動補充空格填充.

replace(pos,n,after)用於從某個位置開始替換n個字元.

其還有一種形式replace(before,after)用於替換所有before字串為after.可以指定Qt::CaseInsensitive分辨大小寫.

remove(pos,n)的功能為從字串pos開始的位置移出n個字元.若超出實際意義,則把pos後面的字元都移除.

同樣的,其還有另一種引數模式,remove(ch),即移除字串中某個字元出現的所有例項.

QString字串與數值轉換

QString有一些介面函式用於將字串轉換為整數:

引數ok用於獲取返回值,表示轉換是否成功.

  • toInt(bool* ok,int base=10)
  • toUInt(bool* ok,int base=10)
  • toLong(bool* ok,int base=10)
  • toUInt(bool* ok,int base=10)
  • toShort(bool* ok,int base=10)
  • toUShort(bool* ok,int base=10)
  • toLongLong(bool* ok,int base=10)
  • toULongLong(bool* ok,int base=10)

其也還有兩個介面函式用於將字串轉換為浮點數:

  • toFloat(bool* ok)
  • toDouble(bool* ok)

函式setNum()則用於將整數或浮點數轉換為字串.

  • setNum(int n,int base=10)
  • setNum(float n,char format='g',int precision=6)
格式字元 格式字元含義 精度位數含義
e,E 科學計數法 基數小數點後位數
f 自然計數法 小數點後的有效位數
g,G 根據情況自動調節 小數點前後的數字位數之和

QString還有一個靜態函式number(),其與setNum類似,但是是靜態函式形式

  • QString::number(long n,int base)
  • QString::number(double n,char format,precision)

靜態函式asprintf()用於構造格式化輸出字串.

  • QString QString::asprintf(const char cformat*,...)

但是注意,asprintf輸出%s會導致亂碼,只能使用UTF-8編碼的const char*字串來作為引數.

也就是說,QString型的字串應當透過QString::data()來表現.

例如:

QString str1=QString::asprintf("Year=%d,Month=%02d",2024,04);
QString str2="哈爾濱工程大學 拓荒者學社"
QString str3=QString::asprintf("歡迎來到%s",str2.toLocal8Bit().data());
QString str4=QString::asprintf("PI=%.10f",M_PI);//3.1415926536

arg()函式是QString的成員函式,用於格式化輸出各種資料的字串,其功能與asprintf類似.

但是arg函式透過形式為%n的佔位符來對應實參,這與一般printf不同.

int year=2024,month=2,day=23;
QString str=QString("%1年,%2月,%3日").arg(year).arg(month).arg(day);

QSpinBox和QDoubleSpinBox

屬性名稱 功能
prefix 數字顯示的字首
suffix 數字現實的字尾
buttonSysbols 右側調節按鈕的符號
text 只讀屬性,SpinBox內的所有文字
cleanText 只讀屬性,不帶前字尾的所有文字
minimum 數值範圍的最小值
maximum 數值範圍的最大值
singleStep 單步步長改變值
stepType 步長型別,單一步長或自適應步長
value 當前顯示的值
displayIntegerBase QSpinBox使用的進位制
decimals QDoubleSpinBox顯示的小數位數

對於預設值value的相關操作,存在兩個相關的函式:

  • int QSpinBox::value()
  • void QSpinBox::setValue(int val)

對於相關的讀寫範圍,還有一個函式setRange(),用於同時設定最小值與最大值.

  • void QSpinBox::setRange(int minimum,int maximum)

QSpinBox還有兩個特有的訊號,訊號定義如下:

  • void QSpinBox::valueChanged(int i)
  • void QSpinBox::textChanged(const QString &text)

訊號valueChanged()在value變化時被髮射,傳遞的引數為變化之後的數值.

訊號textChanged()在顯示的文字發生變化的時候被髮射.

下面是使用QSpinBox的一個例項:

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    //ui->setupUi(this);

    lbTest1= new QLabel(QString("電源電動勢"));
    lbTest2= new QLabel(QString("反應物濃度"));
    lbTest3= new QLabel(QString("十六進位制值測試"));

    sbTest1= new QSpinBox;
    sbTest2= new QSpinBox;
    sbTest3= new QSpinBox;
    sbTest1->setSuffix(QString("mV"));
    sbTest1->setValue(10);
    sbTest2->setSuffix(QString("mod/L"));
    sbTest2->setValue(1);
    sbTest3->setSuffix(QString("值"));
    sbTest3->setValue(28);
    sbTest3->setDisplayIntegerBase(16);

    txlTest= new QLineEdit;
    txlTest->setText(QString("這裡會顯示內容"));
    connect(sbTest1,SIGNAL(valueChanged(int)),this,SLOT(SpinBoxToLineEdit(int)));

    QGridLayout* gridTest= new QGridLayout;
    gridTest->addWidget(lbTest1,0,0,1,1);
    gridTest->addWidget(lbTest2,1,0,1,1);
    gridTest->addWidget(lbTest3,3,0,1,1);
    gridTest->addWidget(sbTest1,0,1,1,1);
    gridTest->addWidget(sbTest2,1,1,1,1);
    gridTest->addWidget(sbTest3,3,1,1,1);
    gridTest->addWidget(txlTest,2,0,1,2);

    this->setLayout(gridTest);
}
void Widget::SpinBoxToLineEdit(int i)
{
    this->txlTest->clear();
    this->txlTest->insert(QString("電源電動勢改變後:%1").arg(i));
    return;
}

常用的按鈕控制元件

按鈕是介面上常用的元件,常用的4種按鈕控制元件是:普通按鈕(QPushButton),工具按鈕(QToolButton),單選按鈕(QRadioButton),核取方塊(QCheckBox)

這四種按鈕都是繼承於QAbstractButton類的.

QAbstractButton主要屬性
屬性 屬性值型別 功能
text QString 按鈕的顯示文字
icon QIcon 按鈕的圖示
shortcut QKeySequence 按鈕的快捷鍵
checkable bool 按鈕是否可複選
checked bool 按鈕是否複選狀態
autoExclusive bool 在一個佈局或容器元件內的同類按鈕是否互斥
autoRepeat bool 是否自動重複發射訊號
  • QPushButton的checkable預設為false
  • QRadioButton和QCheckBox的checkable屬性預設為true
  • QCheckBox的autoExclusive屬性預設為false
  • QRadioButton的autoExclusive屬性預設為true
QPushButton的新增屬性
屬性 屬性值型別 功能
autoDefault bool 按鈕是否為自動預設按鈕
default bool 按鈕是否為預設按鈕
flat bool 按鈕是否沒有邊框

QCheckBox新增了一個tristate屬性,QRadioButton沒有新的屬性.

QAbstractButton定義的新訊號:

  • void clicked(bool checked)//點選按鈕時
  • void pressed()//按下空格或左鍵
  • void released()//釋放空格或左鍵
  • void toggled(bool checked)//按鈕的checked屬性變化

QPushButton和QRadioButton沒有定義新訊號.

QCheckBox定義了一個新訊號:

  • void QCheckBox::stateChanged(int state)

下面提供了一個使用button的例子:
mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
private slots:
    void on_btnLeft();
    void on_btnMiddle();
    void on_btnRight();

    void on_btnBF();
    void on_btnIT();
    void on_btnUL();

    void on_chkRead(bool checked);
    void on_chkEnabled(bool checked);
    void on_chkClean(bool checked);

    void on_radBlack();
    void on_radBlue();
    void on_radRed();

signals:

};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(ui->btnLeft,SIGNAL(clicked(bool)),this,SLOT(on_btnLeft()));
    connect(ui->btnRight,SIGNAL(clicked(bool)),this,SLOT(on_btnRight()));
    connect(ui->btnMiddle,SIGNAL(clicked(bool)),this,SLOT(on_btnMiddle()));

    connect(ui->btnBF,SIGNAL(clicked(bool)),this,SLOT(on_btnBF()));
    connect(ui->btnIT,SIGNAL(clicked(bool)),this,SLOT(on_btnIT()));
    connect(ui->btnUL,SIGNAL(clicked(bool)),this,SLOT(on_btnUL()));

    connect(ui->radBlack,SIGNAL(clicked(bool)),this,SLOT(on_radBlack()));
    connect(ui->radBlue,SIGNAL(clicked(bool)),this,SLOT(on_radBlue()));
    connect(ui->radRed,SIGNAL(clicked(bool)),this,SLOT(on_radRed()));

    connect(ui->chkClean,SIGNAL(clicked(bool)),this,SLOT(on_chkClean(bool)));
    connect(ui->chkEnabled,SIGNAL(clicked(bool)),this,SLOT(on_chkEnabled(bool)));
    connect(ui->chkRead,SIGNAL(clicked(bool)),this,SLOT(on_chkRead(bool)));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_btnLeft()
{
    ui->pltEdit->setAlignment(Qt::AlignLeft);
}

void MainWindow::on_btnMiddle()
{
    ui->pltEdit->setAlignment(Qt::AlignCenter);
}

void MainWindow::on_btnRight()
{
    ui->pltEdit->setAlignment(Qt::AlignRight);
}

void MainWindow::on_btnBF()
{
    static bool flag=true;
    QFont font= ui->pltEdit->font();
    font.setBold(flag);
    ui->pltEdit->setFont(font);
    flag=!flag;
}

void MainWindow::on_btnIT()
{
    static bool flag=true;
    QFont font= ui->pltEdit->font();
    font.setItalic(flag);
    ui->pltEdit->setFont(font);
    flag=!flag;
}

void MainWindow::on_btnUL()
{
    static bool flag=true;
    QFont font= ui->pltEdit->font();
    font.setUnderline(flag);
    ui->pltEdit->setFont(font);
    flag=!flag;
}

void MainWindow::on_chkRead(bool checked)
{
    ui->pltEdit->setReadOnly(checked);
}

void MainWindow::on_chkEnabled(bool checked)
{
    ui->pltEdit->setEnabled(checked);
}

void MainWindow::on_chkClean(bool checked)
{
    ui->pltEdit->setClearButtonEnabled(checked);
}

void MainWindow::on_radBlack()
{
    QPalette plet= ui->pltEdit->palette();
    plet.setColor(QPalette::Text,Qt::black);
    ui->pltEdit->setPalette(plet);
}

void MainWindow::on_radBlue()
{
    QPalette plet= ui->pltEdit->palette();
    plet.setColor(QPalette::Text,Qt::blue);
    ui->pltEdit->setPalette(plet);
}

void MainWindow::on_radRed()
{
    QPalette plet= ui->pltEdit->palette();
    plet.setColor(QPalette::Text,Qt::red);
    ui->pltEdit->setPalette(plet);
}

QSlider和QProgressBar

QAbstractSlider是QSlider,QScrollBar和QDial的父類,它定義了這幾個類共有的一些屬性和介面函式.

QAbstractSlider的屬性
屬性 屬性值型別 功能
minimum int 資料範圍的最小值
maximum int 資料範圍的最大值
singleStep int 變化最小步長
pageStep int 按PgUp與PgDn變化的數值
value int 元件的當前值
sliderPosition int 滑塊的位置
tracking bool 改變value是否改變slider位置
orientation Qt::Orientation 滑動條的方向,水平或垂直
invertedAppearance bool 顯示方式是否反向
invertedControls bool 反向按鍵控制

QAbstractSlider的介面函式主要是屬性的讀寫函式,還有一個常用函式setRange()用於設定最大值與最小值.

  • void QAbstractSlider::setRange(int min,int max)

QAbstractSlider類的訊號主要有:

  • void actionTriggered(int action)//滑動條觸發一些動作
  • void rangeChanged(int min,int max)//minimum或maximum值變化時
  • void sliderMoved(int value)//使用者按住滑鼠拖動滑塊時
  • void sliderPressed()//在滑塊上按下滑鼠時
  • void sliderReleased()//在滑塊上釋放滑鼠時
  • void valueChanged(int value)//value值改變時

action表示動作的型別,用列舉型別QAbstractSlider::SliderAction的值表示.如SliderToMinimum表示拖動到最小值.

如果tracking屬性被設定為false時,valueChanged()僅在滑鼠拖動結束時發射.

QSlider一般用於滑動輸入數值資料的元件,其新定義的屬性有兩個:

  • tickPosition:標尺刻度的顯示位置,屬性值為列舉型別QSlider::TickPosition.
  • tickInterval:標尺刻度的間隔值.

QScrollBar沒有新定義的屬性,一般與文字編輯器或容器元件組合使用.起滾卷條的作用.

QDial表示錶盤式元件,透過旋轉錶盤獲得輸入值.QDial定義了3個新的屬性:

  • notchesVisible:錶盤外圍的刻度線是否可見.
  • notchTarget:錶盤刻度間的間隔畫素值.
  • wrapping:錶盤上首尾刻度是否連貫.

QProgressBar表示進度條元件,一般以百分比資料來顯示進度.其父類為QWidget.

其幾個不易理解的屬性如下:

  • textDirection:文字的方向.
  • format:顯示文字的格式.

QProgressBar類的介面函式主要是屬性的讀寫函式.QProgressBar還有兩個常用的與屬性無關的函式:

  • void QProgressBar::setRange(int minimum,int maximum)
  • void QProgressBar::reset()

下面是一個使用捲軸的例項:

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(ui->dial,SIGNAL(valueChanged(int)),this,SLOT(do_valueChange(int)));
    connect(ui->progressBar,SIGNAL(valueChanged(int)),this,SLOT(do_valueChange(int)));
    connect(ui->scrollBar,SIGNAL(valueChanged(int)),this,SLOT(do_valueChange(int)));
    connect(ui->slider,SIGNAL(valueChanged(int)),this,SLOT(do_valueChange(int)));
    connect(ui->spinBox,SIGNAL(valueChanged(int)),this,SLOT(do_valueChange(int)));

    ui->dial->setNotchesVisible(true);
    do_valueChange(10);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::do_valueChange(int value)
{
    ui->dial->setValue(value);
    ui->progressBar->setValue(value);
    ui->scrollBar->setValue(value);
    ui->slider->setValue(value);
    ui->spinBox->setValue(value);
}

日期時間資料

日期和時間是經常遇到的資料型別.Qt提供了三個類用於表示和處理資料型別:

  • QTime:表示時間資料的類.
  • QDate:表示日期資料的類.
  • QDateTime:表示時間和日期資料的類.

這三個類都沒有父類.為了在介面上輸入和現實日期時間的資料,Qt定義了幾個用於日期時間資料處理的介面類:

  • QTimeEdit:編輯和顯示時間的元件類
  • QDateEdit:編輯和顯示日期的元件類
  • QDateTimeEdit:編輯和顯示日期的元件類.
  • QCalendarWidget:一個用日曆形式顯示和選擇日期的元件類.

QTime類適用於儲存與操作時間資料的類,時間資料包含小時,分鐘,秒,毫秒.QTime總是24小時制,不區分AM/PM.

QTime初始化時間資料的函式定義如下:

  • QTime::QTime(int h,int m,int s=0,int ms=0)

還可以使用靜態函式QTime::currentTime()建立一個QTime物件,並將其初始化為系統當前時間.

QTime類的主要介面函式
函式原型 功能
int hour() 返回當前時間的小時
int minute() 返回當前時間的分鐘
int second() 返回當前時間的秒
int misec() 返回當前時間的毫秒
bool setHMS(int h,int m,int s,int ms=0) 設定當前時間的資料
int msecSinceStartOfDay() 返回時間從00:00:00開始的毫秒數
QTime addSecs(int s) 當前時間延後s秒後的時間
int secsTo(QTime t) 返回一個與當前時間相差t秒的秒數
QString toString(const QString& format) 將當前時間按照format格式轉換為字串

QDate是用於儲存和操作日期資料的類,日期資料包含年月日資料.

與QTime類似,可以在初始化時為其提供資料,也可以使用靜態函式QDate::currentDate()獲取系統當前日期.

QDate類的主要介面函式
函式原型 功能
int year() 返回當前日期年資料
int month() 返回當前日期月資料
int day() 返回當前日期日資料
int dayOfWeek() 返回當前日期在一週中的日期
int dayOfYear() 返回當前日期在一年中是第多少天
bool setDate(int year,int month,int day) 設定日期的年日月資料
void getDate(int* year,int* month,int* day) 透過指標變數,返回年日月資料
QDate addYears(int nyears) 返回一個較時間遲n年的QDate變數
QDate addMonths(int nmonths) 返回一個較時間遲n月的QDate變數
QDate addDays(qint64 ndays) 返回一個較時間遲n天的QDate變數
qint64 daysTo(QDate d) 返回一個與當前日期差d天的天數
QString toString(const QString&format) 將當前日期按照format格式轉換為字串

此外,QDate還有一個靜態函式isLeapYear()可以判斷某年是否為閏年:

  • bool QDate::isLeapYear(int year)
QDateTime類的主要介面函式
函式原型 功能
QDate date() 返回當前日期時間資料的日期資料
QTime time() 返回當前日期時間資料的時間資料
qint64 toMSecsSinceEpoch() 返回與UTC時間1970-01-01T00:00:00:00.000相差的毫秒數
void setMSecsSinceEpoch(qint64 msecs) 設定與UTC時間1970-01-01T00:00:00:00.000相差的毫秒數
qint64 toSecsSinceEpoch() 返回與UTC時間1970-01-01T00:00:00:00.000相差的秒數
void setSecsSinceEpoch(qint64) 設定與UTC時間1970-01-01T00:00:00:00.000相差的秒數
QString toString(const QString& format) 將當前日期時間按照format設定的格式轉換為字串
QDateTime toUTC() 將當前時間轉換為UTC時間

QDateTime有兩個靜態函式用於返回系統當前時間:

  • QDateTime QDateTime::currentDateTime()
  • QDateTime QDateTime::currentDateTimeUtc()

QTime,QDate,QDateTime都有一個函式toString(),用於將當前的日期時間資料轉換為字串.

同樣的,QTime,QDate,QDateTime都有一個靜態函式fromString().用於將字串轉換為相應類的物件.

  • QString QDateTime::toString(const QString&format,QCalendar cal=QCalendar())
  • QDateTime QDateTime::fromString(const QString&string,const QString&format,QCalendar cal=QCalendar())
用於表示日期時間的常用格式字元及含義
格式字元 含義
d 天1~31
dd 天01~31
M 月1~12
MM 月01~12
yy 年00~99
yyyy 年0000~9999
h 小時023或112
hh 小時0023或0112
H 小時0~23
HH 小時00~23
m 分鐘0~59
mm 分鐘00~59
s 秒0~59
ss 秒00~59
z 毫秒0~999
zzz 毫秒000~999
AP或A 使用AM/PM顯示
ap或a 使用am/pm顯示

而且上述字元僅作為一個佔位符使用,其其他內容不影響其字串format.

QtDesigner有3個用於編輯日期時間資料的介面元件,如QTimeEdit,QDateEdit,QDateTimeEdit.

而QDateTimeEdit是QDateEdit和QTimeEdit的父類,而QDateTimeEdit的父類是QAbstractSpinBox.

所以其實日期時間編輯框的特性與QSpinBox的有些相似.

QDateTimeEdit的主要屬性有:

  • currentSection:游標所在的輸入段,是列舉型別QDateTimeEdit::Section.
  • currentSecitonIndex:用序號表示的游標所在的段.
  • calendarPopup:是否允許彈出一個日曆選擇框.會將上下調節按鈕變成一個下拉按鈕.
  • displayFormat:日期時間資料的顯示格式.

QDateTimeEdit常用的介面函式就是讀取或設定日期時間資料的函式:

  • QDateTime dateTime()
  • void setDateTime(const QDateTime&dateTime)
  • QDate date()
  • void setDate(QDate date)
  • QTime time()
  • void setTime(QTime time)

QDateTimeEdit有3個訊號:

  • void dateChanged(QDate date)
  • void timeChanged(QTime time)
  • void dateTimeChanged(const QDateTime& datetime)

QCalendarWidget則是一個用於選擇日期的日曆元件.

QCalendarWidget的幾個常見介面函式有:

  • void showToday()
  • void showSelectedDate()
  • QDate selectedDate()
  • void setSelectedDate(QDate date)

QCalendarWidget有4個訊號:

  • void activated(QDate date)
  • void clicked(QDate date)
  • void currentPageChanged(int year,int month)
  • void selectionChanged()

選擇的日期變化時,QCalendarWidget會發射selectionChanged訊號.

下面給出了一個使用QDateTime,QCalendarWidget等的例子:
mainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
private slots:
    void on_btnReset();
    void on_btnClear();
    void on_btnTime();
    void on_btnDate();
    void on_btnDateTime();
    void on_btnChange();

    void on_timeEdit();
    void on_dateEdit();
    void on_dateTimeEdit();
    void on_calendar();
};
#endif // MAINWINDOW_H

mainWindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(ui->btnClear,SIGNAL(clicked(bool)),this,SLOT(on_btnClear()));
    connect(ui->btnReset,SIGNAL(clicked(bool)),this,SLOT(on_btnReset()));
    connect(ui->btnTime,SIGNAL(clicked(bool)),this,SLOT(on_btnTime()));
    connect(ui->btnDate,SIGNAL(clicked(bool)),this,SLOT(on_btnDate()));
    connect(ui->btnDateTime,SIGNAL(clicked(bool)),this,SLOT(on_btnDateTime()));
    connect(ui->btnChange,SIGNAL(clicked(bool)),this,SLOT(on_btnChange()));

    connect(ui->dateEdit,SIGNAL(dateChanged(QDate)),this,SLOT(on_dateEdit()));
    connect(ui->timeEdit,SIGNAL(timeChanged(QTime)),this,SLOT(on_timeEdit()));
    connect(ui->dateTimeEdit,SIGNAL(dateTimeChanged(QDateTime)),this,SLOT(on_dateTimeEdit()));
    connect(ui->calendar,SIGNAL(selectionChanged()),this,SLOT(on_calendar()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_btnReset()
{
    ui->calendar->clearFocus();
    ui->dateEdit->clear();
    ui->timeEdit->clear();
    ui->dateTimeEdit->clear();
    ui->pltEdit->clear();
    ui->lineEdit->clear();
}

void MainWindow::on_btnClear()
{
    ui->lineEdit->clear();
    ui->pltEdit->clear();
}

void MainWindow::on_btnTime()
{
    QTime TM1(13,24,5);
    QString str=TM1.toString("HH:mm:ss");
    ui->pltEdit->appendPlainText(QString("Time1:%1").arg(str));
    QTime TM2= TM1.addSecs(150);
    str= TM2.toString("HH:mm:ss");
    ui->pltEdit->appendPlainText(QString("Time1 add 150secs:%1").arg(str));
    TM2= QTime::currentTime();
    str=TM2.toString("HH:mm:ss zzz");
    ui->pltEdit->appendPlainText(QString("Current Time:%1").arg(str));
}

void MainWindow::on_btnDate()
{
    QDate DT1(2021,7,6);
    QString str=DT1.toString("yyyy-MM-dd");
    ui->pltEdit->appendPlainText(QString("Date1:%1").arg(str));
    QDate DT2;
    DT2.setDate(2021,8,25);
    str=DT2.toString("yyyy-MM-dd");
    ui->pltEdit->appendPlainText(QString("Date2:%1").arg(str));
    DT2=QDate::currentDate();
    str=DT2.toString("yyyy-MM-dd");
    ui->pltEdit->appendPlainText(QString("Current Date:%1").arg(str));
}

void MainWindow::on_btnDateTime()
{
    QDateTime DT1=QDateTime::currentDateTime();
    QString str=DT1.toString("yyyy-MM-dd hh:mm:ss zzz");
    ui->pltEdit->appendPlainText(QString("Current DateTime:%1").arg(str));
    QDate dt= DT1.date();
    str=dt.toString("yyyy-MM-dd");
    ui->pltEdit->appendPlainText(QString("DT1 Date:%1").arg(str));
    QTime tm=DT1.time();
    str=tm.toString("hh:mm:ss zzz");
    ui->pltEdit->appendPlainText(QString("DT1 Time:%1").arg(str));
    qint64 MS=DT1.toSecsSinceEpoch();
    ui->pltEdit->appendPlainText(QString("Secs Since:%1").arg(MS));
    MS+=120;
    DT1.setSecsSinceEpoch(MS);
    str=DT1.toString("yyyy-MM-dd hh:mm:ss zzz");
    ui->pltEdit->appendPlainText(QString("DT1 After120s:%1").arg(str));
}

void MainWindow::on_btnChange()
{
    static bool calendar_flag=true;
    ui->dateTimeEdit->setCalendarPopup(calendar_flag);
    calendar_flag=!calendar_flag;
}

void MainWindow::on_timeEdit()
{
    QTime tm= ui->timeEdit->time();
    ui->dateTimeEdit->setTime(tm);
}

void MainWindow::on_dateEdit()
{
    QDate dt= ui->dateEdit->date();
    ui->lineEdit->setText(QString("%1").arg(dt.toString("yyyy-MM-dd")));
    ui->dateTimeEdit->setDate(dt);
    ui->calendar->setSelectedDate(dt);
    ui->calendar->showSelectedDate();
}

void MainWindow::on_dateTimeEdit()
{
    QDateTime datetime= ui->dateTimeEdit->dateTime();
    ui->lineEdit->setText(QString("%1").arg(datetime.date().toString("yyyy-MM-dd")));
    ui->dateEdit->setDate(datetime.date());
    ui->timeEdit->setTime(datetime.time());
    ui->calendar->setSelectedDate(datetime.date());
    ui->calendar->showSelectedDate();
    ui->pltEdit->appendPlainText(QString("Now Time:%1").arg(datetime.toString("yyyy-MM-dd hh:mm:ss zzz")));
}

void MainWindow::on_calendar()
{
    QDate dt=ui->calendar->selectedDate();
    ui->dateEdit->setDate(dt);
    ui->dateTimeEdit->setDate(dt);
    ui->lineEdit->setText(dt.toString("yyyy-MM-dd"));
}

QTimer和QElapsedTimer

QTimer是軟體計時器,其父類是QObject.其主要功能是設定以毫秒為單位的定時週期.

當定時器啟動後,定時溢位時QTimer發射timeout()訊號.

QTimer類的主要屬性如下:

QTimer類的主要屬性
屬性 屬性值型別 功能
interval int 定時週期,單位是毫秒
singleShot bool 定時器是否為單次計時
timerType Qt::TimerType 定時器精度型別
active bool 返回定時器是否正在執行
remainingTime int 到發生定時溢位的剩餘時間

屬性timeType表示定時器的精度型別,設定函式setTimerType()的原型定義如下:

  • void QTimer::setTimerType(Qt::TimerType atype)

引數atype是列舉型別Qt::TimerType,有以下幾個列舉值,預設為Qt::CoarseTimer:

  • Qt::PreciseTimer:精確計時器,精度保持在毫秒級
  • Qt::CoarseTimer:粗糙計時器,定時誤差保持在週期值的5%內
  • Qt::VeryCoarseTimer:非常粗糙的定時器,精度保持在秒級.

QTimer有幾個公有槽函式用於啟動和停止定時器:

  • void QTimer::start()//啟動定時器
  • void QTimer::start(int msec)//啟動定時器,並設定定時週期
  • void QTimer::stop()//停止定時器

QTimer只有一個timeout()訊號,其原型如下:

  • void QTimer::timeout()

QTimer還有一個靜態函式singleShot(),用於建立和啟動單次定時器,並且將定時器的timeout()訊號與指定的槽函式關聯.

這個函式有多種引數形式,其中一種函式原型定義如下:

  • void QTimer::singleShot(int msec,Qt::TimerType,const QObject* receiver,const char* member)

QElapsedTimer則用於快速計算兩個時間的間隔時間,它沒有父類,不支援Qt的元物件系統,所以只有介面函式.

QElapsedTimer的介面函式有:

  • void start()
  • qint64 elapsed()
  • qint64 nsecsElapsed()
  • qint64 restart()

函式elapsed()的返回值是自上次start()之後計時器的執行時間,單位是毫秒.

函式nsecsElapsed()的返回值也是指上次start()之後計時器的執行時間,但單位是納秒.

函式restart()返回從上次啟動計時器到現在的時間,單位是毫秒,然後重啟計時器.

下面是一個使用QTimer的例項:

mainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTime>
#include <QTimer>
#include <QElapsedTimer>

QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    QTimer* m_timer;
    QElapsedTimer m_counter;
private slots:
    void do_timer_timeout();
    void do_timer_shot();

    void do_btnStart();
    void do_btnStop();
    void do_btnOneShot();
};
#endif // MAINWINDOW_H

mainWindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    m_timer= new QTimer(this);
    m_timer->stop();
    m_timer->setTimerType(Qt::CoarseTimer);
    ui->radCoarse->setChecked(true);
    connect(m_timer,SIGNAL(timeout()),this,SLOT(do_timer_timeout()));
    connect(ui->btnStart,SIGNAL(clicked(bool)),this,SLOT(do_btnStart()));
    connect(ui->btnStop,SIGNAL(clicked(bool)),this,SLOT(do_btnStop()));
    connect(ui->btnOneShot,SIGNAL(clicked(bool)),this,SLOT(do_btnOneShot()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::do_timer_timeout()
{
    QApplication::beep();
    QTime curTime= QTime::currentTime();
    ui->LCDHour->display(curTime.hour());
    ui->LCDMin->display(curTime.minute());
    ui->LCDSec->display(curTime.second());
    if(m_timer->isSingleShot()){
        int tmMsec= m_counter.elapsed();
        QString str=QString("流逝的時間:%1毫秒").arg(tmMsec);
        ui->labelTime->setText(str);
        ui->btnStop->setEnabled(false);
    }
}

void MainWindow::do_timer_shot()
{
    QApplication::beep();
    int tmMsec= m_counter.elapsed();
    QString str=QString("流逝的時間:%1毫秒").arg(tmMsec);
    ui->labelTime->setText(str);
    ui->btnOneShot->setEnabled(true);
}

void MainWindow::do_btnStart()
{
    m_timer->setInterval(ui->spinBox->value());
    if(ui->radCoutinue->isChecked())
        m_timer->setSingleShot(false);
    else
        m_timer->setSingleShot(true);

    if(ui->radPrecise->isChecked())
        m_timer->setTimerType(Qt::PreciseTimer);
    else if(ui->radCoutinue->isChecked())
        m_timer->setTimerType(Qt::CoarseTimer);
    else
        m_timer->setTimerType(Qt::VeryCoarseTimer);

    m_timer->start();
    m_counter.start();
    ui->btnStart->setEnabled(false);
    ui->btnOneShot->setEnabled(false);
    ui->btnStop->setEnabled(true);
}

void MainWindow::do_btnStop()
{
    m_timer->stop();
    int tmMsec= m_counter.elapsed();
    int ms= tmMsec%1000;
    int sec= tmMsec/1000;
    QString str= QString("流逝的時間:%1秒%2毫秒").arg(sec).arg(ms,3,10,QChar('0'));
    ui->labelTime->setText(str);
    ui->btnStart->setEnabled(true);
    ui->btnOneShot->setEnabled(true);
    ui->btnStop->setEnabled(false);
}

void MainWindow::do_btnOneShot()
{
    int intv= ui->spinBox->value();
    QTimer::singleShot(intv,Qt::PreciseTimer,this,&MainWindow::do_timer_shot);
    m_counter.start();
    ui->btnOneShot->setEnabled(false);
}

QComboBox

QComboBox是下拉選單框元件,它可以提供下拉選單供使用者選擇輸入,也可以提供編輯框用於輸入文字.

所以QComboBox也被稱為組合框.

QComboBox類的主要屬性
屬性 屬性值型別 功能
editable bool 是否可編輯,若為false則只可使用下拉欄
currentText QString 當前顯示的文字
currentIndex int 當前選中項的序號
maxVisibleItems int 下拉選單中顯示最大條數,若超過將出現卷滾條
maxCount int 下拉選單中最大項數
insertPolicy InsertPolicy 使用者編輯的新文字插入列表的方式,為列舉型別QComboBox::InsertPolicy
placeholderText QString 佔位文字
duplicatesEnabled bool 是否允許列表中出現重複的項
modelColumn int 下拉選單中的資料在資料模型中的列編號

QComboBox使用模型/檢視結構儲存和顯示下拉選單的資料,下拉選單的資料實際上儲存在QStandardItemModel模型裡.下拉選單使用QListView的子類元件顯示.modelColumn屬性表示下拉選單現實的資料在模型中的列編號.

QComboBox的幾個訊號原型如下:

  • void activated(int index)
  • void currentIndexChanged(int index)
  • void currentTextChanged(const QString &text)
  • void editTextChanged(const QString &text)
  • void highlighted(int index)
  • void textActivated(const QString &text)
  • void textHighlighted(const QString &text)

下面是使用QComboBox的一個例項:

mainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
private slots:
    //void on_btnSimpleInit();
    void on_pushButton_5_clicked(bool checked);
    void on_btnSimpleInit_clicked(bool checked);
    void on_chkEditable_clicked(bool checked);
    void on_btnClearList_clicked(bool checked);
    void on_btnDataInit_clicked(bool checked);

    void comChanged(const QString& arg1);
    void on_comData_currentIndexChanged(int index);
    void on_chkReadOnly_clicked(bool checked);
};
#endif // MAINWINDOW_H

mainWindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_5_clicked(bool checked)
{
    ui->pltEdit->clear();
}


void MainWindow::on_btnSimpleInit_clicked(bool checked)
{
    QIcon icon;
    icon.addFile(":/img/icon.jpg");
    ui->comSimple->clear();
    for(int i=0;i<20;i++)
        ui->comSimple->addItem(icon,QString("城市%1").arg(i));
}


void MainWindow::on_chkEditable_clicked(bool checked)
{
    ui->comSimple->setEditable(checked);
}


void MainWindow::on_btnClearList_clicked(bool checked)
{
    ui->comSimple->clear();
}


void MainWindow::on_btnDataInit_clicked(bool checked)
{
    ui->comData->clear();
    QMap<QString,int>city_zone;
    city_zone.insert(QString("北京"),10);
    city_zone.insert(QString("上海"),20);
    city_zone.insert(QString("廣州"),30);
    city_zone.insert(QString("長沙"),40);
    city_zone.insert(QString("成都"),50);
    for(auto iter:city_zone.keys())
        ui->comData->addItem(iter,city_zone.value(iter));
}

void MainWindow::comChanged(const QString &arg1)
{
    ui->pltEdit->appendPlainText(arg1);
}


void MainWindow::on_comData_currentIndexChanged(int index)
{
    Q_UNUSED(index);
    QString str= ui->comData->currentText()+ui->comData->currentData().toString();
    ui->pltEdit->appendPlainText(str);
}


void MainWindow::on_chkReadOnly_clicked(bool checked)
{
    ui->pltEdit->setEnabled(!checked);
}

QMainWindow和QAction

QMainWindow是主視窗類,具有選單欄,工具欄,狀態列等主視窗常見的介面元素.

要設計主視窗上的選單欄,工具欄,按鈕的下拉選單,組建的快捷選單等需要用到QAction類.

視窗介面視覺化設計

建立一個GUI專案,在嚮導中選擇視窗基類為QMainWindow,新建視窗類的名稱會被自動設定為MainWindow.

QAction的父類是QObject,所以支援Qt的元物件系統.在UI視覺化設計時就可以建立Action,使用設計好的Action可以建立選單項和工具按鈕.

Qt Designer介面下方有一個Action編輯器,可以在這個編輯器裡視覺化設計Action.

在Action編輯器中,編輯Action的對話方塊,包括以下一些設定內容:

  • Text:Action的顯示文字
  • Object name:Action的物件名稱
  • ToolTip:當滑鼠游標停留時的提示
  • Icon:Action的圖示
  • Checkable:Action是否可被複選
  • ShortCut:Action的快捷鍵.

在Action編輯器中建立一個Action後,屬性編輯器就會顯示這幾個Action的屬性.一些屬性說明如下:

  • text:用Action建立選單項時顯示的文字.
  • iconText:這是用Action建立工具按鈕時按鈕上顯示的文字.
  • statusTip:這是滑鼠移到Action上時的提示.
  • shortcutContext:這是Action快捷鍵的有效響應範圍.
  • autoRepeat:當快捷鍵一直按下時,Action是否自動重複執行.
  • menuRole:在macOS上才有作用的功能.
  • iconVisibleInMenu:表示選單項上是否需顯示Action圖示.
  • shortcutVisuableInContextMenu:表示使用Action建立右鍵快捷選單時,是否顯示快捷鍵.
  • priority:表示Action在UI上的優先順序.


工具欄對應QToolBar類,選擇一個工具欄後,在屬性編輯器中可對其屬性進行設定.

QToolBar類的主要屬性
屬性名稱 屬性值型別 含義與作用
movable bool 工具欄是否可移動
allowedAreas Qt::ToolBarAreas 工具欄可以放置的視窗區域
orientation Qt::Orientation 工具欄的方向
iconSize QSize 圖示的大小
toolButtonStyle Qt::ToolButtonStyle 工具按鈕樣式
floatable bool 工具欄是否可浮動

屬性toolButtonStyle的取值決定了工具按鈕顯示的樣式,屬性值Qt::ToolButtonStyle有以下幾種列舉值.

  • Qt::ToolButtonIconOnly:只顯示圖示
  • Qt::ToolButtonTextOnly:只顯示文字
  • Qt::ToolButtonTextBesideIcon:文字顯示在圖示旁邊
  • Qt::ToolButtonTextUnderIcon:文字顯示在圖示下面
  • Qt::ToolButtonFollowStyle:由QStyle樣式定義

QAction的類大部分介面函式是用於屬性讀寫的函式.

QAction還定義了一些訊號和公有槽.QAction主要的訊號有:

  • void changed()//Action的text等屬性發生改變時
  • void checkableChanged(bool checkable)//checkable的屬性變化時
  • void enabledChanged(bool enabled)//enabled屬性值變化時
  • void hovered()//滑鼠移動至該Action上時
  • void toggled(bool checked)//checked屬性值變化時
  • void triggered(bool checked=false)//點選此Action時
  • void visibleChanged()//visible屬性值變化時

當我們點選Action建立的選單項/工具按鈕或按下Action的快捷鍵時,QAction屬性發射triggered()訊號.

當Action的checked屬性變化時,Action會發射toggled(bool)訊號.

QAction定義了一些公有槽,這些公有槽可以在程式中直接呼叫或connect.

  • void hover()//觸發hovered()訊號
  • void trigger()//觸發triggered()訊號
  • void resetEnabled()//復位enabled為預設值
  • void setChecked(bool)//設定checked屬性的值
  • void setDisabled(bool b)//設定enabled屬性的值
  • void setVisible(bool)//設定visible屬性的值
  • void toggle()//反轉checked屬性的值

在UI視覺化設計時,可以用Action視覺化地建立工具欄上的按鈕,但是不能視覺化地在工具欄上放置其他元件.

QToolBar提供了介面函式,可以透過程式碼在工具欄上新增元件,從而靈活地設計工具欄.

  • void addAction(QAction *action)//新增一個Action
  • QAction *addWidget(QWidget *widget)//新增一個介面元件
  • QAction *insertWidget(QAction *before,QWidget *widget)//插入一個介面元件
  • QAction *addSeparator()//新增一個分隔條
  • QAction *insertSeparator(QAction *before)//插入一個分隔條

主視窗上的狀態列對應的是QStatusBar類,在UI視覺化設計時,不能在狀態列上放置任何元件,而只能透過其介面函式向狀態列新增元件.

QStatusBar有兩個函式用於新增元件,其原型如下:

  • void addWidget(QWidget *widget,int stretch=0)//新增正常元件
  • void addPermanentWidget(QWidget *widget,int strech=0)//新增永久元件

QStatusBar類有兩個公有槽,可以顯示和清楚臨時訊息,定義如下:

  • void showMessage(const QString &message,int timeout=0)//顯示臨時訊息
  • void clearMessage()//清除臨時訊息

如果一個Action的statusTip屬性不為空,當滑鼠移到這個Action建立的選單或按鈕上時,狀態列就會自動顯示這個Action的statusTip屬性的內容:當滑鼠移出時,臨時訊息就會被自動清除.

下面是一個使用QAction,QToolBar,QStatusBar的綜合例子:

mainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QActionGroup>
#include <QLabel>
#include <QFontComboBox>
#include <QSpinBox>
#include <QProgressBar>
#include <QTextCharFormat>

QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
private:
    QLabel* lbFile;
    QProgressBar* progressBar;
    QSpinBox* spinFontSize;
    QLabel* lbFontSize;
    QFontComboBox* fcomFont;
private slots:
    void on_actNewFile_triggered();

    void on_actOpenFile_triggered();

    void on_actSaveFile_triggered();

    void on_pltEdit_copyAvailable(bool b);

    void on_pltEdit_selectionChanged();

    void on_actBlod_triggered(bool checked);

    void on_actItalian_triggered(bool checked);

    void on_actUnderline_triggered(bool checked);

    void on_spinFontSize(int fontSize);

    void on_fcomCombo(QFont font);
private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

mainWindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    //中英介面互斥
    ui->setupUi(this);
    QActionGroup *acgLanguage = new QActionGroup(this);
    acgLanguage->addAction(ui->actChinese);
    acgLanguage->addAction(ui->actEnglish);
    acgLanguage->setExclusive(true);

    //建立一些無法透過GUI介面設計的元件
    spinFontSize=new QSpinBox(this);
    spinFontSize->setMinimum(5);
    spinFontSize->setMaximum(50);
    spinFontSize->setValue(ui->pltEdit->font().pointSize());
    spinFontSize->setMinimumWidth(50);
    QLabel* lbSpinFont= new QLabel(QString("字號"),this);
    QLabel* lbFontComboBoxFont= new QLabel(QString("字型"),this);
    fcomFont= new QFontComboBox(this);
    fcomFont->setMaximumWidth(80);
    fcomFont->setFont(ui->pltEdit->font());
    ui->toolBar->addWidget(lbSpinFont);
    ui->toolBar->addWidget(spinFontSize);
    ui->toolBar->addWidget(lbFontComboBoxFont);
    ui->toolBar->addWidget(fcomFont);
    ui->toolBar->addSeparator();
    ui->toolBar->addAction(ui->actClose);
    ui->toolBar->addSeparator();

    //狀態列相關
    lbFile= new QLabel(this);
    lbFile->setMaximumWidth(150);
    lbFile->setText(QString("檔名:"));
    ui->statusbar->addWidget(lbFile);
    progressBar= new QProgressBar(this);
    progressBar->setMinimum(5);
    progressBar->setMaximum(50);
    progressBar->setValue(ui->pltEdit->font().pointSize());
    ui->statusbar->addWidget(progressBar);
    lbFontSize= new QLabel(QString("Permanent"),this);
    ui->statusbar->addPermanentWidget(lbFontSize);

    //訊號與槽
    connect(spinFontSize,SIGNAL(valueChanged(int)),this,SLOT(on_spinFontSize(int)));
    connect(fcomFont,SIGNAL(currentFontChanged(QFont)),this,SLOT(on_fcomCombo(QFont)));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_actNewFile_triggered()
{
    ui->pltEdit->clear();
    ui->pltEdit->document()->setModified(false);
    lbFile->setText("檔名:新建檔案");
}


void MainWindow::on_actOpenFile_triggered()
{
    lbFile->setText(QString("正在開啟檔案"));
    for(int i=1;i<99;i++){
        progressBar->setValue(i);
        _sleep(1);
    }
    lbFile->setText(QString("檔名:新建檔案"));
    progressBar->setValue(ui->pltEdit->font().pointSize());
}


void MainWindow::on_actSaveFile_triggered()
{
    ui->pltEdit->clear();
    ui->pltEdit->document()->setModified(false);
    QString str= lbFile->text();
    lbFile->setText("檔案已儲存");
    _sleep(2);
    lbFile->setText(str);
}


void MainWindow::on_pltEdit_copyAvailable(bool b)
{
    ui->actCopy->setEnabled(b);
    ui->actCut->setEnabled(b);
    ui->actPaste->setEnabled(ui->pltEdit->canPaste());
}


void MainWindow::on_pltEdit_selectionChanged()
{
    QTextCharFormat fmt= ui->pltEdit->currentCharFormat();
    ui->actBlod->setChecked(fmt.font().bold());
    ui->actItalian->setChecked(fmt.font().italic());
    ui->actUnderline->setChecked(fmt.font().underline());
    spinFontSize->setValue(fmt.font().pointSize());
    fcomFont->setCurrentFont(fmt.font());
}


void MainWindow::on_actBlod_triggered(bool checked)
{
    QTextCharFormat fmt= ui->pltEdit->currentCharFormat();
    if(checked)
        fmt.setFontWeight(QFont::Bold);
    else
        fmt.setFontWeight(QFont::Normal);
    ui->pltEdit->setCurrentCharFormat(fmt);
}


void MainWindow::on_actItalian_triggered(bool checked)
{
    QTextCharFormat fmt= ui->pltEdit->currentCharFormat();
    fmt.setFontItalic(checked);
    ui->pltEdit->setCurrentCharFormat(fmt);
}


void MainWindow::on_actUnderline_triggered(bool checked)
{
    QTextCharFormat fmt= ui->pltEdit->currentCharFormat();
    fmt.setFontUnderline(checked);
    ui->pltEdit->setCurrentCharFormat(fmt);
}

void MainWindow::on_spinFontSize(int fontSize)
{
    QTextCharFormat fmt=ui->pltEdit->currentCharFormat();
    fmt.setFontPointSize(fontSize);
    progressBar->setValue(fontSize);
    ui->pltEdit->setCurrentCharFormat(fmt);
}

void MainWindow::on_fcomCombo(QFont font)
{
    QTextCharFormat fmt=ui->pltEdit->currentCharFormat();
    fmt.setFont(font);
    ui->pltEdit->setCurrentCharFormat(fmt);
    lbFontSize->setText(QString("字型:%1").arg(font.family()));
}

在此還需要補充QPlainTextEdit相關的一些使用.

QPlainTextEdit元件定義了許多用於編輯操作的槽函式,其也有一些訊號函式:

  • void blockCountChanged(int newBlockCount)//段落數變化時
  • void copyAvailable(bool yes)//有文字被選擇或取消選擇時
  • void cursorPositionChanged(bool changed)//游標位置變化時
  • void modificationChanged(bool changed)//文件的修改狀態變化時
  • void redoAvailable(bool available)//redo操作狀態變化時
  • void selectionChanged()//選擇的內容變化時
  • void textChanged()//文件內容變化時
  • void undoAvailable(bool available)//undo操作狀態變化時
  • void updateRequest(const QRect &rect,int dy)//需要更新顯示時

QToolButton和QListWidget

Qt中用於處理項資料(item data)的元件有兩類:

一類是Item Views元件,包括QListView,QTreeView,QTableView等;

另一類是Item Widgets元件,包括QListWidget,QTreeWidget,QTableWidget等.

Item Widgets元件直接將資料儲存在每一個項裡,一個項儲存了文字,文字的格式定義,圖示,使用者資料等內容.

QToolBox是工具箱元件類,工具箱是一種垂直分頁的多頁容器元件.在UI視覺化設計時,在工具箱元件上點選滑鼠右鍵調出快捷選單,可以分別使用Insert Page和Delete Page選單項新增和刪除頁面.

工具箱的每一個頁面都是一個QWidget元件,在頁面的工作區可以放置任何其他介面元件.

QToolBox有一個訊號,其中index是當前頁面序號:

  • void QToolBox::currentChanged(int index)

對於QListWidget,其有的QListWidgetItem有一個標識變數flags,用於設定列表項的特性.

flags是列舉型別Qt::ItemFlag的列舉值的組合:

  • Selectable:列表項可被選擇,Qt::ItemIsSelectable
  • Editable:列表項可被編輯,Qt::ItemIsEditable
  • DragEnabled:列表項可以被拖動,Qt::ItemIsDragEnabled
  • DropEnabled:列表項可以接收拖放的項,Qt::ItemIsDropEnabled
  • UserCheckable:列表項可以被複選,Qt::ItemIsUserCheckable
  • Enabled:列表項可用,Qt::ItemIsEnabled
  • Tristate:自動改變列表項複選狀態,Qt::ItemIsAutoTristate

QToolButton繼承於一般的QAbstractButton,並在此基礎上有新增的屬性:

  • popupMode屬性:屬性值為QToolButton::ToolButtonPopupMode.這個屬性決定了彈出選單的模式.
    • QToolButton::DelayedPopup:按鈕上沒有任何附加的顯示內容.如果按鈕有下拉選單,則按下按鈕並延時一會兒後才顯示下拉選單.
    • QToolButton::MenuButtonPopup:會在按鈕右側顯示一個帶箭頭的下拉按鈕.
    • QToolButton::InstantPopup:會在按鈕右下角顯示一個很小的下拉箭頭圖示.
  • toolButtonStyle屬性:屬性值是列舉型別Qt::ToolButtonTextBesideIcon.比歐仕工具按鈕上文字標的顯式方式.
  • autoRaise屬性:如果設定為true,按鈕就沒有邊框,滑鼠移動到按鈕上才顯示邊框.
  • arrowType屬性:屬性值是列舉型別Qt::ArrowType,預設值Qt::NoArrow.不會在上面顯示內容.

除了與讀寫相關的一些介面函式,QToolButton類還有兩個主要的函式:

  • setDefaultAction()函式:這個函式用於為工具按鈕設定關聯的Action
    • void QToolButton::setDefaultAction(QAction*action)
  • setMenu()函式:這個函式用於為工具按鈕設定下拉選單,其函式原型定義如下:
    • void QToolButton::setMenu(QMenu*menu)

QMenu是選單類,它直接從QWidget繼承而來.在Qt Designer中我們可以透過Action視窗建立選單欄.

QMenu是管理選單的類,它的父類是QWidget,選單實際上是一種視窗.建立選單主要會用到一下幾個函式:

  • void QWidget::addAction(QAction*action)//新增Action
  • QAction *QMenu::addMenu(QMenu *menu)//新增選單
  • QAciton *QMenu::addSeparator()//新增一個分隔條

顯示選單可以使用exec()函式,其函式原型定義如下:

  • QAction *QMenu::exec(const QPoint&p,QAction*action=nullptr)

引數p表示選單左上角座標,顯示滑鼠右鍵快捷選單時,通常使用滑鼠游標的當前位置QCursor::pos()作為引數p的值.

QListWidget元件的列表項是QListWidgetItem物件.QListWidgetItem沒有父類,所以沒有屬性,但是它有一些讀取函式與設定函式:

QListWidgetItem類的主要介面函式
讀取函式 設定函式 資料型別 設定函式的功能
text() setText() QString 設定項的文字
icon() setIcon() QIcon 設定項的圖示
data() setData() QVariant 為項的不同角色設定資料
flags() setFlags() Qt::ItemFlag 設定項的特性,是Qt::ItemFlag的組合
checkState() setCheckState() Qt::CheckState 設定項的複選狀態
isSelected() setSelected() bool 設定為當前項

QListWidget的主要介面函式則見下:

分組 函式名 功能
新增或刪除項 void addItem() 新增一個項
void addItems() 一次新增多個項
void insertItem() 在某一行前面插入一個項
void insertItems() 在某一行前面一次插入多個項
QListWidgetItem *takeItem() 從列表元件中移除一個項,並返回這個項
的物件指標,但不從記憶體中刪除這個項
void clear() 移除列表中所有的項,並從記憶體中刪除
項的訪問 QListWidgetItem *currentItem() 返回當前項
void setCurrentItem() 設定當前項
QListWidgetItem *item() 根據行號返回一個項
QListWidgetItem *itemAt() 根據螢幕座標返回項
int currentRow() 返回當前行的行號
void setCurrentRow() 設定當前行
int row() 返回一個項所在行號
int count() 返回列表元件中項的個數
排序 void setSortingEnabled() 設定列表是否可排序
bool isSortingEnabled() 列表是否可排序
void sortItems() 對列表按照指定方式排序

QListWidget元件中的每一行是一個QListWidgetItem物件.

QListWidgetItem的函式setFlags()用於設定項的一些特性.其函式原型定義如下:

  • void QListWidgetItem::setFlags(Qt::ItemFlags flags)

QListWidget定義的訊號比較多,各訊號的定義如下:

  • void currentItemChanged(QListWidget *current,QListWidgetItem *previous)
  • void currentRowChanged(int currentRow)
  • void currentTextChanged(const QString& currentText)
  • void itemSelectionChanged()
  • void itemChanged(QListWidgetItem *item)
  • void itemActivated(QListWidgetItem *item)
  • void itemEntered(QListWidgetItem *item)
  • void itemPressed(QListWidgetItem *item)
  • void itemClicked(QListWidget *item)
  • void itemDoubleClicked(QListWidgetItem *item)

每個繼承自QWidget的類都有customContexrMenuRequested()訊號,在一個元件上點選滑鼠右鍵時,元件發射這個訊號,用於請求建立快捷選單.

要是QWidget元件在點選滑鼠右鍵時發射customContextMenuRequested()訊號,還需要設定contextMenuPolicy屬性:

  • Qt::NoContextMenu:元件沒有快捷選單,由其父容器元件處理
  • Qt::PreventContextMenu:阻止快捷選單,並且點選滑鼠右鍵事件也不會交給父容器元件處理.
  • Qt::DefaultContextMenu:預設的快捷選單,QWidget::contextMenuEvent()事件被自動處理.
  • Qt::ActionsContextMenu:自動根據QWidget::actions()返回的Action列表建立並顯示快捷選單.
  • Qt::CustomContextMenu::元件發射customContextMenuRequested()訊號,由使用者程式設計實現快捷選單.

下面是一個綜合使用QToolButton和QListWidget的例子:

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(ui->actQuit,SIGNAL(triggered(bool)),this,SLOT(close()));

    ui->toolButton->setDefaultAction(ui->actInitList);
    ui->toolButton_2->setDefaultAction(ui->actDeleteList);
    ui->toolButton_3->setDefaultAction(ui->actAddItem);
    ui->toolButton_5->setDefaultAction(ui->actInsertItem);
    ui->toolButton_6->setDefaultAction(ui->actDeleteItem);

    ui->tbnSelAll_2->setDefaultAction(ui->actSelectAll);
    ui->tbnSelNone_2->setDefaultAction(ui->actSelectNone);
    ui->tbnSelInv_2->setDefaultAction(ui->actSelectInv);

    QMenu* menuSelection=new QMenu(this);
    menuSelection->addAction(ui->actSelectAll);
    menuSelection->addAction(ui->actSelectInv);
    menuSelection->addAction(ui->actSelectNone);

    ui->tbnSelItems->setPopupMode(QToolButton::MenuButtonPopup);
    ui->tbnSelItems->setMenu(menuSelection);
    ui->tbnSelItems->setDefaultAction(ui->actSelection);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_actInitList_triggered()
{
    ui->listWidget_2->clear();
    QIcon icon(QString(":/img/img/redo.jpg"));
    bool chk=ui->chkEditable_2->isChecked();
    for(int i=0;i<10;i++){
        QListWidgetItem* aItem= new QListWidgetItem();
        aItem->setIcon(icon);
        aItem->setText(QString("Item %1").arg(i));
        aItem->setCheckState(Qt::Checked);
        if(chk)
            aItem->setFlags(Qt::ItemIsEditable|Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled);
        else
            aItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled);
        ui->listWidget_2->addItem(aItem);
    }
}


void MainWindow::on_actDeleteList_triggered()
{
    ui->listWidget_2->clear();
}


void MainWindow::on_actAddItem_triggered()
{
    QIcon icon(QString(":/img/img/redo.jpg"));
    bool chk=ui->chkEditable_2->isChecked();
    QListWidgetItem* aItem= new QListWidgetItem();
    aItem->setIcon(icon);
    aItem->setText(QString("New Item"));
    aItem->setCheckState(Qt::Checked);
    if(chk)
        aItem->setFlags(Qt::ItemIsEditable|Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled);
    else
        aItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled);
    ui->listWidget_2->insertItem(ui->listWidget_2->currentRow(),aItem);
}


void MainWindow::on_actDeleteItem_triggered()
{
    int row= ui->listWidget_2->currentRow();
    delete ui->listWidget_2->takeItem(row);
}


void MainWindow::on_actInsertItem_triggered()
{
    QIcon icon(QString(":/img/img/redo.jpg"));
    bool chk=ui->chkEditable_2->isChecked();
    QListWidgetItem* aItem= new QListWidgetItem();
    aItem->setIcon(icon);
    aItem->setText(QString("New Item"));
    aItem->setCheckState(Qt::Checked);
    if(chk)
        aItem->setFlags(Qt::ItemIsEditable|Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled);
    else
        aItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled);
    ui->listWidget_2->addItem(aItem);
}



void MainWindow::on_listWidget_2_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
{
    QString str="";
    if(current!=NULL){
        str+="當前項:"+current->text();
        if(previous!=NULL)
            str+=" 前一項:"+previous->text();
        ui->litItemEdit_2->setText(str);
    }
    ui->plainTextEdit->appendPlainText(QString("currentChanged()訊號被髮射"));
}


void MainWindow::on_checkBox_clicked(bool checked)
{
    ui->listWidget_2->setSortingEnabled(checked);
    ui->toolButton_7->setEnabled(checked);
    ui->toolButton_8->setEnabled(checked);
}


void MainWindow::on_toolButton_7_clicked(bool checked)
{
    ui->listWidget_2->sortItems(Qt::AscendingOrder);
}


void MainWindow::on_toolButton_8_clicked(bool checked)
{
    ui->listWidget_2->sortItems(Qt::DescendingOrder);
}


void MainWindow::on_pushButton_clicked()
{
    ui->plainTextEdit->clear();
}


void MainWindow::on_pushButton_2_clicked()
{
    ui->plainTextEdit->appendPlainText(QString(""));
}


void MainWindow::on_listWidget_2_itemDoubleClicked(QListWidgetItem *item)
{
    ui->plainTextEdit->appendPlainText(QString("doubleClicked訊號發射")+item->text());
}


void MainWindow::on_listWidget_2_customContextMenuRequested(const QPoint &pos)
{
    Q_UNUSED(pos);
    QMenu* menuList= new QMenu(this);
    menuList->addAction(ui->actInitList);
    menuList->addAction(ui->actDeleteItem);
    menuList->addAction(ui->actDeleteList);
    menuList->addAction(ui->actInsertItem);
    menuList->addAction(ui->actAddItem);
    menuList->addSeparator();
    menuList->addAction(ui->actSelectAll);
    menuList->addAction(ui->actSelectNone);
    menuList->addAction(ui->actSelectInv);
    menuList->exec(QCursor::pos());
    delete menuList;
}


void MainWindow::on_actSelectAll_triggered()
{
    int cnt= ui->listWidget_2->count();
    for(int i=0;i<cnt;i++){
        QListWidgetItem *aItem=ui->listWidget_2->item(i);
        aItem->setCheckState(Qt::Checked);
    }
}


void MainWindow::on_actSelectNone_triggered()
{
    int cnt= ui->listWidget_2->count();
    for(int i=0;i<cnt;i++){
        QListWidgetItem *aItem=ui->listWidget_2->item(i);
        aItem->setCheckState(Qt::Unchecked);
    }
}


void MainWindow::on_actSelectInv_triggered()
{
    int cnt= ui->listWidget_2->count();
    for(int i=0;i<cnt;i++){
        QListWidgetItem *aItem=ui->listWidget_2->item(i);
        if(aItem->checkState()==Qt::Checked)
            aItem->setCheckState(Qt::Unchecked);
        else if(aItem->checkState()==Qt::Unchecked)
            aItem->setCheckState(Qt::Checked);
    }
}



QTreeWidget

QTreeWidget簡介

QTreeWidget是一種Item Widget元件.QTreeWidget元件被稱為樹形元件,它的項(item)被稱為節點,一個樹形元件內的所有節點組成的結構被稱為目錄樹.

樹形元件適合顯示具有層級結構的資料,例如,Windows資源管理器中顯示的檔案系統.

  • QTreeWidget樹形元件:例項使用樹形元件管理目錄與圖片檔案,可以新增或刪除節點.
  • QDockWidget停靠元件:QDockWidget是可以在視窗上停靠或桌面上層浮動的元件.
  • QLabel標籤元件:視窗右側是一個QScrollArea元件,在它上面放置一個標籤,為標籤設定一個QPixmap物件顯示圖片.透過QPixmap的介面函式可進行圖片縮放.

QDockWidget的主要屬性有:

  • floating屬性:表示停靠區元件是否處於浮動狀態.
  • features屬性:停靠區元件的特性.其為Qt::DockWidgetAreas列舉值的組合.
  • allowedAreas屬性:允許停靠的區域,可以設定在視窗左側,右側,頂部,底部停靠,也可以設定不允許停靠.
  • windowTitle屬性:停靠區視窗的標題.

一個QTreeWidget元件的顯示內容分為表頭和目錄樹兩部分,表頭和目錄樹都是QTreeWidgetItem物件.

QTreeWidget可以使用QTreeWidgetItem或簡單的文字作為表頭.

如果只是簡單地設定表頭文字,可以使用函式setHeaderLabels()將字串列表作為表頭各列的標題.

  • void QTreeWidget::setHeaderLabels(const QStringList &labels)

如果使用QTreeWidget作為表頭,則可以使用函式setHeaderItem()設計表頭,還可以使用headerItem()返回.

  • void QTreeWidget::setHeaderItem(QTreeWidgetItem *item)
  • QTreeWidgetItem *QTreeWidget::headerItem()

如果使用QTreeWidgetItem物件作為表頭,就可以透過QTreeWidgetItem的介面函式設定表頭屬性.

目錄樹裡一行就是一個節點,節點是QTreeWidgetItem物件.節點可以有直接點,子節點就是下一級的節點.

目錄樹裡最上層的節點稱為頂層節點,頂層節點沒有父節點.目錄樹裡可以有任意多個頂層節點.相關函式如下:

  • int topLevelItemCount()//返回頂層節點個數
  • void addTopLevelItem(QTreeWidgetItem *item)//新增一個頂層節點
  • void insertTopLevelItem(int index, QTreeWidgetItem *item)//插入一個頂層節點
  • int indexOfTopLevelItem(QTreeWidgetItem *item)//返回一個頂層節點的索引號
  • QTreeWidgetItem *topLevelItem(int index)//根據index返回一個頂層節點
  • QTreeWidgetItem *takeTopLevelItem(int index)//移除一個頂層節點,但是不刪除

獲得一個頂層節點後,就可以訪問它的所有子節點.所有次級節點都直接或間接掛靠在某個頂層節點下面.

目錄樹中還有一個隱藏的根節點,其可以看作所有頂層節點的父節點.透過invisibleRootItem()可以訪問它:

  • QTreeWidgetItem *QTreeWidget::invisibleRootItem().

使用這個結點就可以透過QTreeWidgetItem類的介面函式訪問所有頂層節點.

QTreeWidget也還有一些其他的常用函式:

  • int columnCount()//返回表頭列數
  • void setColumnCount(int columns)//設定表頭列數
  • void sortItems(int columns,Qt::SortOrder order)//將目錄樹按照某一列排序
  • int sortColumn()//返回用於排序的列的編號
  • QTreeWidgetItem *currentItem()//返回當前節點
  • QList<QTreeWidgetItem*> selectedItems()//返回選擇的節點列表

如果樹形元件允許多選,函式selectedItems()會返回選擇的節點的列表.透過QTreeWidget的上層父類QAbstractItemView的selectionMode屬效能夠設定選擇模式,可以設定為多選.

QTreeWidget有如下幾個共有槽函式:

  • void clear()//清除整個目錄樹
  • void collapseItem(const QTreeWidgetItem *item)//摺疊節點
  • void expandItem(const QTreeWidget *item)//展開節點
  • void scrollToItem(const QTreeWidget *item,QAbstractItemView::ScrollHint hint=EnsureVisible)
    //用於保證節點item可見,必要時自動移動卷滾條

QTreeWidget類有如下幾個訊號:

  • void currentItemChanged(QTreeWidgetItem *current,QTreeWidgetItem *previous)
    //當選中項變化時發射
  • void itemActivated(QTreeWidgetItem *item,int column)//雙擊節點或按下enter時
  • void itemChanged(QTreeWidgetItem *item,int column)//其中項改變
  • void itemClicked(QTreeWidgetItem *item,int column)//其中項被單擊或雙擊
  • void itemCollapsed(QTreeWidgetItem *item)//節點摺疊時
  • void itemDoubleClicked(QTreeWidgetItem *item,int column)//其中項被雙擊
  • void itemEntered(QTreeWidgetItem *item,int column)//滑鼠游標移動到節點上拖動時
  • void itemExpanded(QTreeWidgetItem *item)//節點展開時
  • void itemPressed(QTreeWidgetItem *item,int column)//使用者選中了項
  • void itemSelectionChanged()//使用者選擇的項改變

為了更好地理解,這裡需要對幾個訊號的發射條件進行區分:

currentItemChanged()訊號在當前節點發生變化時被髮射,current是當前節點,previous是之前節點.
itemChanged()訊號在某節點的某一列的屬性發生變化時被髮射.
itemClicked()訊號在點選節點時被髮射,不管當前節點的行和列有沒有變化都會觸發此訊號.
itemSelectionChanged()訊號在使用者選擇的節點發生變化時被髮射.

下面給出一個測試程式說明這些差異:

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    for(int i=0;i<10;i++){
        QTreeWidgetItem* new_item=new QTreeWidgetItem();
        new_item->setText(0,QString("編號"));
        new_item->setTextAlignment(0,Qt::AlignHCenter);
        new_item->setTextAlignment(0,Qt::AlignVCenter);
        new_item->setCheckState(0,Qt::Checked);
        new_item->setText(1,QString("姓名"));
        new_item->setTextAlignment(1,Qt::AlignHCenter);
        new_item->setTextAlignment(1,Qt::AlignVCenter);
        new_item->setCheckState(1,Qt::Checked);
        ui->treeWidget->addTopLevelItem(new_item);
    }
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_treeWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
{
    ui->plainTextEdit->appendPlainText(QString("currentItemChanged:%1").arg(ui->treeWidget->invisibleRootItem()->indexOfChild(current)));
    return;
}


void MainWindow::on_treeWidget_itemActivated(QTreeWidgetItem *item, int column)
{
    ui->plainTextEdit->appendPlainText(QString("itemActivated:%1").arg(ui->treeWidget->invisibleRootItem()->indexOfChild(item)));
    return;
}


void MainWindow::on_treeWidget_itemChanged(QTreeWidgetItem *item, int column)
{
    ui->plainTextEdit->appendPlainText(QString("itemChanged:%1").arg(ui->treeWidget->invisibleRootItem()->indexOfChild(item)));
    return;
}


void MainWindow::on_treeWidget_itemClicked(QTreeWidgetItem *item, int column)
{
    ui->plainTextEdit->appendPlainText(QString("itemClicked:%1").arg(ui->treeWidget->invisibleRootItem()->indexOfChild(item)));
    return;
}


void MainWindow::on_treeWidget_itemCollapsed(QTreeWidgetItem *item)
{
    ui->plainTextEdit->appendPlainText(QString("itemCollapsed:%1").arg(ui->treeWidget->invisibleRootItem()->indexOfChild(item)));
    return;
}


void MainWindow::on_treeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column)
{
    ui->plainTextEdit->appendPlainText(QString("itemDoubleClicked:%1").arg(ui->treeWidget->invisibleRootItem()->indexOfChild(item)));
    return;
}


void MainWindow::on_treeWidget_itemEntered(QTreeWidgetItem *item, int column)
{
    ui->plainTextEdit->appendPlainText(QString("itemEntered:%1").arg(ui->treeWidget->invisibleRootItem()->indexOfChild(item)));
    return;
}


void MainWindow::on_treeWidget_itemExpanded(QTreeWidgetItem *item)
{
    ui->plainTextEdit->appendPlainText(QString("itemExpanded:%1").arg(ui->treeWidget->invisibleRootItem()->indexOfChild(item)));
    return;
}


void MainWindow::on_treeWidget_itemPressed(QTreeWidgetItem *item, int column)
{
    ui->plainTextEdit->appendPlainText(QString("itemPressed:%1").arg(ui->treeWidget->invisibleRootItem()->indexOfChild(item)));
    return;
}


void MainWindow::on_treeWidget_itemSelectionChanged()
{
    ui->plainTextEdit->appendPlainText(QString("itemSelectionChanged"));
    return;
}

QTreeWidgetItem簡介

QTreeWidget元件的表頭和目錄樹節點都是QTreeWidgetItem類物件,對目錄樹節點的操作主要透過QTreeWidgetItem類的介面函式實現.

QTreeWidgetItem類沒有父類,它只用來儲存結點的資料和各種屬性.繪製目錄樹由QTreeWidget實現.

QTreeWidgetItem類有多種引數形式的建構函式,較簡單的一種定義如下:

  • QTreeWidgetItem(int type=Type)

可以傳遞一個整數表示結點的型別,可以透過成員函式type()返回這個型別.

在建立節點時,還可以傳遞字串列表作為節點各列的文字:

  • QTreeWidgetItem(const QStringList &strings,int type=Type)

也可以在某個節點下建立子節點:

  • QTreeWidgetItem(QTreeWidgetItem *parent,int type=Type)

還可以直接在樹形元件裡建立頂層節點:

  • QTreeWidgetItem(QTreeWidget *parent,int type=Type)

建立一個節點後,可以透過一些函式對其進行操作:

  • void setBackground(int column,const QBrush &brush)
  • void setForeground(int column,const QBrush &brush)
  • void setText(int column,const QString &text)
  • void setTextAlignment(int column,const QString &toolTip)
  • void setStatusTip(int column,const QString &statusTip)
  • void setIcon(int column,const QIcon &icon)
  • void setCheckState(int column,Qt::CheckState state)
  • void setFont(int column,const QFont &font)

Qt::Alignment的取值有:

  • Qt::AlignLeft:水平方向靠左
  • Qt::AlignRight:水平方向靠右
  • Qt::AlignTop:垂直方向靠頂部
  • Qt::AlignButton:垂直方向靠底部
  • Qt::AlignHCenter:水平方向居中
  • Qt::AlignVCenter:垂直方向居中
  • Qt::AlignCenter:水平垂直方向居中
  • Qt::AlignJustify:水平方向調整間距兩端對齊

上面設定函式當然有相應的讀取函式,同樣需要傳遞引數column.

QTreeWidgetItem還有一個函式setData()用於為節點中的某一列設定使用者資料,這個資料是不顯示在介面上的.

  • void setData(int column,int role,const QVariant &value)
  • QVariant data(int column,int role)

引數role是使用者資料角色,可以使用常量Qt::UserRole定義第一個使用者資料,使用Qt::UserRole+1定義第二個使用者資料.

使用者資料是QVariant型別,可以儲存各種型別的資料.

QTreeWidgetItem的一些常用的介面函式有:

  • int type()//返回建立節點時設定的type
  • setFlags(Qt::ItemFlags flags)//設定結點的標誌
  • Qt::ItemFlags flags()//讀取節點的標誌
  • void setExpanded(bool expand)
  • bool isExpanded()
  • void setDisabled(bool disabled)
  • bool isDisabled()
  • void setHidden(bool hide)
  • bool isHidden()
  • void setSelected(bool select)
  • bool isSelected()

注意,函式type()所返回的是建立節點時傳遞的type引數,節點建立後就不能更改.

Qt::ItemFlags的取值有:

  • Qt::NoItemFlags//沒有標誌
  • Qt::ItemIsSelectable//節點可以被選中
  • Qt::ItemIsEditable//節點可以編輯
  • Qt::ItemIsDragEnabled//節點可以被拖動
  • Qt::ItemIsDropEnabled//節點可以接收被拖動的物件
  • Qt::ItemIsUserCheckable//節點可以被複選
  • Qt::ItemIsEnabled//節點可用
  • Qt::ItemIsAutoTristate//自動決定三種複選狀態
  • Qt::ItemIsUserTristate//使用者決定三種複選狀態
  • Qt::ItemNeverHasChildren//不允許有子節點

而且這些節點可以用|組合.

一個節點可以有任意多個子節點,可以新增,插入或移除節點.

QTreeWidgetItem類中用於操作子節點的介面函式主要有以下幾個:

  • void addChild(QTreeWidgetItem *child)//新增一個子節點
  • QTreeWidgetItem *child(int index)//根據序號返回一個子節點
  • int childCount()//返回子節點的個數
  • int indexOfChild(QTreeWidgetItem *child)//返回一個子節點的索引號
  • void insertChild(int index,QTreeWidgetItem *child)//插入一個子節點
  • void removeChile(QTreeWidget *child)//移除一個子節點
  • QTreeWidgetItem *takeChild(int index)//移除一個子節點,並返回節點指標
  • QTreeWidgetItem *parent()//返回父節點

QLabel和Qpixmap的使用

對於QPixmap類變數,QPixamp::load()直接從一個檔案載入圖片.

QPixmap類儲存圖片資料,它有以下幾個函式可以用於縮放圖片:

  • scaledToHeight(int height):返回一個縮放後的圖片副本,圖片按height縮放
  • scaledToWidth(int width):返回一個縮放後的圖片副本,圖片按width縮放
  • scaled(int width,int height):返回一個縮放後的圖片副本,預設不保持比例

設定圖片到標籤的,函式原型為:void QLabel::setPixmap(const QPixmap&)

將標籤放在一個QScrollArea元件上,當圖片過大時,QScrollArea將會出現卷滾條.

QDockWidget的操作

程式執行時,視窗上的QDockWidget元件可以被拖動.

QDockWidget類有如下幾個訊號:

  • void allowedAreasChanged(Qt::DockWidgetAreas allowedAreas)//allowedAreas屬性值變化時
  • void dockLocationChanged(Qt::DockWidgetArea area)//移動到其他停靠區時
  • void featuresChanged(QDockWidget::DockWidgetFeatures features)//features屬性變化時
  • void topLevelChanged(bool topLevel)//floating屬性值變化時
  • void visiblityChanged(bool visible)//visible屬性值變化時

下面最終給出綜合使用QTreeWidget與QPixmap的例子:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QLabel>
#include <QSpinBox>
#include <QTreeWidgetItem>

QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void changeItemCaption(QTreeWidgetItem *item);

    void displayImage(QTreeWidgetItem* item);

    void on_actAddFolder_triggered();

    void on_actAddFile_triggered();

    void on_actDeleteNode_triggered();

    void on_treeWidget_2_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);

    void on_actForeachNode_triggered();

    void on_actSuitWidth_triggered();

    void on_actSuitHeight_triggered();

    void on_actReal_triggered();

    void on_actBigger_triggered();

    void on_actSmaller_triggered();

    void on_actVisiable_triggered(bool checked);

    void on_actFloating_triggered(bool checked);

private:
    QLabel *lbFileName,*lbNodeText;
    QSpinBox *spinRadio;
    QPixmap m_pixmap;
    float radio;

    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

mainindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->treeWidget_2->clear();

    //header
    QTreeWidgetItem *header=new QTreeWidgetItem();
    header->setText(0,"目錄與檔案");
    header->setText(1,"節點型別");
    header->setText(2,"最後修改日期");

    header->setTextAlignment(0,Qt::AlignHCenter|Qt::AlignVCenter);
    header->setTextAlignment(1,Qt::AlignHCenter|Qt::AlignVCenter);

    ui->treeWidget_2->setHeaderItem(header);

    //root node
    QIcon icon(QString(":/icons/img/close.jpg"));
    QTreeWidgetItem *topItem= new QTreeWidgetItem();
    topItem->setIcon(0,icon);
    topItem->setText(0,"/...");
    topItem->setText(1,"根目錄");
    topItem->setText(2,"");
    topItem->setFlags(Qt::ItemIsSelectable|
        Qt::ItemIsUserCheckable|
        Qt::ItemIsEnabled|
        Qt::ItemIsAutoTristate
    );
    topItem->setCheckState(0,Qt::Checked);
    ui->treeWidget_2->addTopLevelItem(topItem);

    //status bar
    lbNodeText= new QLabel("節點標題",this);
    lbNodeText->setMinimumWidth(200);
    ui->statusbar->addWidget(lbNodeText);

    spinRadio=new QSpinBox(this);
    spinRadio->setRange(0,2000);
    spinRadio->setValue(100);
    spinRadio->setSuffix("%");
    spinRadio->setReadOnly(true);
    spinRadio->setButtonSymbols(QAbstractSpinBox::NoButtons);
    ui->statusbar->addPermanentWidget(spinRadio);

    lbFileName=new QLabel("檔名",this);
    ui->statusbar->addPermanentWidget(lbFileName);
}


MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::changeItemCaption(QTreeWidgetItem *item)
{
    QString str="*"+item->text(0);
    item->setText(0,str);
    if(item->childCount()>0)
        for(int i=0;i<item->childCount();i++)
            changeItemCaption(item->child(i));
    else
        return;
}

void MainWindow::displayImage(QTreeWidgetItem *item)
{
    QString filename=item->data(0,Qt::UserRole).toString();
    lbFileName->setText(filename);
    lbNodeText->setText(item->text(0));
    m_pixmap.load(filename);
    ui->actSuitWidth->trigger();

    ui->actSuitHeight->setEnabled(true);
    ui->actSuitWidth->setEnabled(true);
    ui->actBigger->setEnabled(true);
    ui->actSmaller->setEnabled(true);
    ui->actReal->setEnabled(true);
}

#include <QFileDialog>
#include <QVariant>
void MainWindow::on_actAddFolder_triggered()
{
    QString dir= QFileDialog::getExistingDirectory();
    if(dir.isEmpty())
        return;
    QTreeWidgetItem *parItem=ui->treeWidget_2->currentItem();
    if(parItem==nullptr)
        return;
    if(parItem->text(1)!="圖片"){
        int cnt=dir.length();
        int i=dir.lastIndexOf("/");
        QString nodeName=dir.right(cnt-i-1);
        QTreeWidgetItem *item=new QTreeWidgetItem();
        QIcon icon(QString(":/icons/img/close.jpg"));
        item->setIcon(0,icon);
        item->setText(0,nodeName);
        item->setText(1,"目錄");
        item->setText(2,"");
        item->setFlags(Qt::ItemIsSelectable|
            Qt::ItemIsUserCheckable|
            Qt::ItemIsEnabled|
            Qt::ItemIsAutoTristate
        );
        item->setData(0,Qt::UserRole,QVariant(dir));
        item->setCheckState(0,Qt::Checked);
        parItem->addChild(item);
    }
}


void MainWindow::on_actAddFile_triggered()
{
    QStringList files=QFileDialog::getOpenFileNames(this,"選擇檔案","","Images(*.jpg;*.png)");
    if(files.isEmpty())
        return;

    QTreeWidgetItem *parItem,*item;
    item=ui->treeWidget_2->currentItem();

    if(item->text(1)!="圖片")
        parItem=item;
    else
        parItem=item->parent();

    for(int i=0;i<files.size();i++){
        QString fileName= files.at(i);
        QFileInfo fileInfo(fileName);
        QString nodeText=fileInfo.fileName();
        QDateTime dateTime=fileInfo.lastModified();
        QTreeWidgetItem *item=new QTreeWidgetItem();
        QIcon icon(fileInfo.filePath());
        item->setIcon(0,icon);
        item->setText(0,nodeText);
        item->setText(1,"圖片");
        item->setText(2,dateTime.toString("yyyy-MM-dd"));
        item->setFlags(Qt::ItemIsSelectable|
                       Qt::ItemIsUserCheckable|
                       Qt::ItemIsEnabled|
                       Qt::ItemIsAutoTristate
                       );
        item->setData(0,Qt::UserRole,QVariant(fileName));
        item->setCheckState(0,Qt::Checked);
        parItem->addChild(item);
    }
    parItem->setExpanded(true);
}


void MainWindow::on_actDeleteNode_triggered()
{
    QTreeWidgetItem *item,*parItem;
    item=ui->treeWidget_2->currentItem();
    parItem=item->parent();

    if(item!=nullptr){
        parItem->removeChild(item);
        delete item;
    }
    else
        return;
}


void MainWindow::on_treeWidget_2_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
{
    if(current==nullptr||current==previous)
        return;

    QString itemType=current->text(1);
    if(itemType=="根目錄"){
        ui->actAddFile->setEnabled(true);
        ui->actAddFolder->setEnabled(true);
        ui->actDeleteNode->setEnabled(false);
    }
    else if(itemType=="目錄"){
        ui->actAddFile->setEnabled(true);
        ui->actAddFolder->setEnabled(true);
        ui->actDeleteNode->setEnabled(true);
    }
    else if(itemType=="圖片"){
        ui->actAddFile->setEnabled(false);
        ui->actAddFolder->setEnabled(true);
        ui->actDeleteNode->setEnabled(true);
        displayImage(current);
    }
}


void MainWindow::on_actForeachNode_triggered()
{
    QTreeWidgetItem *item,*parItem;
    item=ui->treeWidget_2->currentItem();
    changeItemCaption(item);
}


void MainWindow::on_actSuitWidth_triggered()
{
    int width=ui->scrollArea->width()-30;
    int realWidth=m_pixmap.width();
    radio=float(width)/realWidth;

    spinRadio->setValue(radio*100);
    QPixmap pix=m_pixmap.scaledToWidth(width);
    ui->label->setPixmap(pix);
}


void MainWindow::on_actSuitHeight_triggered()
{
    int height=ui->scrollArea->height()-30;
    int realHeight=m_pixmap.height();
    radio=float(height)/realHeight;

    spinRadio->setValue(radio*100);
    QPixmap pix=m_pixmap.scaledToHeight(height);
    ui->label->setPixmap(pix);
}


void MainWindow::on_actReal_triggered()
{
    int height=ui->scrollArea->height()-30;
    int realHeight=m_pixmap.height();
    radio=float(height)/realHeight;

    spinRadio->setValue(radio*100);
    QPixmap pix=m_pixmap.scaledToHeight(realHeight);
    ui->label->setPixmap(pix);
}


void MainWindow::on_actBigger_triggered()
{
    radio*=1.2;
    int width=radio*m_pixmap.width();
    int height=radio*m_pixmap.height();
    ui->label->setPixmap(m_pixmap.scaled(width,height));
    spinRadio->setValue(radio*100);
}


void MainWindow::on_actSmaller_triggered()
{
    radio*=0.8;
    int width=radio*m_pixmap.width();
    int height=radio*m_pixmap.height();
    ui->label->setPixmap(m_pixmap.scaled(width,height));
    spinRadio->setValue(radio*100);
}


void MainWindow::on_actVisiable_triggered(bool checked)
{
    ui->dockWidget_2->setVisible(checked);
}


void MainWindow::on_actFloating_triggered(bool checked)
{
    ui->dockWidget_2->setFloating(checked);
}



QTableWidget

QTableWidget是QTableView的便利類,類QTableWidget的屬性和介面主要是父類中定義的.

QTableWidget還新增了兩個屬性,rowCount表示資料區行數,columnCount表示資料區列數.

QTableWidget還定義瞭如下的幾個公有槽函式:

  • void insertColumn(int column)//在列號column處插入空行
  • void removeColumn(int column)//移除列號column的一列
  • void insertRow(int row)//在行號row處插入空行
  • void removeRow(int row)//移除行號row的一行

QTableWidget表格的一個單元格通常關聯一個QTableWidgetItem物件.

要為表格的一個單元格設定項,一般是先建立一個QTableWidgetItem物件item,設定各種屬性,然後透過setItem()將其設定至某個單元格.其函式原型如下:

  • void setItem(int row,int column,QTableWidgetItem *item)

要移除一個單元格關聯的項,可以使用含稅takeItem()來實現,其函式原型如下:

  • QTableWidgetItem *takeItem(int row,int column)

函式takeItem會移除單元格關聯的項,並返回這個項的物件指標,但是不刪除這個物件.

QTableWidget定義了兩個公有槽:

  • void clear()
  • void clearContents()

QTableWidget表格資料區有一個當前單元格,也就是獲得輸入焦點的單元格.相關函式如下:

當前單元格關聯的QTableWidgetItem物件就是當前項,可以返回當前項的物件指標.也可以設定某個QTableWidgetItem物件為當前項,以改變當前單元格的位置.

  • int currentRow()//返回當前單元格的行號
  • int currentColumn()//返回當前單元格的列號
  • void setCurrentCell(int row,int column)//透過行號和列號設定當前單元格位置
  • QTableWidgetItem *currentItem()//返回當前項
  • void setCurrentItem(QTableWidgetItem *item)//設定當前項,改變當前單元格位置
  • QTableWidgetItem *item(int row,int column)//透過行號和列號返回項
  • int row(const QTableWidgetItem *item)//返回一個項的行號
  • int column(const QTableWidgetItem *item)//返回一個項的列號
  • void setHorizontalHeaderItem(int column)//為某列設定項
  • QTableWidgetItem *horizontalHeaderItem(int column)//返回column列的表頭項
  • QTableWidgetItem *takeHorizontalHeaderItem(int column)//移除column列的表頭項
  • void setHorizontalHeaderLabels(const QStringList &labels)
    //使用字串列表的每一行作為水平表頭每一列的標題
  • setVerticalHeaderItem(int row,QTableWidgetItem *item)//設定row的表頭項
  • QTableWidgetItem *verticalHeaderItem(int row)//返回row的表頭項
  • QTableWidgetItem *takeVerticalHeaderItem(int row)//移除row的表頭項
  • void setVerticalHeaderLabels(const QStringList &labels)//用一個字串列表設定表頭標題

QTableWidget定義了較多的訊號:

  • void cellActivated(int row,int column)//單元格被啟用時
  • void cellChanged(int row,int column)//單元格的資料改變時
  • void cellClicked(int row,int column)//在單元格上單擊滑鼠時
  • void cellDoubleClicked(int row,int column)//在單元格上雙擊滑鼠時
  • void cellEntered(int row,int column)//滑鼠移動到一個單元格上時
  • void cellPressed(int row,int column)//在單元格上按下滑鼠左鍵或右鍵時
  • void currentCellChanged(int currentRow,int currentColumn,int previousRow,int previousColumn)
    //當前單元格發生切換時
  • void itemActivated(QTableWidgetItem *item)//項被啟用時
  • void itemChanged(QTableWidgetItem *item)//項內容改變時
  • void itemClicked(QTableWidgetItem *item)//項被點選
  • void itemDoubleClicked(QTableWidgetItem *item)//項被雙擊
  • void itemEntered(QTableWidgetItem *item)//滑鼠移動到一個項上時
  • void itemPressed(QTableWidgetItem *item)//在項上按下滑鼠左鍵或右鍵時
  • void currentItemChanged(QTableWidgetItem *current,QTableWidgetItem *previous)
    //當前項發生改變時
  • void itemSelectionChanged()//選擇的項發生變化時

QTableWidgeItem關聯的每個單元格都需要關聯一個QTableWidgetItem物件.

QTableWidgetItem有多種引數形式的建構函式,其中的三種建構函式定義如下:

  • QTableWidgetItem(const QIcon &icon,const QString &text,int type=Type)
  • QTableWidgetItem(const QString &text,int type=Type)
  • QTableWidgetItem(int type=Type)

建立QTableWidgetItem物件後,透過QTableWidget::setItem()函式可以將其設定為某個單元格的項.

QTableWidgetItem物件有一些介面函式用於設定項的特性:

  • void setText(const QString &text)//設定單元格顯示文字
  • void setTextAlignment(int alignment)//設定文字對其方式
  • void setBackground(const QBrush &brush)//設定背景色
  • void setForeground(const QBrush &brush)//設定前景色
  • void setFont(const QFont &font)//設定字型
  • void setIcon(const QIcon &icon)//設定圖示
  • void setCheckState(Qt::CheckState state)//設定複選狀態
  • void setToolTip(const QString &toolTip)//設定toolTip
  • void setStatusTip(const QString &statusTip)//設定statusTip
  • void setFlags(Qt::ItemFlags flags)//設定標誌
  • void setData(int role,const QVariant &value)//設定資料
  • int row()//返回項所在單元格行號
  • int column()//返回項所在單元格的列號
  • void setSelected(bool select)//設定項的選中狀態
  • bool isSelected()//項是否被選中
  • QTableWidget *tableWidget()//返回項所在的QTableWidget物件指標

後記:好長的一章,一章更比四章強( )

相關文章