Qt 学习之路 2(8):添加动作

本节,我们将在前面主窗口基础之上,添加菜单和工具栏等的动作。虽然 Qt Creator 已经帮我们实现了主窗口的框架代码,但是具体的功能,还是需要我们一行行添加。

Qt 使用QAction类作为动作。顾名思义,这个类就是代表了窗口的一个“动作”,这个动作可能显示在菜单,作为一个菜单项,当用户点击该菜单项,对用户的点击做出响应;也可能在工具栏,作为一个工具栏按钮,用户点击这个按钮就可以执行相应的操作。有一点值得注意:无论是出现在菜单栏还是工具栏,用户选择之后,所执行的动作应该都是一样的。因此,Qt 并没有专门的菜单项类,只是使用一个QAction类,抽象出公共的动作。当我们把QAction对象添加到菜单,就显示成一个菜单项,添加到工具栏,就显示成一个工具按钮。用户可以通过点击菜单项、点击工具栏按钮、点击快捷键来激活这个动作。

QAction包含了图标、菜单文字、快捷键、状态栏文字、浮动帮助等信息。当把一个QAction对象添加到程序中时,Qt 自己选择使用哪个属性来显示,无需我们关心。同时,Qt 能够保证把QAction对象添加到不同的菜单、工具栏时,显示内容是同步的。也就是说,如果我们在菜单中修改了QAction的图标,那么在工具栏上面这个QAction所对应的按钮的图标也会同步修改。

下面我们来看看如何在QMainWindow中使用QAction

// !!! Qt 5
// ========== mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    void open();

    QAction *openAction;
};

#endif // MAINWINDOW_H

// ========== mainwindow.cpp
#include <QAction>
#include <QMenuBar>
#include <QMessageBox>
#include <QStatusBar>
#include <QToolBar>

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    setWindowTitle(tr("Main Window"));

    openAction = new QAction(QIcon(":/images/doc-open"), tr("&Open..."), this);
    openAction->setShortcuts(QKeySequence::Open);
    openAction->setStatusTip(tr("Open an existing file"));
    connect(openAction, &QAction::triggered, this, &MainWindow::open);

    QMenu *file = menuBar()->addMenu(tr("&File"));
    file->addAction(openAction);

    QToolBar *toolBar = addToolBar(tr("&File"));
    toolBar->addAction(openAction);

    statusBar() ;
}

MainWindow::~MainWindow()
{
}

void MainWindow::open()
{
    QMessageBox::information(this, tr("Information"), tr("Open"));
}

上面的代码分别属于两个文件:mainwindow.h 和 mainwindow.cpp。为了让 MainWindow 运行起来,我们还需要修改 main() 函数如下:

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    MainWindow win;
    win.show();

    return app.exec();
}

当我们编辑好文件,点击运行,可以看到MainWindow的运行结果:

Main Window with Action

这是一个相对完整的程序。首先,我们在MainWindow类中添加了一个私有函数open()和一个私有变量openAction。在 MainWindow 的构造函数中,第一行我们调用了setWindowTitle(),设置主窗口的标题。注意我们的文本使用tr()函数,这是一个用于 Qt 国际化的函数。在后续章节中我们可以看到,我们可以使用 Qt 提供的国际化工具,将tr()函数的字符串提取出来,进行国际化。由于所需进行国际化的文本应该被大多数人认识,所以,tr()函数里面一般会是英文文本。

然后,我们在堆上创建了openAction对象。在QAction构造函数,我们传入了一个图标、一个文本和 this 指针。我们将在后面的文章中解释 this 指针的含义。

图标我们使用了QIcon,传入值是一个字符串,这个字符串对应于 Qt 资源文件中的一段路径。Qt 资源文件的后缀名是 qrc。如果我们使用 Qt Creator,我们可以在新建文件中看到 Qt 资源文件。Qt 资源文件其实是一个 XML 描述的文件,表示 Qt 应用程序所需要的各个资源。我们可以使用普通文本编辑器打开这个文件:

<RCC>
    <qresource prefix="/images">
        <file alias="doc-open">document-open.png</file>
    </qresource>
</RCC>

我们会在后面的章节中详细介绍 Qt 资源文件(注意,资源文件需要在 pro 文件中使用 RESOURCES 引入。)。这里只需要了解,QIcon的参数,以 : 开始,意味着从资源文件中查找资源。:/images/doc-open就是找到了这里的 document-open.png 这个文件。(我们使用的是 png 格式的图片,这是 Qt 内置支持的图片格式。其他格式的图片,比如 jpg、gif 则需要插件支持。这些插件实际已经随着 Qt 一同发布。)

QAction第二个参数中,文本值前面有一个 &,意味着这将成为一个快捷键。注意看截图中 File 的 F 有一个下划线。

