目录

QMainWindow

菜单栏(Menu Bar)

添加菜单栏,添加菜单,添加菜单项,并为菜单项设置触发事件(槽函数)

给菜单,菜单项添加快捷键

添加子菜单

给菜单项之间添加分割线

给菜单/菜单项添加图标

题外话——创建菜单栏的内存泄漏

工具栏(QToolBar)

创建工具栏,给工具栏添加action,给action设置图标以及提示信息

菜单栏和工具栏结合使用

设置多个工具栏

工具栏的移动设置

状态栏(Status Bar)

QDockWidget


QMainWindow

大多数时候客户端窗口的主体是QMainWindow而不是QWidget,QWidget是其中的组成部分。QMainWindow的组成如下:

实际上,当我们创建一个QMainWindow项目并选择生成ui文件的时候,中心窗口,菜单栏,状态栏都是默认创建好的:


菜单栏(Menu Bar)

一个窗口只能有一个菜单栏,菜单栏结构示意图如下:

添加菜单栏,添加菜单,添加菜单项,并为菜单项设置触发事件(槽函数)

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //创建一个菜单栏对象
    QMenuBar* menubar = new QMenuBar();
    //将菜单栏添加到窗口,此时menubar的父节点被设置为窗口
    this->setMenuBar(menubar);

    //给菜单栏添加菜单
    QMenu *menu1 = new QMenu("文件");//创建菜单对象
    QMenu *menu2 = new QMenu("编辑");
    QMenu *menu3 = new QMenu("帮助");
    menubar->addMenu(menu1);//把菜单对象添加到菜单栏
    menubar->addMenu(menu2);
    menubar->addMenu(menu3);

    //给菜单添加菜单项
    QAction * action1 = new QAction("打开");//创建菜单项对象
    QAction * action2 = new QAction("保存");
    QAction * action3 = new QAction("退出");
    menu1->addAction(action1);//把菜单项对象添加到菜单
    menu1->addAction(action2);
    menu1->addAction(action3);

    //给菜单项关联一个槽
    connect(action1,&QAction::triggered,this,&MainWindow::handler);
}

void MainWindow::handler()
{
    qDebug()<<"点击了打开按钮!";
}

给菜单,菜单项添加快捷键

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //创建一个菜单栏对象
    QMenuBar* menubar = new QMenuBar();
    //将菜单栏添加到窗口,此时menubar的父节点被设置为窗口
    this->setMenuBar(menubar);

    //给菜单栏添加菜单
    QMenu *menu1 = new QMenu("文件(&a)");//创建菜单对象,并添加快捷键ALt+a
    QMenu *menu2 = new QMenu("编辑(&b)");
    QMenu *menu3 = new QMenu("帮助(&c)");
    menubar->addMenu(menu1);//把菜单对象添加到菜单栏
    menubar->addMenu(menu2);
    menubar->addMenu(menu3);

    //给菜单添加菜单项
    QAction * action1 = new QAction("打开(&z)");//创建菜单项对象并添加快捷键ALt+z
    QAction * action2 = new QAction("保存");
    QAction * action3 = new QAction("退出");
    menu1->addAction(action1);//把菜单项对象添加到菜单
    menu1->addAction(action2);
    menu1->addAction(action3);

    //给菜单项关联一个槽
    connect(action1,&QAction::triggered,this,&MainWindow::handler);
}

在菜单/菜单项文本添加"&+字母"就表示给这个菜单/菜单项添加快捷键"alt+字母"

添加子菜单

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //创建一个菜单栏对象
    QMenuBar* menubar = new QMenuBar();
    //将菜单栏添加到窗口,此时menubar的父节点被设置为窗口
    this->setMenuBar(menubar);

    //给菜单栏添加菜单
    QMenu *menu1 = new QMenu("父菜单");//创建菜单对象
    QMenu *menu2 = new QMenu("菜单2");
    QMenu *menu3 = new QMenu("子菜单");
    menubar->addMenu(menu1);//把菜单对象添加到菜单栏
    menubar->addMenu(menu2);
    menu1->addMenu(menu3);//菜单对象中也有addMenu方法,用于添加子菜单


    //给菜单添加菜单项
    QAction * action1 = new QAction("打开");//创建菜单项对象
    QAction * action2 = new QAction("保存");
    QAction * action3 = new QAction("退出");
    menu1->addAction(action1);//把菜单项对象添加到菜单
    menu3->addAction(action2);
    menu3->addAction(action3);
}

