• Qt 学习(4)


    Qt UI 文件机制

    使用 Qt 设计界面程序时,若界面是静态的,可以借助 Qt Designer 进行所见即所得的界面设计。设计好界面后,在界面类中对 ui 对象进行操作非常方便。

    QtCreator 自动生成的界面类

    构建运行一个有 Qt 界面文件的项目时,会在程序构建目录下面生成一些前缀为 ui_ 的文件,在界面类(以 window 为例)中引用的就是对应 ui_window 文件中的内容。window.h 和 window.cpp 中的内容示例:

    // window.h
    namespace Ui {
        class Window;
    }
    
    class Window : public QWidget {
        Q_OBJECT
    public:
        explicit Window(QWidget *parent = 0);
    
    private:
        Ui::Window *ui;
    }
    
    // window.cpp
    #include "window.h"
    #include "ui_window.cpp"
    
    Window::Window() : QWidget(parent), ui(new Ui::Window) 
    {
    
    }
    

    由 Qt 的 moc 系统自动生成的 ui_window 中的内容示例:

    QT_BEGIN_NAMESPACE
    
    class Ui_Window
    {
    public:
        QAction *action;
        ...
        
        void setupUi(QWidget *Window)
        {
            ...
    
            retranslateUi(Window);
            QMetaObject::connectSlotsByName(Window);
        }
    
        void retranslateUi(QWidget *Window)
        {
            ....
            action->setText(QApplication::translate("Window", "aciton", 0));
        }
    
    }
    
    namespace Ui {
        class Window: public Ui_Window {};
    } // namespace Ui
    
    QT_END_NAMESPACE
    

    ui_window 文件中包含有 Ui_Window 类,还有个 Ui 命名空间,命名空间中包含有一个和界面类同名的 Window 类,而这个类是 Ui_Window 的子类。

    Ui::Window 类的方法有: setupUi 和 retranslateUi,从字面上看能够知道一个是用于界面初始化的,一个是用来做多语言功能的。

    分离界面和业务逻辑

    Qt Designer 使得界面程序的开发变得简单,在 Designer 中拖动组件就可以快速完成界面的开发。但有些界面程序需要在界面上右键显示弹出菜单,如果能够像 Qt Designer 所作的那样,把右键菜单和具体的业务逻辑分开,那么界面类实现起来感觉就会更加流畅。(似乎没法直接用 Qt Designer 制作一个 QMenu 的 ui 文件)

    自己动手写界面代码,就按照 Qt Creator 中提供的模版进行编写就可以了。将要用到的界面全都放进 ui_curve.h 中,然后在 curve.cpp 中引用 Ui::Curve。

    #ifndef UI_CURVE_H
    #define UI_CURVE_H
    
    #include <QVariant>
    #include <QApplication>
    #include <QWidget>
    #include <QGridLayout>
    #include <QMenu>
    #include <QAction>
    // 界面类
    
    class Ui_Curve{
    public:
        QGridLayout *mainLayout;
        QMenu *mainMenu;
        QMenu *subCurveMenu;
        QAction *autoXAxisRange;
        QAction *autoYAxisRange;
        QAction *saveDataAction;
        QAction *xCurveAction;
        QAction *yCurveAction;
        QAction *zCurveAction;
        QAction *subPlotAction;
        QAction *resetAction;
        QAction *rescaleAction;
        QAction *setXRangeAction;
        QAction *setYRangeAction;
        QAction *unionSubYAxis;
        QAction *wheelOnYOnly;
    
        void setupUi(QWidget *curve) {
            if( curve->objectName().isEmpty() )
                curve->setObjectName("Curve");
    
            mainLayout = new QGridLayout();
            curve->setLayout( mainLayout );
    
            mainMenu = new QMenu( curve );
    
            // setup Sub Curve on One plot => menu
            subCurveMenu = new QMenu( curve );
            xCurveAction = new QAction( curve );
            xCurveAction->setData( "X" ); // used for identify
            xCurveAction->setCheckable( true );
            xCurveAction->setChecked( true );
            subCurveMenu->addAction( xCurveAction );
    
            yCurveAction = new QAction( curve );
            yCurveAction->setData( "Y" );
            yCurveAction->setCheckable( true );
            yCurveAction->setChecked( true );
            subCurveMenu->addAction( yCurveAction );
    
            zCurveAction = new QAction( curve );
            zCurveAction->setData( "Z" );
            zCurveAction->setCheckable( true );
            zCurveAction->setChecked( true );
            subCurveMenu->addAction( zCurveAction );
    
            mainMenu->addMenu( subCurveMenu );
            mainMenu->setProperty( "SubCurveCount", 3 );
    
            // display sub curve in independent widgets => action
            subPlotAction = new QAction( curve );
            subPlotAction->setCheckable( true );
            subPlotAction->setChecked(true);
            mainMenu->addAction( subPlotAction );
            mainMenu->addSeparator();
    
            resetAction = new QAction( curve );
            mainMenu->addAction( resetAction );
            mainMenu->addSeparator();
    
            // rescale Y AXis => action
            rescaleAction = new QAction( curve );
            mainMenu->addAction( rescaleAction );
    
            //
            autoXAxisRange = new QAction( curve );
            autoXAxisRange->setCheckable( true );
            autoXAxisRange->setChecked( true );
            mainMenu->addAction( autoXAxisRange );
    
            autoYAxisRange = new QAction( curve );
            autoYAxisRange->setCheckable( true );
            autoYAxisRange->setChecked( true );
            mainMenu->addAction( autoYAxisRange );
            mainMenu->addSeparator();
    
            setXRangeAction = new QAction( curve );
            mainMenu->addAction( setXRangeAction );
            setYRangeAction = new QAction( curve );
            mainMenu->addAction( setYRangeAction );
    
            unionSubYAxis = new QAction( curve );
            unionSubYAxis->setCheckable( true );
            unionSubYAxis->setChecked( true );
    
            mainMenu->addAction( unionSubYAxis );
    
            wheelOnYOnly = new QAction( curve );
            wheelOnYOnly->setCheckable( true );
            wheelOnYOnly->setChecked( true );
            mainMenu->addAction( wheelOnYOnly );
    
            mainMenu->addSeparator();
    
            saveDataAction = new QAction( curve );
            saveDataAction->setCheckable( true );
            saveDataAction->setChecked( false );
            mainMenu->addAction( saveDataAction );
    
            retranslateUi( curve );
            QMetaObject::connectSlotsByName(curve);
        }
    
        void retranslateUi(QWidget *curve) {
            subCurveMenu->setTitle(QApplication::translate("Curve", "Show Sub Curve On Main Widget", 0));
            xCurveAction->setText(QApplication::translate("Curve", "Display X (red) Line", 0));
            yCurveAction->setText(QApplication::translate("Curve", "Display Y (green) Line", 0));
            zCurveAction->setText(QApplication::translate("Curve", "Display Z (blue) Line", 0));
            subPlotAction->setText(QApplication::translate("Curve", "Display Sub Curves In Other Widgets", 0));
            resetAction->setText(QApplication::translate("Curve", "Reset Timer and clear ALL points", 0));
            rescaleAction->setText(QApplication::translate("Curve", "Rescale Y Axis", 0));
            autoXAxisRange->setText(QApplication::translate("Curve", "Auto Set X Axis Range", 0));
            autoYAxisRange->setText(QApplication::translate("Curve", "Auto Set Y Axis Range", 0));
            setXRangeAction->setText(QApplication::translate("Curve", "Set X Axis Range", 0));
            setYRangeAction->setText(QApplication::translate("Curve", "Set Y Axis Range", 0));
            unionSubYAxis->setText(QApplication::translate("Curve", "union All three sub y axis (x-y-z)", 0));
            wheelOnYOnly->setText(QApplication::translate("Curve", "Wheel Grag or Zomm On Y axis only", 0));
            saveDataAction->setText(QApplication::translate("Curve", "Save All Data On Close", 0));
        }
    };
    
    namespace Ui {
        class Curve : public Ui_Curve {};
    }
    
    #endif // UI_CURVE_H
    

    然后在界面类中重写 mousePressEvent 事件,检测到鼠标右击后调用 ui->mainMenu->popup( event->globalPos() ); 弹出菜单。

    上述文件中有两个方法值得注意:

    • QMetaObject::connectSlotsByName 这是用来自动连接信号和槽(槽的名称模式为:void on_<object name>_<signal name>(<signal parameters>);)的,但是 Ui_Curve 中我没有给各个 QAction 对象写 objectName,所以这里对 connectSlotsByName 的调用没有效果。
    • QApplication::translate 是提供翻译功能的,和 Qt 中常用的 QObject::tr 功能相同,但显然 QObject::tr 用起来更方便。

    虽然编写界面代码没什么技术含量,但是更重要的事情是理解 Qt 的 UI 模型。这个模型能够将界面代码从逻辑代码中分离出来,分离后的 UI 和业务逻辑使得代码的可维护性提高,整体代码的可读性和可维护性都提高了很多。

  • 相关阅读:
    关于FPGA设计16位乘法器的两…
    const&nbsp;int&nbsp;*pi与int&amp;nbs…
    HTML5基础学习
    html5基础!!
    正确分析结构使用正确的HTML标签。CSS样式写一起。
    开发经验以及方法
    布局设计
    position定位
    浏览器的兼容性
    float浮动的世界
  • 原文地址:https://www.cnblogs.com/brifuture/p/9564077.html
Copyright © 2020-2023  润新知