下面一句,我们使用了setShortcut()函数,用于说明这个QAction的快捷键。Qt 的QKeySequence为我们定义了很多内置的快捷键,比如我们使用的 Open。你可以通过查阅 API 文档获得所有的快捷键列表。 这个与我们自己定义的有什么区别呢?简单来说,我们完全可以自己定义一个tr("Ctrl+O")来实现快捷键。原因在于,这是 Qt 跨平台性的体现。比如 PC 键盘和 Mac 键盘是不一样的,一些键在 PC 键盘上有,而 Mac 键盘上可能并不存在,或者反之。使用QKeySequence类来添加快捷键,会根据平台的不同来定义相应的快捷键。

setStatusTip()则实现了当用户鼠标滑过这个 action 时,会在主窗口下方的状态栏显示相应的提示。

后面的connect()函数,将这个QActiontriggered()信号与MainWindow类的open()函数连接起来。当用户点击了这个QAction时,会自动触发MainWindowopen()函数。这是我们之前已经了解过的。

下面的menuBar()toolBar()statusBar()三个是QMainWindow的函数,用于创建并返回菜单栏、工具栏和状态栏。我们可以从代码清楚地看出,我们向菜单栏添加了一个 File 菜单,并且把这个QAction对象添加到这个菜单;同时新增加了一个 File 工具栏,也把QAction对象添加到了这个工具栏。我们可以看到,在菜单中,这个对象被显示成一个菜单项,在工具栏变成了一个按钮。至于状态栏,则是出现在窗口最下方,用于显示动作对象的提示信息的。

至于open()函数中的内容,我们会在后文介绍。这里可以运行一下,你会看到,触发这个动作,程序会弹出一个提示框。

下面是 Qt 4 版本的程序,具体非常类似,这里不再赘述。

// !!! Qt 4
// ========== mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void open();

private:
    QAction *openAction;
};

#endif // MAINWINDOW_H

// ========== mainwindow.cpp
#include <QAction>
#include <QMenuBar>
#include <QMessageBox>
#include <QToolBar>

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    setWindowTitle(tr("Main Window"));

    openAction = new QAction(QIcon(":/images/doc-open"), tr("&Open..."), this);
    openAction->setShortcuts(QKeySequence::Open);
    openAction->setStatusTip(tr("Open an existing file"));
    connect(openAction, SIGNAL(triggered()), this, SLOT(open()));

    QMenu *file = menuBar()->addMenu(tr("&File"));
    file->addAction(openAction);

    QToolBar *toolBar = addToolBar(tr("&File"));
    toolBar->addAction(openAction);

    statusBar();
}

MainWindow::~MainWindow()
{
}

void MainWindow::open()
{
    QMessageBox::information(this, tr("Information"), tr("Open"));
}

