這裏通過一個文本編輯器的應用實例來介紹QMainWindow主窗體的各種功能的開發。
1 基本元素
QMainWindow是一個爲用戶提供主窗口程序的類,包含一個菜單欄(menu bar)、多個工具欄(tool bars)、多個錨接部件(dock widgets)、一個狀態欄(status bar)及一箇中心部件(central widget),是許多應用程序的基礎,如文本編輯器、圖片編輯器等。
2 Qt5文件操作功能
2.1 新建文件
實現新建文件功能的函數ShowNewFile()如下:
void ImgProcessor::ShowNewFile()
{
ImgProcessor *newImgProcessor =new ImgProcessor;
newImgProcessor->show();
}
2.2 打開文件
實現打開文件功能的函數ShowOpenFile()如下:
void ImgProcessor::ShowOpenFile()
{
fileName = QFileDialog::getOpenFileName(this);
if(!fileName.isEmpty())
{
if(showWidget->text->document()->isEmpty())
{
loadFile(fileName);
}
else
{
ImgProcessor *newImgProcessor =new ImgProcessor;
newImgProcessor->show();
newImgProcessor->loadFile(fileName);
}
}
}
其中,loadFile()函數的實現如下,該函數利用QFile和QTextStream完成具體讀取文件內容的工作:
void ImgProcessor::loadFile(QString filename)
{
printf("file name:%s\n",filename.data());
QFile file(filename);
if(file.open(QIODevice::ReadOnly|QIODevice::Text))
{
QTextStream textStream(&file);
while(!textStream.atEnd())
{
showWidget->text->append(textStream.readLine());
printf("read line\n");
}
printf("end\n");
}
}
在此僅詳細說明標準文件對話框QFileDialog的getOpenFileName()靜態函數各個參數的作用,其他文件對話框類中相關的靜態函數的參數有與其類似之處。
QString QFileDialog::getOpenFileName
(
QWidget* parent=0, //定義標準文件對話框的父窗口
const QString & caption=QString(), //定義標準文件對話框的標題名
const QString & dir=QString(), //指定默認目錄
const QString & filter=QString(), //對文件類型進行過濾,只有與過濾匹配的文件類型才顯示
QString * selectedFilter=0, //用戶選擇的過濾器通過此參數返回
Options options=0
);
2.3 打印文件
打印文本在文本編輯工作中經常使用,OPrintDialog標準對話框提供了打印機的選擇、配置功能,並允許使用者改變文檔有關的設置,如頁面範圍、打印份數等。Qt5中將QPrinter、QPrintDialog等類歸入到了printsupport模塊中,使用時要在.pro文件中加“QT += printsupport”。
2.3.1 文本打印
實現打印文本功能的函數ShowPrintText ()如下:
void ImgProcessor::ShowPrintText()
{
QPrinter printer;
QPrintDialog printDialog(&printer, this); //創建一個QPrintDialog對象,參數爲QPinter對象
if(printDialog.exec()) //判斷用戶是否單擊“打印”按鈕
{
QTextDocument *doc =showWidget->text->document();
doc->print(&printer);
}
}
2.3.2 圖像打印
實現打印圖像功能的函數ShowPrintImage ()如下:
void ImgProcessor::ShowPrintImage()
{
QPrinter printer;
QPrintDialog printDialog(&printer,this);
if(printDialog.exec()) //判斷用戶是否點擊了"打印“按鈕
{
QPainter painter(&printer);
QRect rect =painter.viewport(); //獲取QPianter對象的視口矩形區域
QSize size = img.size(); //獲取圖像的大小
size.scale(rect.size(),Qt::KeepAspectRatio);
painter.setViewport(rect.x(),rect.y(),size.width(),size.height()); //按照圖形的比例大小重新設置視口矩形區域
painter.setWindow(img.rect()); //設置QPainter窗口大小爲圖像的大小
painter.drawImage(0,0,img); //打印圖像
}
}
3 Qt5圖像座標變換功能
QMatrix類提供了世界座標系統的二維轉換功能,可以使窗體轉換變形,經常在繪圖程序中使用,還可以實現座標系統的移動、縮放、變形及旋轉功能。
3.1 縮放功能
實現圖形放大功能的函數ShowZoomIn()如下:
void ImgProcessor::ShowZoomIn()
{
if(img.isNull()) //有效性判斷
return;
QMatrix martix;
martix.scale(2,2); //按照兩倍比例對水平和垂直方向進行放大,縮小兩倍改爲(0.5, 0.5)即可
img = img.transformed(martix); //將當前顯示的圖形按照該座標矩陣進行轉換
showWidget->imageLabel->setPixmap(QPixmap::fromImage(img)); //重新設置顯示圖形
}
3.2 旋轉功能
實現90度旋轉功能的ShowRotate90()函數的具體實現代碼如下:
void ImgProcessor::ShowRotate90()
{
if(img.isNull())
return;
QMatrix matrix;
matrix.rotate(90);
img = img.transformed(matrix);
showWidget->imageLabel->setPixmap(QPixmap::fromImage(img));
}
3.3 鏡像功能
通過QImage::mirroored(bool horizontal, bool vertical)實現圖形的鏡像功能,參數horizontal和vertical分別指定了鏡像的方向。
ShowMirrorVertical ()、ShowMirrorHorizontal ()函數的具體實現代碼如下:
void ImgProcessor::ShowMirrorVertical()
{
if(img.isNull())
return;
img=img.mirrored(false,true);
showWidget->imageLabel->setPixmap(QPixmap::fromImage(img));
}
void ImgProcessor::ShowMirrorHorizontal()
{
if(img.isNull())
return;
img=img.mirrored(true,false);
showWidget->imageLabel->setPixmap(QPixmap::fromImage(img));
}
4 Qt5文本編輯功能
在編寫包含格式設置的文本編輯程序時,經常用到的Qt類有QTextEdit、QTextDocument、QTextBlock、QTextList、QTextFrame、QTextTable、QTextCharFormat、QTextBlockFormat、QTextFrameFormat和QTextTableFormat等,各類之間的劃分與關係如下圖所示。
任何一個文本編輯的程序都要用到QTextEdit作爲輸入文本的容器,在它裏面輸入可編輯文本由QTextDocument作爲載體,而用來便是QTextDocument的元素QTextBlock、QTextList、QTextFrame等是QTextDocument的不同表現形式,可以表示爲字符串、段落、列表、表格或圖片。
每種元素都有自己的格式,例如,QTextBlockFormat類對應於QTextBlock類,QTextBlock類用於表示一塊文本,通常可以理解爲一個段落,但它並不僅指段落;QTextBlockFormat類則表示這一塊文本的格式,如縮進的值、與四邊的邊距等。
從上圖可以看出用於表示編輯文本中的光標QTextCursor類是一個非常重要也經常會用到的類,它提供了對QTextDocument文檔的修改接口,所有文檔格式的修改說到底都與光標有關。例如,改變字符的格式,實際上是指改變光標處字符的格式。又例如,改變段落的格式,實際上是指改變光標所在段落上的格式。因此,所有對QTextDocument的修改都能通過QTextCursor類實現,QTextCursor類在文檔編輯類程序中有着重要的作用。
4.1 設置字體
完成設置選定文字字體的函數ShowFontComboBox()代碼如下:
</pre><pre name="code" class="cpp">void ImgProcessor::ShowFontComboBox(QString comboStr) //設置字體
{
QTextCharFormat fmt;
fmt.setFontFamily(comboStr);
mergeFormat(fmt); //將新的格式應用到光標選區內的字符
}
前面介紹過,所有對於QTextDocument進行的修改都通過QTextCursor類來完成,具體代碼如下:
void ImgProcessor::mergeFormat(QTextCharFormat format)
{
QTextCursor cursor =showWidget->text->textCursor(); //獲得編輯框中的光標
if(!cursor.hasSelection()) //若光標沒有高亮選區則將光標所在處的詞作爲選區,由前後空格或“,”、”.“等標號區分詞
{
cursor.select(QTextCursor::WordUnderCursor);
}
//調用QTextCursor的mergeCharFormat()函數將參數format所表示的格式應用到光標所在處的字符上
cursor.mergeCharFormat(format);
//調用QTextEdit的mergeCurrentCharFormat()函數將格式應用到選區內所有的字符上
showWidget->text->mergeCurrentCharFormat(format);
}
4.2 設置字號
設置選定文字字號大小的ShowSizeSpinBox()函數代碼如下:
void ImgProcessor::ShowSizeSpinBox(QString spinValue) //設置字號
{
QTextCharFormat fmt;
fmt.setFontPointSize(spinValue.toFloat());
showWidget->text->mergeCurrentCharFormat(fmt);
}
4.3 設置文字加粗
文字的粗細值由QFont::Weight表示,它是一個整型值,取值範圍是0-99,有五個預設值,分別爲:QFont::Light(25)、QFont::Normal(50)、QFont::DEMIBold(63)、QFont::Bold(75)和QFont::Black(87),通常在QFont::Normal和QFont::Bold之間轉換。
設置選定文字爲加粗顯示的ShowBoldBtn()函數代碼如下:
void ImgProcessor::ShowBoldBtn() //設置文字顯示加粗
{
QTextCharFormat fmt;
fmt.setFontWeight(boldBtn->isChecked()?QFont::Bold:QFont::Normal);
showWidget->text->mergeCurrentCharFormat(fmt);
}
4.4 設置文字傾斜
設置選定文字爲斜體顯示的ShowItalicBtn()函數代碼如下:
void ImgProcessor::ShowItalicBtn() //設置文字顯示斜體
{
QTextCharFormat fmt;
fmt.setFontItalic(italicBtn->isChecked());
showWidget->text->mergeCurrentCharFormat(fmt);
}
4.5 文字加下劃線
在選定文字下方加下畫線的ShowUnderlineBtn()函數代碼如下:
void ImgProcessor::ShowUnderlineBtn() //設置文字加下畫線
{
QTextCharFormat fmt;
fmt.setFontUnderline(underlineBtn->isChecked());
showWidget->text->mergeCurrentCharFormat(fmt);
}
4.6 設置文字顏色
設置選定文字顏色的ShowColorBtn()函數代碼如下:
void ImgProcessor::ShowColorBtn() //設置文字顏色
{
QColor color=QColorDialog::getColor(Qt::red,this);
if(color.isValid())
{
QTextCharFormat fmt;
fmt.setForeground(color);
showWidget->text->mergeCurrentCharFormat(fmt);
}
}
上面使用了標準顏色對話框QColorDialog類,第一個參數制訂了選中的顏色,默認是白色,通過QColor::isValid()可以判斷用戶選擇的顏色是否有效,若用戶單擊”取消“按鈕,QColor::isValid()將返回false。第二個參數定義了彼岸準顏色對話框的父窗口。
4.7 設置字符格式
當光標所在處的字符格式發生變化時調用此槽函數,函數根據新的字符格式將工具欄上各個格式控件的顯示更新。
void ImgProcessor::ShowCurrentFormatChanged(const QTextCharFormat &fmt)
{
fontComboBox->setCurrentIndex(fontComboBox->findText(fmt .fontFamily()));
sizeComboBox->setCurrentIndex(sizeComboBox->findText( QString::number(fmt.fontPointSize())));
boldBtn->setChecked(fmt.font().bold());
italicBtn->setChecked(fmt.fontItalic());
underlineBtn->setChecked(fmt.fontUnderline());
}
5 Qt5排版功能
具體實現步驟如下。
(1)在頭文件中添加“private:”變量:
QLabel *listLabel; //排序設置項
QComboBox *listComboBox;
QActionGroup *actGrp;
QAction *leftAction;
QAction *rightAction;
QAction *centerAction;
QAction *justifyAction;
QToolBar *listToolBar; //排序工具欄
(2)在頭文件中添加“protected slots:”變量:
void ShowList(int);
void ShowAlignment(QAction *act);
void ShowCursorPositionChanged();
(3)在相對應的構造函數中,在語句“setCentralWidget(showWidget);”與語句“createActions();”之間添加如下代碼:
//排序
listLabel =new QLabel(tr("排序"));
listComboBox =new QComboBox;
listComboBox->addItem("Standard");
listComboBox->addItem("QTextListFormat::ListDisc");
listComboBox->addItem("QTextListFormat::ListCircle");
listComboBox->addItem("QTextListFormat::ListSquare");
listComboBox->addItem("QTextListFormat::ListDecimal");
listComboBox->addItem("QTextListFormat::ListLowerAlpha");
listComboBox->addItem("QTextListFormat::ListUpperAlpha");
listComboBox->addItem("QTextListFormat::ListLowerRoman");
listComboBox->addItem("QTextListFormat::ListUpperRoman");
(4)在構造函數的最後部分添加相關的事件關聯:
connect(listComboBox,SIGNAL(activated(int)),this,SLOT(ShowList(int)));
connect(showWidget->text->document(),SIGNAL(undoAvailable(bool)),redoAction,SLOT(setEnabled(bool)));
connect(showWidget->text->document(),SIGNAL(redoAvailable(bool)), redoAction,SLOT(setEnabled(bool)));
connect(showWidget->text,SIGNAL(cursorPositionChanged()), this,SLOT(ShowCursorPositionChanged()));
(5)在相對應的工具欄createActions()函數中添加如下代碼:
//排序:左對齊、右對齊、居中和兩端對齊
actGrp =new QActionGroup(this);
leftAction =new QAction(QIcon("left.png"),"左對齊",actGrp);
leftAction->setCheckable(true);
rightAction =new QAction(QIcon("right.png"),"右對齊",actGrp);
rightAction->setCheckable(true);
centerAction =new QAction(QIcon("center.png"),"居中",actGrp);
centerAction->setCheckable(true);
justifyAction =new QAction(QIcon("justify.png"),"兩端對齊",actGrp);
justifyAction->setCheckable(true);
connect(actGrp,SIGNAL(triggered(QAction*)),this,SLOT(ShowAlignment (QAction*)));
(6)在相對應的工具欄createToolBars()函數中添加如下代碼:
//排序工具條
listToolBar =addToolBar("list");
listToolBar->addWidget(listLabel);
listToolBar->addWidget(listComboBox);
listToolBar->addSeparator();
listToolBar->addActions(actGrp->actions()); <span style="line-height: 1.5; widows: auto; font-family: 微軟雅黑; background-color: inherit;"> </span>
5.1 實現段落對齊
完成對按下某個對齊按鈕的響應用ShowAlignment()函數,根據比較判斷觸發的是哪個對齊按鈕,調用QTextEdit的setAlignment函數可以實現當前段落的對齊調整。具體代碼如下:
void ImgProcessor::ShowAlignment(QAction *act)
{
if(act==leftAction)
showWidget->text->setAlignment(Qt::AlignLeft);
if(act==rightAction)
showWidget->text->setAlignment(Qt::AlignRight);
if(act==centerAction)
showWidget->text->setAlignment(Qt::AlignCenter);
if(act==justifyAction)
showWidget->text->setAlignment(Qt::AlignJustify);
}
響應文本中光標位置處發生改變的信號的ShowCursorPositionChanged()函數代碼如下:
void ImgProcessor::ShowCursorPositionChanged()
{
if(showWidget->text->alignment()==Qt::AlignLeft)
leftAction->setChecked(true);
if(showWidget->text->alignment()==Qt::AlignRight)
rightAction->setChecked(true);
if(showWidget->text->alignment()==Qt::AlignCenter)
centerAction->setChecked(true);
if(showWidget->text->alignment()==Qt::AlignJustify)
justifyAction->setChecked(true);
}
5.2 實現文本排序
文本排序功能實現的基本流程如下:
QTextListFormat包含兩個基本屬性,一個爲QTextListFormat::style,表示文本採用哪種排序方式;另一個爲QTextListFormat::indent,表示排序後的縮進值。
實現根據用戶選擇的不同排序方式對文本進行排序的ShowList()函數代碼如下:
void ImgProcessor::ShowList(int index)
{
QTextCursor cursor=showWidget->text->textCursor();
if(index!=0)
{
QTextListFormat::Style style=QTextListFormat::ListDisc;
switch(index) //設置style屬性值,Qt提供了下面8中文本排序方式
{
default:
case 1:
style=QTextListFormat::ListDisc; break;
case 2:
style=QTextListFormat::ListCircle; break;
case 3:
style=QTextListFormat::ListSquare; break;
case 4:
style=QTextListFormat::ListDecimal; break;
case 5:
style=QTextListFormat::ListLowerAlpha; break;
case 6:
style=QTextListFormat::ListUpperAlpha; break;
case 7:
style=QTextListFormat::ListLowerRoman; break;
case 8:
style=QTextListFormat::ListUpperRoman; break;
}
cursor.beginEditBlock(); //設置縮進值
QTextBlockFormat blockFmt=cursor.blockFormat();
QTextListFormat listFmt;
if(cursor.currentList())
{
listFmt= cursor.currentList()->format();
}
else
{
listFmt.setIndent(blockFmt.indent()+1);
blockFmt.setIndent(0);
cursor.setBlockFormat(blockFmt);
}
listFmt.setStyle(style);
cursor.createList(listFmt);
cursor.endEditBlock();
}
else
{
QTextBlockFormat bfmt;
bfmt.setObjectIndex(-1);
cursor.mergeBlockFormat(bfmt);
}
}