第五章 Qt之应用程序主窗口
5.1 主窗口框架
Qt中提供了以QMainWindow类为核心的主窗口框架,QMainWindow类拥有自己的布局如下图,包含以下组件:
graph TD
A(QMainWindow)-->b1(菜单栏 QMenuBar)
A-->b2(工具栏 QToolBar)
A-->b3(中心部件 Central Widget)
A-->b4(Dock部件 QDock Widget)
A-->b5(状态栏 QStatusBar)
- 菜单栏:有QAction动作类实现,位于窗口顶部,一个主窗口只能有一个菜单栏
- 工具栏:可以插入其他窗口部件,且可以移动;一个主窗口可以拥有多个工具栏
- 中心部件:应用程序的主要功能实现区域,一个主窗口只能有一个中心部件
- Dock部件:Dock部件常被称为停靠窗口,因为可以停靠在中心部件的四周,用来放置一些部件来实现一些功能。一个主窗口可以拥有多个Dock部件
- 状态栏:用于显示程序的一些信息,在主窗口最底部,一个主窗口只能拥有一个状态栏
5.1.1 Qt资源系统、菜单栏和工具栏
5.1.1.1 使用资源
- add new -> Qt -> Qt Resource File
- 修改Qt Resource File的相对路径前缀,存放文件时,应将文件放置在Qt Resource File的qrc文件的同级或子目录下
- 在资源系统中add File 并 保存
- 在设计师界面通过Action编辑器,双击Action可设置图标,提示和快捷键
添加的qrc文件实际时XML格式的文本文件,代码如下:
<RCC>
<qresource prefix="/images">
<file>images/new.png</file>
<file>images/open.png</file>
</qresource>
</RCC>
#之后在使用资源系统管理的文件时,可以通过“/images/images/new.png”路径进行使用;其中前缀/images表明为图片资源
5.1.1.2 编写代码方式添加菜单
QToolBar *toolBar = new QToolBar(this); //创建一个新的工具栏
this->addToolBar(Qt::TopToolBarArea, toolBar); //为当前主窗口添加一个工具栏
QMenu *FileMenu = ui->menubar->addMenu(tr("文件(&F)")); //为菜单栏添加一个项目卡
QAction *action_New = new QAction(QIcon(":/images/images/new.png"), tr("新建文件或项目(&N)")); //创建一个动作
action_New->setShortcut(QKeySequence("Ctrl+N")); //给动作设置快捷键
action_New->setToolTip("新建文件"); //动作默认的工具栏鼠标放置提示为动作的名称,可通过setToolTip函数设置为其他提示
QAction *action_Open =new QAction(QIcon(":/images/images/open.png"), tr("打开文件或项目(&O)"));
action_Open->setShortcut(QKeySequence("Ctrl+O"));
QAction *action_RecFile = new QAction(tr("最近访问的文件(&R)"));
action_RecFile->setShortcut(QKeySequence("Ctrl+R"));
QList<QAction*> action_File; //创建一个动作列表
//添加动作至动作列表中
QAction* shuzu[] = {action_New,action_Open,action_RecFile};
for(int i=0; i<(int)(sizeof(shuzu)/sizeof(action_New))-1; i++)
action_File.push_back(shuzu[i]);
FileMenu->addActions(action_File); //将动作列表中的动作添加至菜单栏的FileMenu项目卡中
FileMenu->addSeparator(); //为菜单选项卡添加水平分隔线
FileMenu->addAction(action_RecFile); //分割线后添加的Action
/*=============================================================================*/
QMenu *editMenu = ui->menubar->addMenu(tr("新建(&E)"));
QAction *action_Undo = editMenu->addAction(tr("&Undo"));
action_Undo->setShortcut(QKeySequence("Ctrl+Z"));
// toolBar->addAction(action_New);
// toolBar->addAction(action_Open);
toolBar->addActions({action_New, action_Open});
5.1.1.3 菜单栏
QMenu *editMenu = ui->menubar->addMenu(tr("新建(&E)"));
QAction *action_Undo = editMenu->addAction(tr("&Undo"));
action_Undo->setShortcut(QKeySequence("Ctrl+Z"));
QActionGroup *group = new QActionGroup(this); //创建一个动作组,该动作组中只能有一个动作处于被选中状态
QAction *action_L = group->addAction(tr("左对齐(&L)"));
action_L->setCheckable(true); //对QAction的SsetCheckable属性进行设置,使被选中时能够在选项前显示状态
QAction *action_R = group->addAction(tr("右对齐(&R)"));
action_R->setCheckable(true);
QAction *action_C = group->addAction(tr("居中(&C)"));
action_C->setCheckable(true);
action_L->setChecked(true); //设置action_L为默认选中状态
editMenu->addSeparator();
editMenu->addActions({action_L, action_R, action_C});
editMenu->addSeparator();
5.1.1.4 工具栏
| QToolBar属性 | 描述 |
|---|---|
| toolButtonStyle | 用于设置图标和相应文本的显示及其相对位置 |
| movable | 设置状态栏是否可移动 |
| allowedArea | 用来设置允许停靠的位置 |
| iconsize | 用于设置图标的大小 |
| floatable | 用于设置是否可以悬浮 |
#include <QToolButton>
/*-------------------------------------设置工具栏属性--------------------------------------------*/
QToolBar *toolBar = new QToolBar(this); //创建一个新的工具栏
toolBar->setMovable(true); //设置工具栏是否可移动
toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); //设置工具栏图标和文本的显示方式
toolBar->setAllowedAreas(Qt::TopToolBarArea|Qt::LeftToolBarArea); //设置工具栏能够停靠的位置
toolBar->setIconSize(QSize(48,48)); //设置图标显示大小
this->addToolBar(Qt::TopToolBarArea, toolBar); //为当前主窗口添加一个工具栏
/*-------------------------------------为工具栏添加QToolButon部件--------------------------------------------*/
QToolButton *toolBtn = new QToolButton(this); //创建一个toolButton部件,其父为当前主窗口
toolBtn->setText(tr("颜色")); //设置toolButton部件的显示文本
QMenu *colorMenu = new QMenu(this); //为ToolButton创建一个菜单列表
colorMenu->addAction(tr("绿色")); //添加菜单动作
colorMenu->addAction(tr("红色")); //添加菜单动作
toolBtn->setMenu(colorMenu); //将ToolButton与上述创建的菜单列表绑定
toolBtn->setPopupMode(QToolButton::MenuButtonPopup); //设置ToolButton的调用属性(点击箭头显示)
toolBar->addWidget(toolBtn); //将创建的toolButton部件加入工具栏
5.1.2 中心部件
中心部件一般为编辑器或者浏览器。支持单文档部件和多文档部件。
graph TD
A(中心部件)-->b1(浏览器与编辑器支持富文本 QTextEdit)
A-->b2(纯文本编辑器 QPlainEdit)
A-->b3(富文本浏览器 QTextBrowser)
A--显示多文档界面的区域-->b4(QMdiArea)
b4--子窗口-->c1(QMdiSubWindow)
c1-->d1(标题栏)
c1-->d2(中心区域)
d2-->其他部件
#include <QMdiSubWindow>
#include <QTextEdit>
QTextEdit *edit = new QTextEdit(this);
QMdiSubWindow *child = ui->midArea->addSubWindow(edit);
child->setWindowTitle(tr("多文档编辑子窗口"));
child->show();
5.1.3 Dock部件
QDockWiget类提供的部件可以停靠在QMainWindow中,也可以悬浮起来作为桌面顶级窗口,称为Dock部件或者停靠部件。
- Dock部件一般用于存放一些其他部件实现特殊功能,like工具箱。
- 可以停靠在中心部件的四周,也可以悬浮起来拖动到任意位置,同时也可被关闭和隐藏
- Dock部件包含一个标题栏和一个内容区域
- 可以向Dock部件中放置任何部件
#include <QDockWidget>
#include <QTextEdit>
QDockWidget *dockwidget = new QDockWidget(tr("Dock"),this); //在当前主窗口下添加Dock部件
QTextEdit *edit = new QTextEdit(); //新建一个TextEdit部件
dockwidget->setWidget(edit); //将TextEdit部件添加到dock部件中
dockwidget->show(); //显示dock部件
5.1.4 状态栏
graph TD
A(状态栏)-->b1(临时信息--提示信息)
b1-->c1(showMessage函数)
c1-->默认最左边
A-->b2(正常信--显示页数和行号等)
b2-->c2(addWidget函数添加QLabel)
c2-->默认最左边
A-->b3(永久信息--版本号或日期等)
b3-->c3(addPermanent函数)
c3-->默认最右边
在状态栏的最右端有一个QSizeGrip部件,用来调整窗口的大小,可以使用setSizeGripEnabled()函数禁用它
#include <QLabel>
ui->statusbar->showMessage(tr("欢迎使用多文档编辑器"),2000); //2000表示显示的时间单位ms
QLabel *permanent = new QLabel(this);
permanent->setFrameStyle(QFrame::Box|QFrame::Sunken); //因为QLabel继承了QFrame类,所以可以直接设置
permanent->setText("www.qter.org"); //设置标签内容
ui->statusbar->addPermanentWidget(permanent); //添加永久信息,默认在状态栏最右边显示
5.1.5 自定义菜单
菜单中也可以使用其他的部件。该功能的实现依赖于QWidgetAction类。需新建一个类,该类继承自QWidgetAction类,并且在其中重新实现createWidget()函数。
/*实现一个菜单项:包含一个标签和一个行编辑器*/
//QWidgetAction()创建的QAction在被添加到QMenu时会调用createWidget()函数
MyAction *action = new MyAction;
QMenu *editMenu = ui->menubar->addMenu(tr("编辑(&E)"));
editMenu->addAction(action); //此处会调用QWidgetAction::createWidget()函数
5.2 富文本处理
富文本:即在文档中可以使用比如字体颜色、图片和表格等。QTextEdit支持富文本格式。关键字:Rich Text Processing
5.2.1 富文本文档结构
- 编辑操作:基于光标实现的接口函数;基于QTextCursor类
- 只读操作:使用只读的分层次接口函数,有利于文档的检索和输出;基于QTextDocument类
graph TD
A(QTextEdit)-->b1(QTextCursor)
A-->b2(QTextDocument)
b1-->QTextFrameFormat
b1-->QTextBlockFormat
b1-->QTextTableFormat
b1-->QTextListFormat
b2-->QTextFrame
b2-->QTextBlock
b2-->QTextTable
b2-->QTextList