178 Comments

  1. Anonymous 2012年8月31日
    • DevBean 2012年8月31日
      • Anonymous 2012年8月31日
      • Junoja 2014年11月20日
      • zwb 2016年3月8日
        • 豆子 2016年3月8日
    • Forward 2014年11月14日
    • TingQT 2019年6月17日
  2. 羊八井 2012年10月7日
    • DevBean 2012年10月8日
  3. esdf 2012年11月13日
    • esdf 2012年11月13日
      • DevBean 2012年11月13日
  4. KOFLazycat 2012年11月14日
    • DevBean 2012年11月14日
      • Rui-huai Zhang 2013年4月22日
        • 豆子 2013年4月23日
          • Rui-huai Zhang 2013年4月23日
          • 梓涵 2013年6月11日
          • tomisacat 2013年8月12日
          • towardsocean 2015年6月13日
          • Zaccur 2016年1月20日
      • HaborHuang 2014年1月2日
  5. smile 2013年1月9日
    • 豆子 2013年1月9日
      • sornor 2014年6月11日
        • 豆子 2014年6月12日
    • 瞬间 2016年8月26日
  6. hwb 2013年1月15日
    • hwb 2013年1月15日
      • hwb 2013年1月15日
      • 豆子 2013年1月16日
  7. JiaPan 2013年1月28日
    • 豆子 2013年1月28日
      • JiaPan 2013年1月28日
        • 豆子 2013年1月28日
          • JiaPan 2013年1月28日
    • tttttbbb 2013年6月10日
  8. 轨迹 2013年5月28日
    • 豆子 2013年5月30日
  9. 芽子 2013年7月5日
    • 豆子 2013年7月7日
  10. ghl 2013年7月16日
    • 豆子 2013年7月17日
  11. kimihunhun 2013年7月24日
    • 豆子 2013年7月24日
    • Rice 2013年9月18日
      • 豆子 2013年9月18日
  12. kimihunhun 2013年7月24日
  13. enockipp 2013年8月12日
    • 豆子 2013年8月13日
      • enockipp 2013年8月13日
        • 豆子 2013年8月13日
  14. 漂木 2013年8月17日
    • 豆子 2013年8月17日
  15. tux 2013年8月26日
    • 豆子 2013年8月26日
      • tux 2013年8月26日
  16. xyt 2013年9月17日
    • 豆子 2013年9月18日
  17. devnull 2013年9月22日
    • 豆子 2013年9月22日
  18. qcp 2013年9月27日
    • 豆子 2013年9月28日
  19. 乔玉东 2013年11月5日
    • 乔玉东 2013年11月5日
  20. 咚冬 2013年11月14日
    • 豆子 2013年11月15日
  21. 陈胖子要逆袭 2013年12月20日
  22. 陈胖子要逆袭 2013年12月20日
    • 陈胖子要逆袭 2013年12月20日
  23. LSH 2014年1月2日
    • 豆子 2014年1月3日
      • LSH 2014年1月3日
  24. gazzi 2014年2月17日
    • 豆子 2014年2月17日
      • gazzi 2014年2月18日
  25. Jimmy 2014年2月19日
    • 豆子 2014年2月19日
  26. Johnny 2014年4月3日
    • Johnny 2014年4月4日
      • 豆子 2014年4月4日
        • Johnny 2014年4月5日
  27. Kab 2014年5月21日
    • 豆子 2014年5月23日
  28. xuan120520 2014年5月27日
    • 豆子 2014年5月30日
  29. xuan120520 2014年5月27日
    • 豆子 2014年5月30日
      • xuan120520 2014年5月30日
  30. gzy0011 2014年6月12日
    • 豆子 2014年6月13日
  31. source 2014年7月31日
    • 豆子 2014年7月31日
  32. vx 2014年8月10日
    • 豆子 2014年8月10日
      • vx 2014年8月10日
        • vx 2014年8月10日
        • 豆子 2014年8月11日
          • vx 2014年8月11日
          • Chia 2015年2月4日
  33. 唯儿 2015年6月8日
    • 豆子 2015年6月11日
  34. chenjings 2015年7月19日
  35. Taget L 2015年7月21日
    • 豆子 2015年7月21日
  36. 无名 2015年8月16日
    • 豆子 2015年8月17日
  37. poofee 2015年11月2日
    • 豆子 2015年11月4日
  38. poofee 2015年11月2日
    • 豆子 2015年11月4日
  39. Yann 2015年11月5日
    • 豆子 2015年11月5日
  40. LouiseGAN 2015年11月10日
    • 豆子 2015年11月13日
      • jiangcheng 2016年3月29日
  41. Tank93 2015年11月17日
    • 豆子 2015年11月17日
  42. Rainfd 2015年11月23日
    • 豆子 2015年11月23日
  43. small 2015年12月12日
    • 豆子 2015年12月14日
  44. usopp 2015年12月25日
    • usopp 2015年12月25日
  45. fusuyang 2015年12月25日
    • 豆子 2015年12月29日
  46. guoyinbo2012 2016年3月18日
    • guoyinbo2012 2016年3月18日
  47. Kempinski 2016年4月21日
  48. sheldon zuo 2016年5月29日
    • 豆子 2016年6月3日
  49. 卖鱼的小白菜 2016年7月3日
    • 卖鱼的小白菜 2016年7月3日
  50. ben 2016年7月23日
  51. ben 2016年7月23日
  52. ben 2016年7月23日
  53. ben 2016年7月23日
  54. ben 2016年7月24日
    • 豆子 2016年7月24日
      • ben 2016年7月25日
        • 豆子 2016年7月25日
    • Fantasy 2017年2月10日
  55. t850508594 2016年8月8日
    • 豆子 2016年8月12日
  56. augest rush 2016年11月22日
    • 豆子 2016年11月26日
  57. ljl 2016年12月26日
    • ljl 2016年12月26日
  58. Fantasy 2017年2月10日
    • 豆子 2017年2月11日
      • Fantasy 2017年2月11日
  59. QT learning 2017年3月14日
    • 豆子 2017年3月16日
      • Qt之路 2017年7月6日
        • Qt之路 2017年7月6日
  60. chou 2018年3月21日
    • chou 2018年3月21日
    • chou 2018年3月21日
      • 豆子 2018年3月25日
  61. 陈宇 2018年3月22日
    • 豆子 2018年3月25日
  62. 2019年3月5日
    • 2019年3月5日
  63. Rong_ggq 2019年5月6日
    • 豆子 2019年5月8日
  64. Kitty 2019年5月24日
    • Kitty 2019年5月24日
  65. Kitty 2019年5月24日
  66. Li 2019年5月24日
  67. mercuriex 2019年6月13日
  68. cxtan 2019年6月24日
    • 豆子 2019年6月25日

Leave a Reply