这里通过一个文本编辑器的应用实例来介绍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);
}
}