给菜单项之间添加分割线

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //创建一个菜单栏对象
    QMenuBar* menubar = new QMenuBar();
    //将菜单栏添加到窗口,此时menubar的父节点被设置为窗口
    this->setMenuBar(menubar);

    //给菜单栏添加菜单
    QMenu *menu1 = new QMenu("菜单1");//创建菜单对象
    QMenu *menu2 = new QMenu("菜单2");
    menubar->addMenu(menu1);//把菜单对象添加到菜单栏
    menubar->addMenu(menu2);


    //给菜单添加菜单项
    QAction * action1 = new QAction("菜单项1");//创建菜单项对象
    QAction * action2 = new QAction("菜单项2");
    QAction * action3 = new QAction("菜单项3");
    QAction * action4 = new QAction("菜单项4");
    menu1->addAction(action1);//把菜单项对象添加到菜单
    menu1->addAction(action2);
    menu1->addSeparator();//把分割线也当做一个菜单项,它在谁后面被添加,分割线就在谁后面
    menu1->addAction(action3);
    menu1->addAction(action4);

}

给菜单/菜单项添加图标

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //创建一个菜单栏对象
    QMenuBar* menubar = new QMenuBar();
    //将菜单栏添加到窗口,此时menubar的父节点被设置为窗口
    this->setMenuBar(menubar);

    //给菜单栏添加菜单
    QMenu *menu1 = new QMenu("菜单1");//创建菜单对象
    QMenu *menu2 = new QMenu("子菜单");//创建菜单对象
    menubar->addMenu(menu1);//把菜单对象添加到菜单栏
    menu1->addMenu(menu2);//给菜单1添加子菜单

    //给菜单1添加图标
    menu1->setIcon(QIcon(":/rose.jpg"));
    //给子菜单添加图标
    menu2->setIcon(QIcon(":/rose.jpg"));

    //给菜单添加菜单项
    QAction * action1 = new QAction("菜单项1");//创建菜单项对象
    //给菜单项添加图标
    action1->setIcon(QIcon(":/rose.jpg"));
    //把菜单项对象添加到菜单
    menu1->addAction(action1);
}

菜单,子菜单,菜单项都可以设置图标,但是如果给菜单设置图标的话,就会把原有文本覆盖

题外话——创建菜单栏的内存泄漏

在该文章开头我们以及谈及,一旦创建了一个QMainWindows项目并且选择使用QtDesigner(也就是使用ui文件),那么默认就会生成一个菜单栏,而上面的所有代码中我是这么写的:

  //创建一个菜单栏对象
  QMenuBar* menubar = new QMenuBar();
  //将菜单栏添加到窗口,此时menubar的父节点被设置为窗口
  this->setMenuBar(menubar);

一个窗口只能有一个菜单栏,这就相当于我们新创建了一个菜单栏,把人家默认生成的给替换掉了,原有的菜单栏对象就得不到释放了。(细心的同学可能发现我在创建菜单栏的时候没有指定菜单栏的父对象可能导致内存泄漏,不必担心,setMenuBar会帮我们把对象挂到对象树上。)下面我们修改代码,修复内存泄漏:

QMenuBar* menubar = this->menuBar();
this->setMenuBar(menubar);

menuBar函数就是从窗口中获取一个菜单栏对象,如果有就直接获取,如果没有就创建一个。这样一来,在下面设置窗口的菜单栏时,如果本来没有,我们就把新创建的菜单栏对象设置进去了,如果有,也是自己替换自己,不会造成内存泄漏。

当然,不只是菜单栏,选择ui文件后默认生成的栏如果使用不当都会出现这种问题。


工具栏(QToolBar)

大多数情况下,工具栏中的内容就是菜单中的菜单项,相当于菜单项的快捷键,因此工具栏中的元素也是用QAction对象表示

除此之外,一个窗口可以有多个工具栏,也正是因此,添加工具栏的接口是addToolBar而不是像添加菜单栏一样格式的setToolBar。

建工具栏,给工具栏添加action,给action设置图标以及提示信息

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //创建工具栏对象
    QToolBar* tb = new QToolBar();
    //将工具栏对象添加到窗口中
    this->addToolBar(tb);

    //创建QAction
    QAction * action1 = new QAction("选项1");
    QAction * action2 = new QAction("选项2");
    //给QAction设置图标,一般来说工具栏的元素都用图标表示
    action1->setIcon(QIcon(":/rose.jpg"));
    action2->setIcon(QIcon(":/rose.jpg"));

    //给工具栏上的元素设置图标会导致文本被覆盖,因此可以给每个元素设置一个提示信息,鼠标悬停到对应元素就显示提示信息
    //实际上就算不设置提示信息,也有默认的提示信息,即action原来的文本
    action1->setToolTip("这是选项1");
    action2->setToolTip("这是选项2");

    //把QAction对象添加到工具栏中
    tb->addAction(action1);
    tb->addAction(action2);

}

