QT 主窗口

简介

任何界面应用都有一个主窗口,今天我们谈谈主窗口相关知识。一个主窗口包括菜单栏,工具栏,状态栏,以及中心区域等部分。我们先从菜单栏说起

菜单栏

我们创建一个主窗口应用程序, 在ui文件里的菜单栏里有“在这里输入”的一个菜单,我们双击它输入“文件(&F)”, 这样通过点击alt + F 就可以弹出文件菜单。点击文件菜单,同样会弹出“在这里输入”,我们双击它编辑输入“新建文件(&N)”,可以在右侧的属性栏里为其添加一个图标,同样,我们再添加一个“显示Dock(&D)”的菜单。我们再从左侧的控件Containers里拖动Dock Widget到中心区域,在dock widget中添加一个按钮,一个fontComboBox,一个QTextEdit。DockWidget添加的控件并不会影响主窗口的centralwidget, 我们在centralwidget中添加一个QMdiArea控件。
https://cdn.llfc.club/1665046632168.jpg
我们可以选择Action Editor中的两个action,分别为其添加槽函数,右击actionnew_N选择转到槽,然后选择trigger信号,Qt会自动生成槽函数代码
https://cdn.llfc.club/1665047247148.jpg
同样的道理为显示dock菜单添加槽函数,然后分别实现两个槽函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void MainWindow::on_actionnew_N_triggered()
{
qDebug() << "新建文件..." << endl;
QTextEdit * textEdit = new QTextEdit(this);
auto childWindow = ui->mdiArea->addSubWindow(textEdit);
childWindow->setWindowTitle(tr("文本编辑子窗口"));
childWindow->show();
}

void MainWindow::on_actionshowdock_triggered()
{
qDebug() << "显示dock widget" << endl;
ui->dockWidget_2->show();
}

因为QMdiArea是一个多窗口控件,这样我们每次点击新建菜单就会在窗口的中心部件中创建一个子窗口,多次点击会生成多个子窗口。点击显示dock菜单就会显示dockwidget。

我们可以在代码中添加菜单并创建菜单点击后的回调函数

1
2
3
4
5
6
7
8
9
10
11
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QMenu* editMenu = ui->menubar->addMenu(tr("编辑(&E)"));
editMenu->addSeparator();
QAction * action_Open = editMenu->addAction(QIcon(":/img/head.jpg"), tr("打开文件(&O)"));
action_Open->setShortcut(QKeySequence("Ctrl+O"));
connect(action_Open,&QAction::triggered, this, &MainWindow::on_action_open_triggered);
}

通过代码我们创建了一个编辑菜单,编辑菜单下有打开文件的动作,设置Ctrl+O为快捷键,并为该动作创建槽函数,然后连结这个槽函数。

1
2
3
4
void MainWindow::on_action_open_triggered()
{
qDebug() << "打开文件..." << endl;
}

所以每次点击打开文件后输出上面的日志。除了可以为菜单栏添加动作外,还可以添加动作组

1
2
3
4
5
6
7
8
9
10
11
12
//建立动作组
QActionGroup * group = new QActionGroup(this);
QAction * action_L = group->addAction(tr("左对(&L)"));
action_L->setCheckable(true);
QAction * action_R = group->addAction(tr("右对(&R)"));
action_R->setCheckable(true);
QAction * action_C = group->addAction(tr("居中(&C)"));
action_C->setCheckable(true);
editMenu->addSeparator();
editMenu->addAction(action_L);
editMenu->addAction(action_R);
editMenu->addAction(action_C);

我们也可以自定义动作类,我们接下来自定义一个动作类,动作类包含一个label和lineEdit。自定义的动作类叫MyAction,
声明如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#ifndef MYACTION_H
#define MYACTION_H

#include <QWidgetAction>
#include <QLineEdit>
#include <QObject>
class MyAction : public QWidgetAction
{
Q_OBJECT
signals:
void getText(const QString& string);

public:

explicit MyAction(QObject * parent = 0);
virtual ~MyAction();
protected:

virtual QWidget *createWidget(QWidget *parent);

private slots:
void sentText();
private:
//声明行编辑器对象
QLineEdit* lineEdit;
};

#endif // MYACTION_H

createWidget 为一个虚函数,继承自QWidgetAction, 将Action加入菜单或者工具栏就会调用createWidget函数。接下来我们实现这个类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include "myaction.h"
#include <QSplitter>
#include <QLabel>


MyAction::MyAction(QObject * parent):QWidgetAction(parent){
// 创建行编辑器
lineEdit = new QLineEdit;
// 将行编辑器的按下回车键信号和发送文本槽关联
connect(lineEdit, &QLineEdit::returnPressed, this, &MyAction::sentText);
}

QWidget* MyAction::createWidget(QWidget * parent){
if(parent->inherits("QMenu")|| parent->inherits("QToolBar")){
QSplitter * spliter = new QSplitter(parent);
QLabel * label = new QLabel;
label->setText(tr("插入文本:"));
spliter->addWidget(label);
spliter->addWidget(lineEdit);
return spliter;
}
return 0;
}

void MyAction::sentText()
{
emit getText(lineEdit->text());
lineEdit->clear();
}

构造函数里创建了一个LineEdit,然后绑定了LineEdit的返回信号,在sentText槽函数里发送了getText信号,然后清除了lineEdit里的内容。createWidget里判断了父节点如果是QMenu或者QToolBar,就创建一个spliter,然后将label和lineedit都加入spliter。在mainwindow的构造函数中创建MyAction,并且加入菜单里。然后将MyAction的getText的信号和MainWindow的setText函数绑定在一起。

1
2
3
MyAction * action = new MyAction(this);
editMenu->addAction(action);
connect(action, &MyAction::getText, this, &MainWindow::setText);

MainWindow的槽函数实现如下

1
2
3
void MainWindow::setText(const QString &string){
ui->textEdit->setText(string);
}

这样当我们点击编辑菜单弹出我们自己实现的MyAction动作,在输入框里输入文字按下回车后文字就会显示到dockwidget的textedit中。
https://cdn.llfc.club/1665062815744.jpg

工具栏

工具栏相比菜单栏更容易操作,更加直观,添加方式和菜单的方式类似,可以添加label,按钮,以及spinbox等。
可以通过ui添加,也可以通过代码添加,下面用代码添加工具栏菜单。

1
2
3
4
5
6
7
8
9
10
11
12
//工具栏添加元素
QToolButton * toolBtn = new QToolButton(this);
toolBtn->setText(tr("颜色"));
QMenu* colorMenu = new QMenu(this);
colorMenu->addAction(tr("红色"));
colorMenu->addAction(tr("绿色"));
toolBtn->setMenu(colorMenu);
toolBtn->setPopupMode(QToolButton::MenuButtonPopup);
ui->toolBar->addWidget(toolBtn);
QSpinBox* spinBox = new QSpinBox(this);
ui->toolBar->addSeparator();
ui->toolBar->addWidget(spinBox);

状态栏

状态栏在窗口的下方,一般在右下方,左下方的为临时的,右下方的为永久的。

1
2
3
4
5
6
7
8
9
void MainWindow::init_status_bar(){
//显示临时消息
ui->statusbar->showMessage(tr("欢迎使用多文档编辑器"),2000);
//创建标签
QLabel* permanent = new QLabel(this);
permanent->setFrameStyle(QFrame::Box | QFrame::Sunken);
permanent->setText("llfc.club");
ui->statusbar->addPermanentWidget(permanent);
}

总结

源码链接https://gitee.com/secondtonone1/qt-learning-notes