TextEdit部件的结构图如图5-9所示,后续所有的文本块、表格等都添加在Root Frame中。
QTextEdit *textEdit = new QTextEdit;
QTextDocument *document = textEdit->document(); //获取textEdit的文档结构
QTextFrame *frame = document->RootFrame(); //获取文档结构的根框架
/*遍历文档结构中的所有frame框架*/
QTextFrame::iterator it; //建立QTextFrame的迭代器
for(it = frame.begin(); !(it.atEnd); ++it)
{
QTextFrame *childFrame = it.currentFrame();
if(childFrame)
qDebug()<<"this is a frame.";
}
5.2.2 文本块
文本块QTextBlock类为文本文档QTextDocument提供了一个文本片段(QTextFragment)的容器。一个文本块可以看作是一个段落,但不能使用回车换行。因为一个回车换行表示创建一个新的文本块。
- 文本块的格式由QTextBlockFormat类处理:对齐方式、文本块四周边距、缩进等
- 文本块中文本内容的格式由QTextCharFormat类处理:字体大小、加粗、下划线等
/*如何遍历文档结构中的所有文本块(QTextBlock)*/
QTextEdit *textEdit = new QTextEdit;
QTextDocument *document = textEdit->document(); //获取textEdit的文档结构
QTextBlock block = document->firstBlock();
for(int i=0; i<document->blockCount(); i++) //document->blockCount()获取文档结构中所有文本块的个数
{
qDebug()<<tr("文本块%1,文本块首行行号:%2, 长度为: %3, 内容为: ")
.arg(i).arg(block.firstLineNumber()).arg(block.length())
<<block.text(); //block.length()从1开始计算,最小为1
block = block.next();
}
/*编辑文本块及其内容的格式*/
QTextCursor cursor = textEdit->textCursor(); //获取光标
QTextBlockFormat blockFormat; //文本块格式
blockFormat.setAlignment(Qt::AlignCenter); //水平居中
cursor.insertBlock(blockFormat); //使用文本块格式
QTextCharFormat charFormat; //字符格式
charFormat.setBackground(Qt::lightGray); //背景色
charFormat.setForeground(Qt::blue); //字体颜色
//字体设置为宋体,12号,加粗,倾斜
charFormat.setFont(QFont(tr("宋体"), 12, QFont::Bold, true));
charFormat.setFontUnderline(true); //使用下划线
cursor.setCharFormat(charFormat);
cursor.insertText(tr("测试字体"));
5.2.3 表格、列表和图片
- Table:QTextTable类,其格式由QTextTableFormat类管理
- List:QTextList类,其格式由QTextListFormat类管理
- Image:图片没有对应的类;QTextImageFormat类对图片的格式进行管理,通过setHeight()和setWidth()设置图片的高和宽,setName(“路径”)指定图片
/*Table*/
QTextCursor cursor = textEdit->textCursor();
QTextTableFormat format;
format.setCellSpacing(2); //表格外边白
format.setCellPadding(10); //表格内边白
cursor.insertTable(2,2,format); //插入2行2列的表格
/*List*/
QTextCursor cursor = textEdit->textCursor();
QTextListFormat format;
format.setStyle(QTextListFormat::ListDecimal); //设置数字编号
cursor.insertList(format);
/*image*/
QTextImageFormat format;
format.setName("C:/Users/LN/Pictures/Saved Pictures/earth01.png");
textEdit->textCursor().insertImage(format);
5.2.4 查找功能
- QTextEdit类的find()函数
- QTextDocument::FindBackward表示向后查找,即从输入完成开始,向左查找
/*创建查找对话框,其中对话框中包含行编辑器和查找下一个按钮*/
findDialog = new QDialog(this);
findDialog->setWindowTitle(tr("查找匹配项"));
lineEdit = new QLineEdit;
QPushButton *btn = new QPushButton;
btn->setText(tr("查找下一个"));
connect(btn, &QPushButton::clicked, this, &MainWindow::findNext);
QVBoxLayout *vblayout = new QVBoxLayout;
vblayout->addWidget(lineEdit);
vblayout->addWidget(btn);
findDialog->setLayout(vblayout);
/*创建一个动作来弹出查找对话框*/
QAction* action_textFind = new QAction(tr("查找"), this);
connect(action_textFind, &QAction::triggered, this, &MainWindow::textFind);
toolBar->addAction(action_textFind);
/*查找动作的槽函数,用于显示查找对话框*/
void MainWindow::textFind()
{
findDialog->show();
}
/*查找下一个按钮的槽函数*/
void MainWindow::findNext()
{
QString string = lineEdit->text(); //获取行编辑器的内容
qDebug()<<"查找内容:"<<string;
//使用查找功能,光标默认位置在输入内容的末端;每次查找后光标的位置会在最后一次查找的位置
//使用查找功能;QTextDocument::FindBackward表示向后查找,默认为向前查找
bool isfind = textEdit->find(string, QTextDocument::FindBackward);
if(isfind)
{
qDebug()<<tr("行号:%1,列号:%2")
.arg(textEdit->textCursor().blockNumber())
.arg(textEdit->textCursor().columnNumber());
}
}
5.2.5 语法高亮和HTML
Qt富文本处理提供了QSyntaxHighlighter类实现语法高亮,为实现该功能,需创建QSyntaxHighlighter类的子类,然后重新实现highlightBlock()函数,使用时直接将QTextDocument类对象指针作为其父部件指针,这样就可以自动调用highlightBlock()函数了。
- QTextEdit 使用HTML语法:textEdit->append(tr("<h1><font color =red>使用HTML</font></h1>"));
/*==========mysyntaxhighlighter.h===========*/
#ifndef MYSYNTAXHIGHLIGHTER_H
#define MYSYNTAXHIGHLIGHTER_H
#include <QSyntaxHighlighter>
class mysyntaxhighlighter : public QSyntaxHighlighter
{
Q_OBJECT
public:
explicit mysyntaxhighlighter(QTextDocument* parent = 0);
protected:
void highlightBlock(const QString &text); //必须重写实现函数
};
#endif // MYSYNTAXHIGHLIGHTER_H
/*==========mysyntaxhighlighter.cpp===========*/
#include "mysyntaxhighlighter.h"
mysyntaxhighlighter::mysyntaxhighlighter(QTextDocument *parent) :
QSyntaxHighlighter(parent)
{
}
void mysyntaxhighlighter::highlightBlock(const QString &text){
QTextCharFormat myFormat;
myFormat.setFontWeight(QFont::Bold);
myFormat.setForeground(Qt::green);
QString pattern = "\\bchar\\b"; //需要匹配的字符串为char
QRegExp expression(pattern); //创建正则表达式
int index = text.indexOf(expression); //从位置0开始匹配字符串
//如果匹配成功则返回值为字符串的起始位置,它大于或等于0
while(index >= 0){
int length = expression.matchedLength(); //要匹配字符串的长度
setFormat(index, length, myFormat); //要对匹配字符串设置格式
index = text.indexOf(expression, index+length); //继续匹配
}
}
/*==========mainWindow.cpp构造函数添加内容===========*/
highlighter = new mysyntaxhighlighter(textEdit->document());
//其中需要对mainwindow类定义中,声明private: highlighter变量
5.3 拖放操作
- 实现将文件拖入后打开的操作;具体参考Drag and Drop示例
5.3.1 使用拖放打开文件
- 当鼠标拖拽一个数据进入主窗口时,触发dragEnterEvent()事件处理函数;该数据由QmimeData类对象处理
- 当松开鼠标左键,将数据放入主窗口时就会触发dropEvent()事件处理函数
#include <QDragEnterEvent>
#include <QUrl>
#include <QFile>
#include <QTextStream>
#include <QMimeData>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
textEdit = new QTextEdit;
QGridLayout *layout = new QGridLayout;
layout->addWidget(textEdit);
ui->centralwidget->setLayout(layout);
setAcceptDrops(true);
}
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
if(event->mimeData()->hasUrls()) //数据中是否包含URL
event->acceptProposedAction(); //如果是则接收动作
else
event->ignore();
}
void MainWindow::dropEvent(QDropEvent *event)
{
const QMimeData *mimeData = event->mimeData(); //获取MIME数据
if(mimeData->hasUrls()){
QList<QUrl> urlList = mimeData->urls(); //获取URL列表
QString fileName = urlList.at(0).toLocalFile(); //将URL列表中的第一个URL表示为本地文件路径
if(!fileName.isEmpty()){ //如果路径不为空
QFile file(fileName); //建立QFile对象
if(!file.open(QIODevice::ReadOnly)) //以只读的方式打开文件
return;
QTextStream in(&file); //建立文本流数据
textEdit->setText(in.readAll()); //将文件中所有内容读入编辑器
}
}
}
浙公网安备 33010602011771号