菜单栏和工具栏结合使用

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //创建工具栏对象
    QToolBar* tb = new QToolBar();
    this->addToolBar(tb);

    //添加菜单栏对象
    QMenuBar* mb = this->menuBar();
    this->setMenuBar(mb);

    //创建QAction
    QAction * action1 = new QAction("选项1");
    QAction * action2 = new QAction("选项2");

    //把QAction对象添加到工具栏中
    tb->addAction(action1);
    tb->addAction(action2);

    //把QAction对象添加到菜单栏中
    mb->addAction(action1);
    mb->addAction(action2);

}

同一个action元素被菜单栏和工具栏同时包含,那么会不会导致对象树上一个节点有两个父节点?或者一个节点释放两次呢?不会的,Qt帮我们处理好了。

设置多个工具栏

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //添加工具栏对象
    QToolBar* tb = new QToolBar();
    this->addToolBar(tb);

    QToolBar* tb2 = new QToolBar();
    this->addToolBar(tb);

    //创建QAction
    QAction * action1 = new QAction("选项1");
    QAction * action2 = new QAction("选项2");

    //把QAction对象添加到工具栏中
    tb->addAction(action1);
    tb->addAction(action2);
    
    tb2->addAction(action1);
    tb2->addAction(action2);
}

工具栏的移动设置

默认情况下可以将工具栏拖动到上下左右四个方向并停靠在窗口边沿,以及浮动在窗口内部

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //添加工具栏对象
    QToolBar* tb = new QToolBar();
    this->addToolBar(Qt::LeftToolBarArea,tb);//在添加工具栏的时候可以设置工具栏的初始位置

    //创建QAction
    QAction * action1 = new QAction("选项1");
    QAction * action2 = new QAction("选项2");

    //把QAction对象添加到工具栏中
    tb->addAction(action1);
    tb->addAction(action2);

    //设置工具栏只允许在左边和右边停靠以及浮动
    tb->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);
    //设置工具栏不允许浮动
    tb->setFloatable(false);
    //设置工具栏不允许移动, 固定住了
    tb->setMovable(false);

}


状态栏(Status Bar)

状态栏也是勾选ui文件后默认生成的,设置状态栏的时候要注意内存泄漏。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //添加状态栏对象
    QStatusBar * sb = this->statusBar();
    this->setStatusBar(sb);

    //直接让状态栏展示文本,可以timeout,到期自动不在显示文本,如果timeout为0表示一直展示
    //sb->showMessage("这是一个状态消息",1000);

    //给状态栏添加标签控件,可以在添加的时候设置拉升系数
    QLabel* label1 = new QLabel("哈哈哈");
    sb->addWidget(label1,1);
    QLabel* label2 = new QLabel("嘿嘿嘿");
    sb->addWidget(label2,2);

    //给状态栏添加按钮控件,这次我们从右往左添加
    QPushButton* button = new QPushButton("按钮");
    sb->addPermanentWidget(button);//调用这个函数就表示从右往左添加

    //给状态栏添加进度条
    QProgressBar* p = new QProgressBar();
    p->setRange(0,100);
    p->setValue(50);
    sb->addWidget(p);
}

QDockWidget

QDockWidget是一个浮动窗口控件,相当于独立的新窗口。不过需要注意的是,QDockWidget默认只能添加一个控件,因此如果想要在浮动窗口上设置更多样式需要先创建一个QWidget并把控件设置其中,然后只要把QWidget对象设置到QDockWidget中去即可

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //添加一个浮动窗口对象
    QDockWidget* widget = new QDockWidget();
    this->addDockWidget(Qt::LeftDockWidgetArea,widget);//添加的时候要指定新窗口的初始停靠位置

    //给浮动窗口设置窗口标题
    widget->setWindowTitle("浮动窗口");

    //创建一个窗口对象
    QWidget* qwidget = new QWidget();
    //把QWidget对象设置进浮动窗口去
    widget->setWidget(qwidget);

    //然后我们就可以在Qwidget中添加更多控件了

    //创建一个布局管理器并添加到QWidget中去
    QVBoxLayout* layout = new QVBoxLayout();
    qwidget->setLayout(layout);

    //在布局管理器中添加控件
    layout->addWidget(new QLabel("这是一个标签"));
    layout->addWidget(new QPushButton("按钮"));

    //还可以给浮动窗口设置什么位置可以停靠
    widget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::TopDockWidgetArea);
}


Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