學習QT的小練習,先看一下目前實現的效果。
功能:
- 編輯文本保存為txt。
- 打開一個txt文本文件,可編輯可保存。
- 文本編輯功能:剪切,復制,粘貼,加粗,斜體,下划線,設置顏色,字體。
要點:
- QT Designer的UI可視化設計:基本控件布局,資源導入,菜單&動作,信號&槽的配置;
- QT信號和槽的機制:可視化配置以及代碼手動連接,實現槽函數;
- plainTextEdit控件相關:展示文本,設置文本格式,顏色等;
- 文件對話框:讀寫文件,打開和保存功能;
- QT常用快捷鍵:F4在源文件和頭文件之間切換,右擊菜單refactor轉到定義等;
1. UI布局設計
整體界面布局如下。
設計思路:
新建mainWindow窗體,自帶菜單欄,工具欄和狀態欄。
(1)菜單欄。依次添加需要的菜單。
(2)工具欄。每個小塊為一個動作(action),新建動作后添加到對應菜單。
(3)字體大小用spinBox控件(QSpinBox類),字體設置用FontComboBox控件(QFontComboBox類)。不能直接在可視化設計里拖到工具欄,只能通過代碼的方式添加。
(4)編輯區。用一個plainTextEdit控件即可。
(5)狀態欄。拖一個Qlabel控件進去顯示當前正在編輯的文件。
2. 添加資源文件
新建一個資源文件。
隨便起個名字,添加到當前工程里面。
在新建的資源文件里添加前綴,然后就可以把所有資源文件(圖標)導入進來。
3. 添加菜單(menu)和動作(action)
可視化設計界面里逐個添加菜單和動作。action的屬性如下,可以設置快捷鍵,如果把checkable勾上,那action按下就不會彈起,像開關一樣(比如加粗,斜體,下划線這三個按鈕)。
每個aciton默認的風格是只顯示圖標,可以更改下面的屬性讓文字顯示在下方。
4.添加spinBox控件和FontComboBox控件
這兩個控件是分別用於設置字體大小和字體的,沒法直接拖到工具欄里,需要在代碼里實現。最底下顯示當前文件的label也同理,用addWidget方法添加到工具欄和狀態欄。
void MainWindow::initUI()
{
//設置字體大小控件
spinFontSize = new QSpinBox();
spinFontSize->setMinimum(5); //最小值5
spinFontSize->setMaximum(50); //最大值50
ui->mainToolBar->addWidget(new QLabel("字體大小:")); //先添加一個label提示
ui->mainToolBar->addWidget(spinFontSize); //添加到工具欄
//設置字體控件
comboFont = new QFontComboBox();
ui->mainToolBar->addWidget(new QLabel("字體:"));
ui->mainToolBar->addWidget(comboFont);
//當前文件控件
currentFile = new QLabel();
currentFile->setText("當前文件:"); //設置文本
ui->statusBar->addWidget(currentFile); //添加到狀態欄
}
5. 實現清空、剪切、復制、粘貼功能
這四個功能很簡單,在信號/槽窗口里直接編輯。plainTextEdit自帶的槽函數可以直接實現這些功能,把信號和槽配置好。
6. 實現粗體、斜體、下划線功能
代碼實現。在可視化界面里右擊動作,轉到slot,編寫槽函數,選擇帶bool參數的。使用QTextCharFormat
設置字體格式,該bool參數會被傳遞到其方法。
實現字體加粗:
void MainWindow::on_actionBold_triggered(bool checked)
{
QTextCharFormat fmt;
if(checked)
fmt.setFontWeight(QFont::Bold);
else
fmt.setFontWeight(QFont::Normal);
ui->plainTextEdit->mergeCurrentCharFormat(fmt);
}
調用plainTextEdit的mergeCurrentCharFormat()
方法融合字體設置。
同理,斜體實現:
void MainWindow::on_actionItalic_triggered(bool checked)
{
QTextCharFormat fmt;
fmt.setFontItalic(checked);
ui->plainTextEdit->mergeCurrentCharFormat(fmt);
}
下划線實現:
void MainWindow::on_actionUnderline_triggered(bool checked)
{
QTextCharFormat fmt;
fmt.setFontUnderline(checked);
ui->plainTextEdit->mergeCurrentCharFormat(fmt);
}
7.實現字體大小和樣式設置
設置字體大小使用spinBox控件,字體樣式用fontComboBox控件,兩個控件都是自己用代碼實現的,所以要自己實現一下槽函數以及配置好信號和槽的連接。
把信號和槽的函數寫到initConnections()里,和initUI()一樣一起初始化。
void MainWindow::initConnections()
{
//連接字體spinBox
connect(spinFontSize,SIGNAL(valueChanged(int)),this,SLOT(on_spinFontSize_valueChanged(int)));
//連接字體comboBox
connect(comboFont,SIGNAL(currentIndexChanged(const QString &)),this,SLOT(on_comboFont_currentIndexChanged(const QString &)));
}
設置字體大小槽函數,調用setFontPointSize()
方法:
void MainWindow::on_spinFontSize_valueChanged(int aFontsize)
{
QTextCharFormat fmt;
fmt.setFontPointSize(aFontsize);
ui->plainTextEdit->mergeCurrentCharFormat(fmt);
}
設置字體樣式槽函數,調用setFontFamily()
方法:
void MainWindow::on_comboFont_currentIndexChanged(const QString &text)
{
QTextCharFormat fmt;
fmt.setFontFamily(text);
ui->plainTextEdit->mergeCurrentCharFormat(fmt);
}
8.實現字體顏色設置
plainTextEdit控件的palette()
方法可以拿到一個調色板對象,用調色板可以獲取和設置顏色,然后再調用setPalette()
方法應用到plainTextEdit控件,但這樣會把整個文本的顏色改變。
我想只把選中的文字顏色改變,可以參考上面類似的實現,用QTextCharFormat
的setForeground()
方法設置字體顏色,然后合並過去。
槽函數:
void MainWindow::on_actionColor_triggered()
{
QPalette pal = ui->plainTextEdit->palette();
QColor iniColor = pal.color(QPalette::Text);
QColor color = QColorDialog::getColor(iniColor,this,"選擇顏色");
if(!color.isValid())
return;
//pal.setColor(QPalette::Text,color);
QTextCharFormat fmt;
fmt.setForeground(color); //設置字體顏色
ui->plainTextEdit->mergeCurrentCharFormat(fmt);
//ui->plainTextEdit->setPalette(pal);
}
9.實現打開和保存文件
使用QFileDialog
的getOpenFileName()
方法,會彈出文件選擇對話框,讓用戶選擇一個文件。
這里設置4個參數:
- 父對象
- 對話框標題
- 當前路徑(打開窗口時顯示的路徑)
- 過濾器
調用QDir::currentPath()
方法可以拿到項目當前路徑。
過濾器我只寫文本文件,如果想再添加其它格式文件,用雙分號隔開,舉例:QString filter = "文本文件(*.txt);;其它文件(*.*)"
獲取到文件名后,在最下方的label上顯示當前處理的文件。
初始化一個QFile對象,調用file.open(QIODevice::ReadWrite)
方法按可讀可寫方式打開文件。調用readAll()
方法讀取到所有文本填充到plainTextEdit控件中。
打開文件的槽函數:
void MainWindow::on_actionOpen_triggered()
{
QString curPath = QDir::currentPath();
QString filter = "文本文件(*.txt)";
QString fileName = QFileDialog::getOpenFileName(this,"打開文本文件",curPath,filter);
if(fileName.isEmpty())
return;
QString curFileName = "當前文件:" + fileName;
currentFile->setText(curFileName);
QFile file(fileName);
if(file.open(QIODevice::ReadWrite)){
ui->plainTextEdit->setPlainText(file.readAll());
file.close();
}
}
保存文件類似,用getSaveFileName()
方法,得到文件名后,初始化QFile對象寫文件。注意下面的寫方法。
保存文件的槽函數:
void MainWindow::on_actionSave_triggered()
{
QString curPath = QDir::currentPath();
QString filter = "文本文件(*.txt)";
QString fileName = QFileDialog::getSaveFileName(this,"另存為",curPath,filter);
if(fileName.isEmpty())
return;
QFile file(fileName);
if(file.open(QIODevice::WriteOnly)){
QString content = ui->plainTextEdit->toPlainText();
QByteArray strBytes = content.toUtf8();
file.write(strBytes,strBytes.length());
}
}
10.總結
很簡單的小項目,只是熟悉QT的入門知識,但是基於上述要點的理解,知道怎么可視化布局,導入資源文件,編寫信號和槽,自定義數據結構,已經能寫一些簡單的小程序了,下面想要做出更酷炫的界面,只要針對控件去學習就行。
完整的mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QSpinBox>
#include <QFontComboBox>
#include <QLabel>
#include <QColorDialog>
#include <QFileDialog>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_actionBold_triggered(bool checked);
void on_plainTextEdit_copyAvailable(bool b);
void on_spinFontSize_valueChanged(int aFontsize);
void on_comboFont_currentIndexChanged(const QString &text);
void on_actionItalic_triggered(bool checked);
void on_actionUnderline_triggered(bool checked);
void on_actionColor_triggered();
void on_actionOpen_triggered();
void on_actionSave_triggered();
private:
Ui::MainWindow *ui;
QSpinBox *spinFontSize;
QFontComboBox *comboFont;
QLabel *currentFile;
void initUI();
void initConnections();
};
#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);
setWindowTitle("簡易文本編輯器");
initUI();
initConnections();
setCentralWidget(ui->plainTextEdit);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::initUI()
{
//設置字體大小控件
spinFontSize = new QSpinBox();
spinFontSize->setMinimum(5); //最小值5
spinFontSize->setMaximum(50); //最大值50
ui->mainToolBar->addWidget(new QLabel("字體大小:")); //先添加一個label提示
ui->mainToolBar->addWidget(spinFontSize); //添加到工具欄
//設置字體控件
comboFont = new QFontComboBox();
ui->mainToolBar->addWidget(new QLabel("字體:"));
ui->mainToolBar->addWidget(comboFont);
//當前文件控件
currentFile = new QLabel();
currentFile->setText("當前文件:"); //設置文本
ui->statusBar->addWidget(currentFile); //添加到狀態欄
}
void MainWindow::initConnections()
{
//連接字體spinBox
connect(spinFontSize,SIGNAL(valueChanged(int)),this,SLOT(on_spinFontSize_valueChanged(int)));
//連接字體comboBox
connect(comboFont,SIGNAL(currentIndexChanged(const QString &)),this,SLOT(on_comboFont_currentIndexChanged(const QString &)));
}
void MainWindow::on_actionBold_triggered(bool checked)
{
QTextCharFormat fmt;
if(checked)
fmt.setFontWeight(QFont::Bold);
else
fmt.setFontWeight(QFont::Normal);
ui->plainTextEdit->mergeCurrentCharFormat(fmt);
}
void MainWindow::on_plainTextEdit_copyAvailable(bool b)
{
ui->actionCut->setEnabled(b);
ui->actionCopy->setEnabled(b);
ui->actionPaste->setEnabled(ui->plainTextEdit->canPaste());
}
void MainWindow::on_spinFontSize_valueChanged(int aFontsize)
{
QTextCharFormat fmt;
fmt.setFontPointSize(aFontsize);
ui->plainTextEdit->mergeCurrentCharFormat(fmt);
}
void MainWindow::on_comboFont_currentIndexChanged(const QString &text)
{
QTextCharFormat fmt;
fmt.setFontFamily(text);
ui->plainTextEdit->mergeCurrentCharFormat(fmt);
}
void MainWindow::on_actionItalic_triggered(bool checked)
{
QTextCharFormat fmt;
fmt.setFontItalic(checked);
ui->plainTextEdit->mergeCurrentCharFormat(fmt);
}
void MainWindow::on_actionUnderline_triggered(bool checked)
{
QTextCharFormat fmt;
fmt.setFontUnderline(checked);
ui->plainTextEdit->mergeCurrentCharFormat(fmt);
}
void MainWindow::on_actionColor_triggered()
{
QPalette pal = ui->plainTextEdit->palette();
QColor iniColor = pal.color(QPalette::Text);
QColor color = QColorDialog::getColor(iniColor,this,"選擇顏色");
if(!color.isValid())
return;
//pal.setColor(QPalette::Text,color);
QTextCharFormat fmt;
fmt.setForeground(color); //設置字體顏色
ui->plainTextEdit->mergeCurrentCharFormat(fmt);
//ui->plainTextEdit->setPalette(pal);
}
void MainWindow::on_actionOpen_triggered()
{
QString curPath = QDir::currentPath();
QString filter = "文本文件(*.txt)";
QString fileName = QFileDialog::getOpenFileName(this,"打開文本文件",curPath,filter);
if(fileName.isEmpty())
return;
QString curFileName = "當前文件:" + fileName;
currentFile->setText(curFileName);
QFile file(fileName);
if(file.open(QIODevice::ReadWrite)){
ui->plainTextEdit->setPlainText(file.readAll());
file.close();
}
}
void MainWindow::on_actionSave_triggered()
{
QString curPath = QDir::currentPath();
QString filter = "文本文件(*.txt)";
QString fileName = QFileDialog::getSaveFileName(this,"另存為",curPath,filter);
if(fileName.isEmpty())
return;
QFile file(fileName);
if(file.open(QIODevice::WriteOnly)){
QString content = ui->plainTextEdit->toPlainText();
QByteArray strBytes = content.toUtf8();
file.write(strBytes,strBytes.length());
}
}